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

      게임 개발자 유정룡

      포트폴리오

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

Direct3D11 공부 24일차(ModelAnimator - CreateClip)

30 Jun 2021

Reading time ~2 minutes

ModelAnimator

지금까지 애니메이션 파일에 있는 정보들을 읽었다. 이 정보를 갖고 클립들을 저장하는 변수를 만들자

이런 식으로 구조가 짜져있다. 그런데 이 구조를 갖고 GPU에 그대로 보내게 되면 보낼수 없다. cbuffer에 한번에 보낼 수 있는 용량은 4996바이트이기 때문이다. 그래서 이 구조를 갖고 텍스처로 만들어 보낸다.

텍스처는 몇개 보내든 상관없기 때문이다.

ModelAnimator

#pragma once

class ModelAnimator
{
public:
	ModelAnimator(Shader* shader);
	~ModelAnimator();

	void Update();
	void Render();

public:
	void ReadMesh(wstring file);
	void ReadMaterial(wstring file);
	void ReadClip(wstring file);

	Transform* GetTransform() { return transform; }
	Model* GetModel() { return model; }

	void Pass(UINT pass);

private:
	void CreateTexture();
	void CreateClipTransform(UINT index);

private:
	struct ClipTransforms
	{
		Matrix** Transform;

		ClipTransforms()
		{
			Transform = new Matrix*[MAX_MODEL_KEYFRAMES];

			for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
			{
				Transform[i] = new Matrix[MAX_MODLE_TRANSFORMS];
			}
		}

		~ClipTransforms()
		{
			for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
			{
				SafeDeleteArray(Transform[i]);
			}

			SafeDeleteArray(Transform);
		}
	};
	ClipTransforms* clipTransforms = NULL;

	ID3D11Texture2D* texture = NULL;
	ID3D11ShaderResourceView* srv = NULL;

private:
	Shader* shader = NULL;
	Model* model = NULL;
	Transform* transform = NULL;
};

ModelRender와 비슷한 형태를 갖고있다.

이 클래스에서 가장 중요한 함수먼저 보자

void ModelAnimator::CreateClipTransform(UINT index)
{
	Matrix* bones = new Matrix[MAX_MODLE_TRANSFORMS];

	ModelClip* clip = model->ClipByIndex(index);
	for (UINT f = 0; f < clip->FrameCount; f++)
	{
		for (UINT b = 0; b < model->BoneCount(); b++)
		{
			ModelBone* bone = model->BoneByIndex(b);

			Matrix parent;
			Matrix invGlobal = bone->Transform();
			D3DXMatrixInverse(&invGlobal, NULL, &invGlobal);

			int parentIndex = bone->ParentIndex();
			if (parentIndex < 0)
			{
				D3DXMatrixIdentity(&parent);
			}
			else
			{
				parent = bones[parentIndex];
			}

			Matrix animation;
			ModelKeyframe* frame = clip->Keyframe(bone->Name());

			if (frame != NULL)
			{
				ModelKeyframeData& data = frame->Transforms[f];

				Matrix S, R, T;
				D3DXMatrixScaling(&S, data.Scale.x, data.Scale.y, data.Scale.z);
				D3DXMatrixRotationQuaternion(&R, &data.Rotation);
				D3DXMatrixTranslation(&T, data.Translation.x, data.Translation.y, data.Translation.z);

				animation = S * R * T;
			}

			else
			{
				D3DXMatrixIdentity(&animation);
			}

			bones[b] = animation * parent;
			clipTransforms[index].Transform[f][b] = invGlobal * bones[b];
		}// for(b)
	}// for(f)
}

간단한데 조금 복잡하다.

이 애니메이션을 갖고올 때, Local좌표에 부모의 좌표(World)를 곱해 현재 본의 위치를 World좌표로 갖고왔었다. 그럼 이제 적용할때는 다시 이것을 활용해야 한다.

본의 위치를 갖고올때 다시 animation과 parent의 행렬을 곱해 world행렬을 갖고온다. 그리고 난 뒤, 클립의 Transform을 저장할 때, World행렬로 저장하면 원하는 값보다 더 많은 값이 나오게 된다. 그러니 이 전에 현재 Bone의 위치를 뒤집은 좌표를 구한 뒤 곱하면 원하는 정확한 좌표가 나온다.

부모의 위치가 30이고 본의 로컬 위치가 20일경우 본의 월드 위치는 50이다.

하지만 그 밑에 있는 ClipTransform을 구할 땐, 현재 Bone의 위치는 World이기 때문에 이 상태로 넣고 작동을 시키면 World의 World가 들어가 원하는 값이 안나온다. 그러니 저장할 때는 역행렬을 곱해 Local로 만들어 넣어준다.



DirectX Share Tweet +1