• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 23일차(Animation - Clip)

29 Jun 2021

Reading time ~2 minutes

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); } ``` 만든 키프레임을 파일로 만든다(최적화)


DirectX Share Tweet +1