Clip
각 애니메이션을 저장하는 클립이다.
Converter.cpp
asClip * Converter::ReadClipData(aiAnimation * animation)
{
asClip* clip = new asClip();
clip->Name = animation->mName.C_Str();
clip->FrameRate = (float)animation->mTicksPerSecond;
clip->FrameCount = (UINT)animation->mDuration + 1;
vector<asClipNode> aniNodeInfos;
for (UINT i = 0; i < animation->mNumChannels; i++)
{
aiNodeAnim* aniNode = animation->mChannels[i];
asClipNode aniNodeInfo;
aniNodeInfo.Name = aniNode->mNodeName;
UINT keyCount = max(aniNode->mNumPositionKeys, aniNode->mNumScalingKeys);
keyCount = max(keyCount, aniNode->mNumRotationKeys);
asKeyframeData frameData;
for (UINT k = 0; k < keyCount; k++)
{
asKeyframeData frameData;
bool bFound = false;
UINT t = aniNodeInfo.Keyframe.size();
if (fabsf((float)aniNode->mPositionKeys[k].mTime - (float)t) <= D3DX_16F_EPSILON)
{
aiVectorKey key = aniNode->mPositionKeys[k];
frameData.Time = (float)key.mTime;
memcpy_s(&frameData.Translation, sizeof(Vector3), &key.mValue, sizeof(aiVector3D));
bFound = true;
}
if (fabsf((float)aniNode->mRotationKeys[k].mTime - (float)t) <= D3DX_16F_EPSILON)
{
aiQuatKey key = aniNode->mRotationKeys[k];
frameData.Time = (float)key.mTime;
frameData.Rotation.x = key.mValue.x;
frameData.Rotation.y = key.mValue.y;
frameData.Rotation.z = key.mValue.z;
frameData.Rotation.w = key.mValue.w;
bFound = true;
}
if (fabsf((float)aniNode->mScalingKeys[k].mTime - (float)t) <= D3DX_16F_EPSILON)
{
aiVectorKey key = aniNode->mScalingKeys[k];
frameData.Time = (float)key.mTime;
memcpy_s(&frameData.Scale, sizeof(Vector3), &key.mValue, sizeof(aiVector3D));
bFound = true;
}
if (bFound == true)
{
aniNodeInfo.Keyframe.push_back(frameData);
}
}
if (aniNodeInfo.Keyframe.size() < clip->FrameCount)
{
UINT count = clip->FrameCount - aniNodeInfo.Keyframe.size();
asKeyframeData keyFrame = aniNodeInfo.Keyframe.back();
for (UINT n = 0; n < count; n++)
{
aniNodeInfo.Keyframe.push_back(keyFrame);
}
}
clip->Duration = max(clip->Duration, aniNodeInfo.Keyframe.back().Time);
aniNodeInfos.push_back(aniNodeInfo);
}
ReadKeyframeData(clip, scene->mRootNode, aniNodeInfos);
return clip;
}
애니메이션 클립일 읽어오는 함수이다.
일단 Assimp에서 읽어온 animation을 갖고와서 FrameRate, FrameCount, Name을 받아온다. 그런 뒤 각 노드들의 정보를 담아온다.
각 노드의 정보는 일단 각 키값을 카운트(Transform, Scale, Rotation)중에 가장 큰 값을 갖고오고 프레임 데이터를 만들어준다.
프레임 레이트는 각 노드의 프레임 갯수와 현재 Position, Rotation, Scale의 시간 값을 뺀 것을 float의 오차값보다 적으면 넣어준다.
그런데 지금까지 Scale, Rotation, Translate 순으로 넣었는대 왜 반대일까?? 이유는 Assimp는 OpenGL기준으로 만들었기 때문에 오른손 좌표계를 사용하기 때문이다.
그리고 만든 노드의 키프레임마다 넣어준다. 그리고 노드를 넣어준다.
void Converter::ReadKeyframeData(asClip * clip, aiNode * node, vector<struct asClipNode>& aiNodeInfos)
{
asKeyframe* keyframe = new asKeyframe();
keyframe->BoneName = node->mName.C_Str();
for (UINT i = 0; i < clip->FrameCount; i++)
{
asClipNode* asClipNode = NULL;
for (UINT n = 0; n < aiNodeInfos.size(); n++)
{
if (aiNodeInfos[n].Name == node->mName)
{
asClipNode = &aiNodeInfos[n];
break;
}
}// for(n)
asKeyframeData frameData;
if (asClipNode == NULL)
{
Matrix transform(node->mTransformation[0]);
D3DXMatrixTranspose(&transform, &transform);
frameData.Time = (float)i;
D3DXMatrixDecompose(&frameData.Scale, &frameData.Rotation, &frameData.Translation, &transform);
}
else
{
frameData = asClipNode->Keyframe[i];
}
keyframe->Transforms.push_back(frameData);
}
clip->Keyframes.push_back(keyframe);
for (UINT i = 0; i < node->mNumChildren; i++)
{
ReadKeyframeData(clip, node->mChildren[i], aiNodeInfos);
}
}
``
간단하다 각 키프레임의 데이터를 갖고온다.
void Converter::WriteClipData(asClip * clip, wstring savePath) { Path::CreateFolders(Path::GetDirectoryName(savePath));
BinaryWriter* w = new BinaryWriter();
w->Open(savePath);
w->String(clip->Name);
w->Float(clip->Duration);
w->Float(clip->FrameRate);
w->UInt(clip->FrameCount);
w->UInt(clip->Keyframes.size());
for (asKeyframe* keyframe : clip->Keyframes)
{
w->String(keyframe->BoneName);
w->UInt(keyframe->Transforms.size());
w->Byte(&keyframe->Transforms[0], sizeof(asKeyframeData) * keyframe->Transforms.size());
SafeDelete(keyframe);
}
w->Close();
SafeDelete(w); } ``` 만든 키프레임을 파일로 만든다(최적화)