엔진프로그래밍

max sdk에서 offsetMatrix를 어떻게 보내야할까

doyyy_0 2025. 10. 24. 10:29

assimp의 offsetMatrix의 주석을 살펴보면,

Matrix that transforms from mesh space to bone space in bind pose..

뭐 이렇다고한다. 이게 정확히 무슨 의미이고 왜 필요할까?

 

애니메이션의 bone을 gpu에보낼때 마지막에

m_FinalBoneMatrices[index] = offset * globalTransformation 이렇게 처리한다.

globalTransformation은 현재 nodeTransform * parentTransform이다.

 

여기서 nodeTransform은 localSpace이고, parentTransform은 worldTransform(=globalTransform)이다. parentTransform은 localTransform들의 계산 합의 결과이다. 따라서 globalTransformation = nodeTransform  * parentTransform 즉, globalTransform또한 worldSpace이다.

 

그럼 우리가 계산하고자 하는 vertex를 한번 살펴보자. 예를들어, 현재 node가 팔이고 그 팔의 globalTransformation의 Translation부분은 대충(0.7,0.7,0.7)이라고 하자. 그 팔 주위에 붙어있는 vertex는 뭐 (0.75, 0.75, 0.75) 이 정도 될 것이다. 그럼, 

만약 offset없이 m_FinalBoneMatrices[index]   = globalTransformation 이렇게 하면 어떻게 될까? vertex에 globalTranslation을 곱해서 좌표가 (1.4,1.4,1.4)이렇게 훅 점프해버릴것이다. offsetMatrix는 그걸 방지하기 위해 vertex를 worldSpace가 아닌, boneSpace(localSpace)로 변환해주는 것이다. 그럼 offsetMatrix는 뭐가 돼야할까? 바로, 현재 node의 worldMatrix의 역행렬이 돼야한다. 그렇다고 globalTransformation의 역행렬이 아니고, T-pose일 때 현재 노드의 역행렬을 넣어주면 된다. 예를들어 그러면 팔 노드의 역행렬은 (-0.7,-0.7,-0.7)이 되겠고, vertex * 팔노드의 역행렬을 계산하면 (0.05, 0.05, 0.05)이렇게 나와서 결국 팔 노드로부터 vertex까지의 떨어진 거리. 즉, bone space(localSpace)로의 위치가 되는것이다.

 

max sdk에서 보낼때

//LocalTM이란 (자신의 월드행렬) * (부모월드행렬의 역행렬)
Matrix3 LocalTM, WorldTM;
LocalTM = node->GetNodeTM(GetStaticFrame()) * Inverse(node->GetParentTM(GetStaticFrame()));
WorldTM = node->GetNodeTM(GetStaticFrame()); //이거의 역행렬이 offsetMatrix가 될것

이렇게 보내면 된다.

 

로컬과 월드가 좀 이해가 어려울 수 있는데, 유니티에서 모델 3개 띄워놓고 자식오브젝트로 붙여가면서 이해하면 LocalTM이 왜 저렇게 나오는지, 그리고 나머지 부분도 이해가 다시 될 것이다.