헤더파일

스킨 애니메이션-뼈대, 포즈 본문

게임엔진아키텍처

스킨 애니메이션-뼈대, 포즈

헤더파일 2018. 1. 28. 14:59

스킨에니메이션은 게임과 영화 산업에서 가장 널리 쓰이는 기법이다.

스킨애니메이션을 하려면 단단한 뼈들로 뼈대를 만들어야 한다.

관련 이미지

뺘대는 화면에 그려지지않고 대신 스킨이라 불리는 이어진 삼각형들로 이뤄진 메시가 뼈대의 관절에 붙고 스킨의 각 정점들은 관절의 움직임을 따라간다.  각 정점들은 여러 관절에 가중치를 갖고 붙을 수 있는데, 이렇게 하면 관절이 움직일 때 스킨이 자연스러운 모양으로 늘어질 수 있다.




1. 뼈대

뼈대는 관절이라 불리는 단단한 조각들이 계층적으로 모여 이뤄진 것이다. 애니메이터가 실제로 움직이는 것은 이 관절이다. 관절들은 계층구조나 트리구조로 이루어지기 때문에 루트관절이 있고 나머지 관절들이 자식이되는 식으로 붙는니다.


사람

척추

오른쪽 어깨

오른쪽 팔 꿈치

왼쪽 어깨

왼쪽 팔 꿈치

보통 관절들은 0 부터 N-1까지 번호를 붙여 구별한다. 각 관절은 부모관절이 하나밖에 없기 때문에 관절마다 부모 관절의 번호를 저장하고 있으면 뼈대의 계층 구조를 다 저장할 수 있다. 맨 위의 루트관절은 부모 관절이 없기 때문에 -1을 갖는다.



 뼈대를 자료구조로 나타낼 때는 각 관절 자료 구조들을 배열로 갖는 형태로 만드는 경우가 많다. 대개 자식 관절은 반드시 나중에 나오게 위치해서 0번 관절은 항상 루트 관절을 의미한다.

  • 관절의 이름

  • 부모 관절의 관절 인덱스

  • 바인드 포즈의 역변환 - 뒤에서 설명합니다.

struct Joint

{

Matrix4x3 m_invBindPose; //바인드 포즈의 역변환

const char* m_name // 관절의 이름

U8 m_iParent //부모 관절의 인덱스

}


struct Skeleton

{

U32 m_JointCount //전체 관절의 개수

Joint* m_aJoint //관절 배열

}




2.포즈

모든 애니메이션은 시간의 흐름에 따라 진행된다. 캐릭터가 움직이는 것 같은 착시 현상을 일으키기 위해서는 캐릭터의 정지된 포즈들을 따로따로 준비한 후 그 포즈들을 초당 30에서 60개 정도 연속적으로 빠르게 보여줘야 한다.

뼈대의 포즈를 잡는 것은 각 관절들을 회전 변환, 평행이동, 때로는 스케일해 다양한 모양을 잡는 것이다. 관절의 포즈는 4x4나 4x3 행렬 아니면 SQT 형식의 자료구조로 나타낸다. 전체 뼈대의 포즈는 이런 관절 포즈들을 모아놓은 것일 뿐이며 행렬이나 SQT 데이터 구조의 배열로 나타내는 경우가 많다.


2-1. 바인드 포즈

레퍼런스 포즈나 레스트 포즈 라고도 부른다. 3D메시가 뼈대에 연결되기 직전의 포즈로 뼈대를 메시와 연결한다는 Bind 라는 용어에서 유래했다.


2-2. 로컬 포즈

바인드 포즈가 아닌 부모 관절에 따라 움직인 포즈를 의미한다. 예를들어 어깨관절을 회전하면 어깨에 종속적인 팔꿈치, 손목, 손가락 등의 포즈를 건드리지 않아도 팔 전체가 강체처럼 따라 움직이기게 된다. 로컬 포즈는 거의 대부분 SQT 형식으로 저장되는데 애니메이션 블렌딩에 유용하기 때문이다.


2-3.관절의 스케일

SQT에서 관절의 스케일을 하는 것을 생략하거나 균등한 스케일로만 제한하면 성능상의 이점이 있는데 저장공간을 줄이고 관절단위로 충돌 채크할 때 경계 구가 타원형이 되는 것도 예방한다.


2-4. 관절 포즈 자료구조

struct JointPose

{

Quaternion m_rot;

Vector3 m_trans;

F32 m_scale; //균등한 스케일

};



struct JointPose

{

Quaternion m_rot;

Vector3 m_trans;

Vector3 m_scale; //균등하지 않은 스케일

U8 padding[8];

};


전체 뼈대의 로컬 포즈는 다음처럼 구현할 수 있는데, 여기서 m_aLocalPose는 JointPose 구조체를 뼈대의 관절 개수만큼 담을 메모리를 동적으로 할당한다.


struct SkeletonPose

{

Skeleton* m_pSkeleton;

JointPose* m_aLocalPose; 

};


로컬관절포즈는 바로 위 부모 관절을 기준으로 상대적이라는 점을 명심해야 한다. 모든 아핀변환은 점과 벡터를 한 좌표공간에서 다른 좌표 공간으로 변환하는 것으로 볼 수 있다. 따라서 관절 j의 좌표공간으로 표현된 점 혹은 벡터에 관절 포즈 변환 Pj를 적용하면 결과는 부모공간으로 표현된 점이나 벡터가 된다. 때로는 점과 벡터를 반대 방향으로 변환할 필요가 있는데 즉, 부모 공간에서 자식 관절 공간으로 변환하는 것이다. 이 변환은 단순히 로컬 관절 포즈의 역에 불과하다.


관절의 포즈를 모델 공간이나 월드 공간으로 나타내면 편할 때가 있는데 이것을 글로벌 포즈라고 한다. 위에서 말한 것처럼 아핀변환 시 부모공간으로 변하므로 모델공간 포즈를 얻으려면 그 관절에서 시작해 뼈대의 계층을 루트까지 거슬러 올라가면서 각 관절의 로컬 포즈를 곱해나가면 된다.


글로벌 포즈를 아까 만든 뼈대 포즈 구조체에 포함하면


struct SkeletonPose

{

Skeleton* m_pSkeleton;

JointPose* m_aLocalPose; 

Matrix4x4* m_aGlobalPose;

};

 m_aGlobalPose는 동적으로 할당된 배열이며 그 크기는 전체 관절을 담을 만한 크기다.



'게임엔진아키텍처' 카테고리의 다른 글

스킨 애니메이션 - 클립  (0) 2018.01.28
Comments