스키닝(skinning)-2(매트릭스 팔레드 개념)

이 문서의 저작권은 김용준(newtype@chollian.net)에게 있습니다.

무단 전재, 복사,인용,수정을 금지합니다.

개인적인 학습의 용도는 상관없으나, 상업적 이용은 금지합니다

소스는 C:\mssdk\samples\Multimedia\Direct3D\Tutorials\Tut03_Matrices     


DirectX 8.1SDK를 깔면 여기 경로에 있다.

3부 고급편 - Matrix Palette

Matrix Palette혹은 Indexed Matrix라고도 하는 방식을 알아보자.

Direct3D 8.0에서 새롭게 도입된 방식으로 7.0에 있던 WORLD(0) ~ WORLD(3)에 오브젝트마다 매번 행렬을 대입하면서 사용했던 불편한 Vertex Blending을 발전시킨 것이라 하겠다.

기본적인 개념은 각각의 버텍스에 최대 4개까지 Blend Weight라는 가중치를 가질 수 있는데, 이들의 가중치에 따라서 다른 행렬을 곱해주게 된다. 이때, 곱해주는 행렬을 최대 256개까지 매트릭스 팔레트라는 영역에 셋팅해 놓으면 나머지는 GPU가 일아서 DrawPrimitive()함수 호출시에 처리해 주는 것이다.

당연히 캐릭터를 위해서 탄생했다고 해도 과언이 아니다. 다른 용도로 사용할 수도 있으나, 최대 256개까지 지원하는 매트릭스 팔레트에 bone의 애니메이션 키를 등록하고 각각의 bone이 영향을 미치는 버텍스에 weight와 index만 적절하게 셋팅되어 있으면 모든 것이 DrawPrimitive()호출 한방(!)으로 끝난다는 얘기가 된다.

연산 수식은 다음과 같다.


단 이며,은 버텍스의 로컬 좌표,은 매트릭스 팔레트에 등록되어 있는 번째 행렬이다.

 정리해서 말하면 하나의 버텍스가 여러 개의 행렬로부터 영향을 받아서 월드 좌표계로 변형된다는 것이다.


사용자 정의 버텍스가 다음과 같이 선언되어있다고 하자.

struct MYVERTEX
{
float      x, y, z;
float      w1, w2, w3;
DWORD      index;
DWORD      diffuse;
};
#define D3DFVF_MYVERTEX (D3DFVF_XYZB4 | D3DFVF_LASTBETA_UBYTE4 | D3DFVF_DIFFUSE)

<그림> 매트릭스 팔레트의 작동 원리(MatrixPalette.ppt)


 는 DWORD index의 가장 마지막 바이트 값이 매트릭스 팔레트의 인덱스번호가 된다.

 DWORD타입인 index는 4개의 바이트로 구성되어 있는데, 이를 최상위 바이트부터 순서대로 배열하면 이런

모양이 될것이다.

 부터 순서대로, 최하위 바이트인 가 가리키는 인덱스(그림에서는 2번째)와 결합하는 것이다.
는 는 의 인덱스가 가리키는 매트릭스와 곱해지게 된다.


뭔 소린지 잘 모르겠지만 하나의 버텍스가 여러 개의 매트릭스와 결합한다는 얘기같다.
좀더, 명확하게 이해하기 위해서, 우리는 뼈대(bone)에 대해서 알아야 하겠다.

Bone은 맥스 메뉴에서 Animation->Create Bone으로 간단하게 만들 수 있는 오브젝트 이다.

<그림> 2개의 bone이 생성된 모습(one-bone.jpg)

<그림> bone을 4개의 뷰포트에서 살펴본 모습(bone.jpg)


그림에서 보듯이 bone은 간단한 사각뿔의 형태를 하고 있으나, 모양은 얼마든지 수정 가능하다.

bone은 만들어진 캐릭터에 애니메이션을 적용하고자 할 때 주로 사용하게 되는데, 이는 bone에 애니메이션을 적용해 놓으면, 캐릭터가 바뀌어도 애니메이션 키는 전혀 손댈 필요 없이 캐릭터의 모델만 바꿔주면 되기 때문이다. 이외에도 여러가지 장점이 많은데, 지금부터 살펴볼 버텍스의 가중치가 대표적인 장점이라고 할 수 있겠다..

다음은 캐릭터를 위한 bone의 사용예이다.

 

bone

bone + mesh

bone + mesh + texture

<그림> 캐릭터에 bone을 적용한 모습(char-bone.jpg, char-bone-mesh.jpg, char-bone-mesh-tex.jpg)


그럼, 이제 bone을 vertex와 결합시키는 방법에 대해서 알아보도록 하자.
가장 쉬운 방식은 단순히 mesh를 bone의 child로 붙여버리는(attach)것이다. 그러나 이 방식은 우리가 원하는 버텍스의 가중치 값이 사용되지 않는다.
버텍스의 가중치는 mesh선택후 modifier->skin->edit envelope에서 적용할 수 있다.

다음에 나오는 그림들을 잘 살펴보도록 하자.

tube형태의 메쉬에 bone을 적용할 것이다(bone-mesh.jpg)

아직 skin modifier를 적용하기 전이다.

skin modifier에서 edit envelope를 선택하면 이와 같이 바뀐다.

bone이 영향을 주는 영역(range)을 조절 할 수 있다..(bone-range.jpg)


bone의 가중치를 받는 버텍스가 색으로 표시되고 있다.(bone-mesh.jpg)

red > yellow > blue 순으로 가중치를 많이 받는 것이다.

modifier를 빠져나와 에디터 화면에서 bone을 y축 회전시킨 결과 mesh가 가중치값을 사용해서 굽은 것을 볼수 있다.즉, 스키닝이 된것이다.(bone-mesh-rotate-wireframe.jpg)

좀더 정확한 모습이다.(bone-mesh-rotate-shade.jpg)

앞에서 살펴본 바와같이 버텍스는 bone으로부터 가중치를 받아서 보관하고 있게된다. 재미있게도, 여기서 사용하는 bone의 가중치 방식은 우리가 앞서 살펴본 매트릭스 팔레트와 완벽하게 일치하는 방식이다. 실제로 맥스 스크립트를 통해 bone의 가중치 값을 뽑아본 결과 하나의 버텍스에 가해지는 가중치의 합은 정확하게 1.0이었다.(사실 당연한 얘기다.)

차이가 있는 것은 Direct3D에서의 가중치의 개수는 4개가 한계인데 비해서, 맥스는 제한이 없다는 것이다. 그러나, 필자가 많은 테스트를 해 본 결과, 특별한 경우가 아니라면 가중치는 4개이상 나오지 않으며, 나온다 하더라도 가중치들 중에서 큰 것 4개만 적용하고, 나머지는 무시하더라도 별다른 차이가 없었다.

이상과 같이 맥스의 bone가중치를 Direct3D의 매트릭스 팔레트에 이용하면 GPU를 최대로 이용하는 대단히 효율적인 애니메이션이 가능하며, 또한 근육 시뮬레이션이나 얼굴의 Facial Animation등을 단순한 키 프레임 몇 개 만으로도 구현할 수 있는 실로 편리한 방법이라 하겠다.

이 글을 공유하기

댓글

Designed by JB FACTORY