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

      게임 개발자 유정룡

      포트폴리오

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

Direct3D11 공부 29일차(ComputeShader - AnimationBuffer)

07 Jul 2021

Reading time ~2 minutes

AnimationBuffer

이제 지금까지 배운 ComputeShader를 갖고 애니메이션에 적용해보자

그 전에 ComputeShader를 넘겨주고 받을 때, 구조체를 넘겨서 받을 수 있는 StructBuffer를 만들고 사용하자

StructuredBuffer

void* inputData;

UINT inputStride;
UINT inputCount;

UINT outputStride;
UINT outputCount;

Input과 Output을 담당하는 변수들이다 각각 Stride는 구조체의 크기, Count는 넘길 갯수다.

나머진 RawBuffer만들때나 TextrueBuffer를 만들때와 같은 방법이다.

ModelAnimator

private:
	struct CS_InputDesc
	{
		Matrix Bone;
	};

	struct CS_OutputDesc
	{
		Matrix Result;
	};

	struct AttachDesc
	{
		UINT BoneIndex = 0;
		float Padding[3];
	}attachDesc;

private:
	Shader* computeShader;
	StructuredBuffer* computeBuffer = NULL;

	CS_InputDesc* csInput = NULL;
	CS_OutputDesc* csOutput = NULL;

	ID3DX11EffectShaderResourceVariable* sInputSRV;
	ID3DX11EffectUnorderedAccessViewVariable* sOutputUAV;

	ConstantBuffer* computeAttachBuffer = NULL;

	ID3DX11EffectConstantBuffer* sComputeAttachBuffer;
	ID3DX11EffectConstantBuffer* sComputeTweenBuffer;
	ID3DX11EffectConstantBuffer* sComputeBlendBuffer;

받아올 값에 관한 버퍼들이다.

ModelAnimator::ModelAnimator(Shader * shader)
	: shader(shader)
{
	model = new Model();

	tweenBuffer = new ConstantBuffer(&tweenDesc, sizeof(TweenDesc) * MAX_MODEL_INSTANCE);
	sTweenBuffer = shader->AsConstantBuffer("CB_TweenFrame");
	
	blendBuffer = new ConstantBuffer(&blendDesc, sizeof(BlendDesc) * MAX_MODEL_INSTANCE);
	sBlendBuffer = shader->AsConstantBuffer("CB_BlendFrame");

	instanceBuffer = new VertexBuffer(worlds, MAX_MODEL_INSTANCE, sizeof(Matrix), 1, true);

	computeShader = new Shader(L"63_GetAnimationBone.fx");
	computeAttachBuffer = new ConstantBuffer(&attachDesc, sizeof(AttachDesc));

	sInputSRV = computeShader->AsSRV("Input");
	sOutputUAV = computeShader->AsUAV("Output");

	sComputeAttachBuffer = computeShader->AsConstantBuffer("CB_AttachBone");
	sComputeTweenBuffer = computeShader->AsConstantBuffer("CB_TweenFrame");
	sComputeBlendBuffer = computeShader->AsConstantBuffer("CB_BlendFrame");
}

생성자 부분을 기존의 것이 아닌 ConstantBuffer를 사용해서 GPU계산을 사용해서 값을 받아온다.

void ModelAnimator::CreateComputeBuffer()
{
	UINT clipCount = model->ClipCount();
	UINT inSize = clipCount * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS;
	UINT outSize = MAX_MODEL_INSTANCE;

	csInput = new CS_InputDesc[inSize];

	UINT count = 0;
	for (UINT clipIndex = 0; clipIndex < clipCount; clipIndex++)
	{
		for (UINT frameIndex = 0; frameIndex < MAX_MODEL_KEYFRAMES; frameIndex++)
		{
			for (UINT boneIndex = 0; boneIndex < MAX_MODEL_TRANSFORMS; boneIndex++)
			{
				csInput[count].Bone = clipTransforms[clipIndex].Transform[frameIndex][boneIndex];

				count++;
			}
		}//for(frameIndex)
	}//for(clipIndex);

	computeBuffer = new StructuredBuffer(csInput, sizeof(CS_InputDesc), inSize, sizeof(CS_OutputDesc), outSize);

	csOutput = new CS_OutputDesc[outSize];

	for (UINT i = 0; i < outSize; i++)
	{
		D3DXMatrixIdentity(&csOutput[i].Result);
	}
}

그리고 현재 있는 본 값을 받아서 버퍼를 만들어 준다.

각 clip, frame, bone에 맞춰서 값을 갖고오고 버퍼를 생성해준다.

// Update
	if (computeBuffer != NULL)
	{
	computeAttachBuffer->Render();
	sComputeAttachBuffer->SetConstantBuffer(computeAttachBuffer->Buffer());
	sComputeTweenBuffer->SetConstantBuffer(tweenBuffer->Buffer());
	sComputeBlendBuffer->SetConstantBuffer(blendBuffer->Buffer());

	sInputSRV->SetResource(computeBuffer->SRV());
	sOutputUAV->SetUnorderedAccessView(computeBuffer->UAV());

	// 인스턴스에서 하나의 본을 갖고옴
	computeShader->Dispatch(0, 0, 1, 1, 1);
	computeBuffer->CopyFromOutput(csOutput);
}

업데이트 마다 인스턴스에서 하나의 본을 계속해서 갖고온다.

void ModelAnimator::GetAttachTransform(UINT instance, Matrix * outResult)
{
	if (csOutput == NULL)
	{
		D3DXMatrixIdentity(outResult);
		return;
	}

	Matrix transform = model->BoneByIndex(attachDesc.BoneIndex)->Transform(); // 기준 본 행렬
	Matrix result = csOutput[instance].Result; // 애니메이션 행렬
	Matrix world = GetTransform(instance)->World();

	*outResult = transform * result * world;
}

그리고 값을 갖고올때 GPU에서 갖고온 데이터를 갖고 넘겨준다.

잘 나온다.

이제 애니메이션에 맞는 본을 잘 갖고왔는지 확인을 해보자

사각형을 각 손에 붙여서 업데이트 해보자

생각한대로 잘 나온다.



DirectX Share Tweet +1