애니메이션 코드 작업을 하고 있으면, 주로 본 인덱스를 보고 있게 됩니다. 여러 다른 본 인디스(indices)들이 있으면 애니메이션 코드에서 헛갈릴 수 있습니다. 이런 문제 때문에 어째서 본 인디스가 여러개이고 그것들 사이에서는 어떤 차이가 있는지를 설명해 드리고자 합니다.
애니메이션 코드에서 중요한 본 인디스는 3종류가 있습니다.
- 메시 본 인덱스(Mesh Bone Index)
- 스켈레톤 본 인덱스(Skeleton Bone Index)
- FCompactPoseBoneIndex
Mesh Bone Index는 스켈레탈 메시의 일부분입니다. 여기에는 모든 메시 조인트, 계층구조(Hierarchy)가 들어 있고 스켈레탈 메시를 랜더링 하는 데에 사용됩니다. 메시 본 인덱스를 보기 위해서는 스켈레탈 메시를 임포트 해야 하고 페르소나에서 열어야 합니다. 여기에서 여러분은 여기에 포함된 모든 조인트를 볼 수 있습니다.
스켈레탈 메시 컴포넌트 속의 SpateBases 나 LocalAtoms에 접근하려면 메시 본 인덱스를 사용해야 할 것입니다.
메시 본 인덱스가 스켈레탈 메시의 부분이라면 스켈레톤 본 인덱스는 도대체 뭘까요? 페르소나를 사용하여 본 적이 있으시다면 USkeleton 애셋에 관해서 알고 계실 것입니다. 이것들은 여러분이 스켈레탈메시를 임포트 하거나 이미 존재하는 것에 할당(Assign) 한 경우에 생성됩니다. 만약 스켈레톤이 왜 여러가지의 메시와 조인트들을 갖게 되는지 확실히 이해가 되지 않으시는 경우에는 Wes Bunn의 영상을 시청하시기 바랍니다. 여기에서 더 자세하게 설명해 드립니다.
언리얼 엔진 4에서, USkeleton 애셋은 스켈레톤이 가지고 있는 모든 본마다 레퍼런스 포즈를 포함하고 있습니다. (USkeleton.ReferenceSkeleton) 스켈레톤 본 인덱스는 이 본 리스트의 인덱스를 말합니다. UAnimSequence 각각에는 내부 트랙 인디스(internal track indices)와 맞는 스켈레톤 본 인덱스 사이의 매핑이 저장되어 있습니다. 에픽은 이 것을 해당 본에 적합한 애니메이션을 적용할 지를 확인하는 과정에서 사용하지만 여기에 따라 스켈레톤이 바뀌면 애니메이션의 데이터를 업데이트 해야 합니다. 이 것은 애니메이션이 ‘지저분한(dirty)’상태로 마킹되는 이유이며 스켈레톤이 변경되었을 때 다시 저장되어야 합니다.
USkeleton의 원래 계획은 애니메이션 데이터만을 추출하고 적당한 스켈레탈 메시 컴포넌트에 리타게팅이 될 수 있는지를 확인하는 데 사용하는 것이었습니다. 아주 멋진 아이디어처럼 들리지만, 제대로 작동하지 않았는데 왜냐하면 SkeletalControls를 가지고 작업할 때에는 정확한 메시 데이터가 필요했기 때문입니다. 예를 들어 IK를 사용할 때 여러분은 다양한 메시를 묶는데, 이는 스켈레톤의 본 트랜스폼이 더이상 사용되지 않음을 의미합니다.
스켈레톤의 참조 포즈 본 트랜스폼은 애니메이션 스케일 변경 리타게팅에서만 사용됩니다.
페르소나에서 스켈레톤 탭을 열면 아래와 같은 것들을 볼 수 있습니다.
기본 값으로, USKeleton속의 모든 본이 표시됩니다. “메시 본 보기(Show Mesh Bones)”로 변경하면 현재 프리뷰 메시에 속한 본들만을 보여 줍니다.
그럼 USkeleton 본 인덱스가 USkeletalMesh 본 인덱스와 일치하지 않는다는 것을 알 수 있습니다. 그렇다면 FCompactPoseBoneIndex는 어디에 속하게 될까요?
FCompactPoseBoneIndex는 FCompactPose에서만 사용될 수 있는 인덱스 입니다. FCompactPose는 확인 과정(evaluation) 동안에서만 사용될 수 있는 런타임 본입니다. 이 것은 현재의 메시 LOD에만 연관된 조인트들만을 포함한 연속적인 리스트 입니다. 다수의 LOD를 가지고 있는 경우 최적화를 위해 조인트의 부분집합만을 가질 수 있습니다. FCompactPose에 앞서 브랜치들이 사용되었지만 브랜치들은 퍼포먼스 이슈를 일으켰는데, 왜냐하면 브랜치의 예측이 잘못되었기 때문입니다. FCompactPoseBoneIndex는 브랜치 없이도 반복 작업을 가능하게 합니다.
FCompactPoseBoneIndex는 그냥 인티저입니다. 그 이유는 코드의 명확성을 위해서죠. 함수가 FCompactPoseBoneIndex를 받거나 반환하면 어떤 스페이스에 본 인덱스가 작동하는지 알 수 있습니다. 이것은 또한 여러분이 실수로 조밀한 인덱스와 메시나 스켈레톤 인덱스(또는 거꾸로)를 사용하도록 의도된 함수를 호출할 수 없다는 것을 의미합니다. 컴파일러가 에러를 발생시킬 것입니다.
핵심 애니메이션 코드들은 모두 FCompactPose를 사용합니다. 여러분은 이러한 세가지 본 인디스들을 API를 이용해 전환할 수 있습니다. 스켈레탈 메시와 스켈레톤을 컨버전하는 대부분의 API는 USkeleton에서 찾을 수 있습니다. (FSkeletonToMeshLinkup)
요약:
- 메시 본 인덱스(Mesh Bone Index) - 스켈레탈 메시 본 인덱스는 스켈레탈 메시 컴포넌트의 SpaceBases 또는 LocalAtoms에 사용됩니다.
- 스켈레톤 본 인덱스(Skeleton Bone Index) - 스켈레톤 본 인덱스에는 모든 스켈레탈 메시의 조인트 연결이 들어 있습니다. 특히 이 것은 애니메이션 트랙 인덱스 입니다. 애니메이션은 트랙 데이터를 위해 이 인덱스를 참조합니다.
- FCompactPoseBoneIndex - 이 것은 메시의 LOD의 일부로 모든 조인트의 부분집합을 갖고 있습니다. 예를 들어 LOD 0 은 메시인덱스(MeshIndex)와 일치할 것입니다. 하지만, LOD 1 또는 LOD 2 로 넘어가면 부분집합만 가질 수 있습니다. 그러므로 더 이상 메시 인덱스와 일치하지 않습니다.
아래는 메시 본으로부터 CompactPoseBoneIndex으로 컨버팅 하는 예제입니다.
// 코든 컴팩트 포즈 구간에서 반복
for (FCompactPoseBoneIndex BoneIndex : Output.Pose.ForEachBoneIndex())
{
// 메시 포즈로부터 컴팩트 포즈를 요청
FMeshPoseBoneIndex MeshPoseBoneIndex = Output.Pose.GetBoneContainer().MakeMeshPoseIndex(BoneIndex);
// 로컬 메시 버퍼를 스켈레탈 메시의 버퍼로 간주
Output.Pose[BoneIndex] = LocalMeshBuffer[MeshPoseBoneIndex.GetInt()];
}
마지막으로, USkeleton은 정확한 이름이 붙은 것이 아닙니다. 이 동영상을 보시면 USkeleton에 대해 더 자세히 이해하실 수 있을 것입니다.
이 포스팅이 본 인디스의 종류간 차이의 이해 및 어떻게 사용할 수 있는지에 대해 도움이 되었길 바랍니다.