본문 바로가기

DirectX11 3D/기본 문법

<DirectX11 3D> 63 - ComputeShader(CS)(3) - StructuredBuffer를 이용한 GetAnimationBone

 

필요한 개념


Animation Bone을 구하기 위해 Structured Buffer를 사용할 것이다.
인스턴싱된 각각의 애니메이션 플레이 되고 있을 때, 우리가 선택한 본의 공간을 가져옴
StructuredBuffer : 구조체를 CS의 입력/출력 자료형으로 사용(구조체로 1차원 배열로 넘김)
얘를 이용해서 bone 번호를 줘서 해당 본의 위치를 CS를 통해 구해올 것이다.

byteAddress는 4바이트 단위로 끊어야 하니까 불편해서
흔히 structuredBuffer를 많이 사용함

지금은 모델 본 한개만 가져오지만, 나중에 추가적으로 다 가져올 예정임

* Shader에서 입력으로 ByteAddress와 Texture로 받고 출력을 Structured Buffer로 받을 수 없냐?(섞어서)
다 가능하다.(이해 편하게 하려고 1대 1로 시험해본것 뿐임)
쪼개서 사용해도 된다.

셰이더 본격적 다루기 위한 프레임워크를 만듬

Bone을 얻어와서 Box Collider를 붙여줄 것이다.

ModelAnimator에 추가적으로 필요한 부분 만듬

 

 

 

 

 

 

 

Buffers.h 추가된 내용


더보기
...

///////////////////////////////////////////////////////////////////////////////

class StructuredBuffer : public CsResource
{
public:
	// inputData -> 구조체 데이터가 들어옴
	// ByteAddress할때는 하나당 4바이트 인데
	// 구조체는 하나당 몇 바이트인지 모른다. 구조체 하나의 크기 (stride)
	// inputCount -> 구조체 개수(배열의 개수)
	StructuredBuffer(void* inputData, UINT inputStride, UINT inputCount, UINT outputStride = 0, UINT outputCount = 0);
	~StructuredBuffer();

private:
	void CreateInput() override;
	void CreateSRV() override;

	void CreateOutput() override;
	void CreateUAV() override;

	void CreateResult() override;

public:
	UINT InputByteWidth() { return inputStride * inputCount; }
	UINT OutputByteWidth() { return outputStride * outputCount; }

	void CopyToInput(void* data);
	void CopyFromOutput(void* data);

private:
	void* inputData;

	UINT inputStride;
	UINT inputCount;

	UINT outputStride;
	UINT outputCount;
};

 

 

 

 

 

 

 

Buffers.cpp 추가된 내용


더보기
...

///////////////////////////////////////////////////////////////////////////////


StructuredBuffer::StructuredBuffer(void* inputData, UINT inputStride, UINT inputCount, UINT outputStride, UINT outputCount)
	: CsResource()
	, inputData(inputData)
	, inputStride(inputStride), inputCount(inputCount)
	, outputStride(outputStride), outputCount(outputCount)
{
	// output은 우리가 따로 지정하지 않았다 간주
	// input과 동일하게 함
	if (outputStride == 0 || outputCount == 0)
	{
		this->outputStride = inputStride;
		this->outputCount = inputCount;
	}

	CreateBuffer();
}

StructuredBuffer::~StructuredBuffer()
{

}

void StructuredBuffer::CreateInput()
{
	ID3D11Buffer* buffer = NULL;

	D3D11_BUFFER_DESC desc;
	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));

	desc.ByteWidth = InputByteWidth(); // 전체 크기
	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; // Resource는 모두 SRV와 연결된다고 했음
	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
	desc.StructureByteStride = inputStride;
	desc.Usage = D3D11_USAGE_DYNAMIC; // 데이터를 써줘야 하니깐
	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

	D3D11_SUBRESOURCE_DATA subResource = { 0 };
	subResource.pSysMem = inputData;

	Check(D3D::GetDevice()->CreateBuffer(&desc, inputData != NULL ? &subResource : NULL, &buffer));

	input = (ID3D11Resource*)buffer;
}

void StructuredBuffer::CreateSRV()
{
	ID3D11Buffer* buffer = (ID3D11Buffer*)input;

	D3D11_BUFFER_DESC desc;
	buffer->GetDesc(&desc);


	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	srvDesc.Format = DXGI_FORMAT_UNKNOWN;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
	srvDesc.BufferEx.NumElements = inputCount; // 개수를 그대로 넣음
	// byteAddress할때에는 4바이트니깐 / 4해줬는데

	Check(D3D::GetDevice()->CreateShaderResourceView(buffer, &srvDesc, &srv));
}

void StructuredBuffer::CreateOutput()
{
	ID3D11Buffer* buffer = NULL;

	D3D11_BUFFER_DESC desc;
	ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));

	desc.ByteWidth = OutputByteWidth();
	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
	desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
	desc.StructureByteStride = outputStride;

	Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));

	output = (ID3D11Resource*)buffer;
}

void StructuredBuffer::CreateUAV()
{
	ID3D11Buffer* buffer = (ID3D11Buffer*)output;

	D3D11_BUFFER_DESC desc;
	buffer->GetDesc(&desc);


	D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
	ZeroMemory(&uavDesc, sizeof(D3D11_UNORDERED_ACCESS_VIEW_DESC));
	uavDesc.Format = DXGI_FORMAT_UNKNOWN; // 포맷을 알 수 없음
	uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
	uavDesc.Buffer.NumElements = outputCount;

	Check(D3D::GetDevice()->CreateUnorderedAccessView(buffer, &uavDesc, &uav));
}

void StructuredBuffer::CreateResult()
{
	ID3D11Buffer* buffer;

	D3D11_BUFFER_DESC desc;
	((ID3D11Buffer*)output)->GetDesc(&desc);
	desc.Usage = D3D11_USAGE_STAGING;
	desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
	desc.BindFlags = 0;
	desc.MiscFlags = 0;

	Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));

	result = (ID3D11Resource*)buffer;
}

void StructuredBuffer::CopyToInput(void* data)
{
	D3D11_MAPPED_SUBRESOURCE subResource;
	D3D::GetDC()->Map(input, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
	{
		memcpy(subResource.pData, data, InputByteWidth());
	}
	D3D::GetDC()->Unmap(input, 0);
}

void StructuredBuffer::CopyFromOutput(void* data)
{
	D3D::GetDC()->CopyResource(result, output);

	D3D11_MAPPED_SUBRESOURCE subResource;
	D3D::GetDC()->Map(result, 0, D3D11_MAP_READ, 0, &subResource);
	{
		memcpy(data, subResource.pData, OutputByteWidth());
	}
	D3D::GetDC()->Unmap(result, 0);
}

 

 

Collider.h


더보기
#pragma once

// 사용 편하게 하려고 묶어놈
struct ColliderObject
{
	class Transform* Init = NULL;
	class Transform* Transform = NULL;
	class Collider* Collider = NULL;
};



/*
	BoxCollider
*/


class Collider
{
public:
	Collider(Transform* transform, Transform* init = NULL);
	~Collider();

	void Update();
	// 보통 충돌체는 녹색이어서, 녹색으로 기본값줌
	void Render(Color color = Color(0, 1, 0, 1));

	Transform* GetTransform() { return transform; }

private:
	// Init이 기준이 됨
	// 최종 위치 = 기준 초기 값(Init) * 이동한 트랜스폼
	// 처음에 회전이나 이런거 기준 잡아 놓고 외부에서 transform 받아오면
	// 그거 곱해서 위치를 구함
	Transform* init = NULL;
	Transform* transform = NULL;

	// 라인을 통해 그려줘야 눈으로 볼 수 있다.
	Vector3 lines[8];
};

 

 

 

 

 

 

 

Collider.Cpp


더보기
#include "Framework.h"
#include "Collider.h"


Collider::Collider(Transform* transform, Transform* init) :
	transform(transform), init(init)
{
	// 육면체 그려주는 라인
	// 0 - 박스의 가장 앞 좌하단(가장 작은 값)
	// 7 - 박스의 가장 뒤 우상단(가장 큰 값)
	// 두개의 값이면 박스의 충돌을 계산할 수 있다.
	lines[0] = Vector3(-0.5f, -0.5f, -0.5f);
	lines[1] = Vector3(-0.5f, +0.5f, -0.5f);
	lines[2] = Vector3(+0.5f, -0.5f, -0.5f);
	lines[3] = Vector3(+0.5f, +0.5f, -0.5f);
	lines[4] = Vector3(-0.5f, -0.5f, +0.5f);
	lines[5] = Vector3(-0.5f, +0.5f, +0.5f);
	lines[6] = Vector3(+0.5f, -0.5f, +0.5f);
	lines[7] = Vector3(+0.5f, +0.5f, +0.5f);
}

Collider::~Collider()
{
}

void Collider::Update()
{
}

void Collider::Render(Color color)
{
	// 위치 마킹으로 만 씀
	Transform temp;
	temp.World(transform->World());

	if (init != NULL)
		temp.World(init->World() * transform->World());

	Matrix world = temp.World();

	// 계산된 공간으로 라인을 모두 변환
	Vector3 dest[8];
	for (UINT i = 0; i < 8; i++)
		D3DXVec3TransformCoord(&dest[i], &lines[i], &world);

	//Front
	DebugLine::Get()->RenderLine(dest[0], dest[1], color);
	DebugLine::Get()->RenderLine(dest[1], dest[3], color);
	DebugLine::Get()->RenderLine(dest[3], dest[2], color);
	DebugLine::Get()->RenderLine(dest[2], dest[0], color);

	//Backward
	DebugLine::Get()->RenderLine(dest[4], dest[5], color);
	DebugLine::Get()->RenderLine(dest[5], dest[7], color);
	DebugLine::Get()->RenderLine(dest[7], dest[6], color);
	DebugLine::Get()->RenderLine(dest[6], dest[4], color);

	//Side
	DebugLine::Get()->RenderLine(dest[0], dest[4], color);
	DebugLine::Get()->RenderLine(dest[1], dest[5], color);
	DebugLine::Get()->RenderLine(dest[2], dest[6], color);
	DebugLine::Get()->RenderLine(dest[3], dest[7], color);
}

 

 

ModelAnimator.h 추가된 내용


더보기
class ModelAnimator
{
...
public:
	UINT GetTransformCount() { return transforms.size(); }
    
    // 계산할 본의 번호를 설정
	void SetAttachTransform(UINT boneIndex);
	// 계산된 본의 결과를 가져옴
	void GetAttachTransform(UINT instance, Matrix* outResult);
    
private:    
	// 컴퓨트 세이더에 계산할 값을 줘야한다.
	void CreateComputeBuffer();
    
private:
	// CS로 입력될 Input, Output 구조체 정의
	struct CS_InputDesc
	{
		Matrix Bone;
	};

	struct CS_OutputDesc
	{
		Matrix Result;
	};

	// 정보를 넘길 구조체
	struct AttachDesc
	{
		// 우리가 구해오고자 하는 본 번호
		// 기본 40한 이유 -> 오른손 엄지(위치 구해옴)
		UINT BoneIndex = 0;
		float Padding[3];
	}attachDesc;

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

	// 입력이 몇개 될지 몰라서
	CS_InputDesc* csInput = NULL;
	CS_OutputDesc* csOutput = NULL;

	// CS로 Buffer SRV를 넘겨야 한다.
	ID3DX11EffectShaderResourceVariable* sInputSRV;
	ID3DX11EffectUnorderedAccessViewVariable* sOutputUAV;

	// AttachDesc가 들어갈버퍼
	ConstantBuffer* computeAttachBuffer;

	ID3DX11EffectConstantBuffer* sComputeAttachBuffer;
	// Tween Blend도 넘어갈 것이다.
	ID3DX11EffectConstantBuffer* sCompuetTweenBuffer;
	ID3DX11EffectConstantBuffer* sComputeBlendBuffer;
}

 

 

 

 

 

 

 

ModelAnimator.cpp 추가된 내용


더보기
...

ModelAnimator::ModelAnimator(Shader* shader) 
	: shader(shader)
{
	...
	// Compute(CS)용 Shader
	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");
}

void ModelAnimator::Update()
{
	// Texture가 null이었다면 Texture를 세팅해서
	// 넘길 수 있도록 세팅
	if (texture == NULL)
	{
		for (ModelMesh* mesh : model->Meshes())
			mesh->SetShader(shader);

		CreateTexture();

		// 컴퓨트 세이더에 계산할 값을 줘야한다.
		CreateComputeBuffer();
	}

	// 0보다 크면 Blend모드로 수행
	// 0이라면 TweenMode로 수행

	// 실제로 그릴 개수 만큼 반복(for문이어서 느려서 computeShader 쪽으로
	// 나중에 옮김)
	for (UINT i = 0; i < transforms.size(); i++)
		blendDesc[i].Mode == 0 ? UpdateTweenMode(i) : UpdateBlendMode(i);

	// 버퍼 자체로 값을 밀어줌
	tweenBuffer->Render();
	blendBuffer->Render();

	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());

		// Dispatch의 그룹은 충돌체 하나만 사용하므로 1개만 설정하고
		// 이후에 충돌체를 한번에 전부 계산할때 그룹을 늘린다.
		computeShader->Dispatch(0, 0, 1, 1, 1);
		computeBuffer->CopyFromOutput(csOutput);

		// 본 위치를 리턴할 것이다. 거기다가 충돌체를 붙일 것이다.
	}

	for (ModelMesh* mesh : model->Meshes())
		mesh->Update();
}

void ModelAnimator::Render()
{
	// 어느 버퍼로 세팅할지(한번만 해주면됨)
	sTweenBuffer->SetConstantBuffer(tweenBuffer->Buffer());
	sBlendBuffer->SetConstantBuffer(blendBuffer->Buffer());

	instanceBuffer->Render();

	for (ModelMesh* mesh : model->Meshes())
		mesh->Render(transforms.size());
}

void ModelAnimator::SetAttachTransform(UINT boneIndex)
{
	// 몇번 본이 Attach 될 건지
	attachDesc.BoneIndex = boneIndex;
}

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;
}

void ModelAnimator::CreateComputeBuffer()
{
	// 정보들을 밀어줌
	UINT clipCount = model->ClipCount();
	// 입력할 데이터 크기
	UINT inSize = clipCount * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS;
	// cs에서 리턴되는 값은 INSTANCE 개수만큼
	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);

}

 

 

 

GetAnimationBoneDemo.h


더보기
#pragma once
#include "Systems/IExecute.h"

class GetAnimationBoneDemo : public IExecute
{
public:
	virtual void Initialize() override;
	virtual void Ready() override {};
	virtual void Destroy() override;
	virtual void Update() override;
	virtual void PreRender() override {};
	virtual void Render() override;
	virtual void PostRender() override {};
	virtual void ResizeScreen() override {};

private:
	void Mesh();
	void Airplane();
	void Kachujin();
	void KachujinCollider();

	void Pass(UINT mesh, UINT model, UINT anim);

private:
	Shader* shader;

	CubeSky* sky;

	Material* floor;
	Material* stone;
	Material* brick;
	Material* wall;

	MeshRender* cube;
	MeshRender* cylinder;
	MeshRender* sphere;
	MeshRender* grid;

	ModelRender* airplane = NULL;

	ModelAnimator* kachujin = NULL;

	// Collider의 인스턴싱은 몇개 인지 모른다.(그래서 *하나 더 붙음)
	ColliderObject** colliders;

	// 나중에 Path 관리를 편하게 하기 위해
	vector<MeshRender*> meshes;
	vector<ModelRender*> models;
	vector<ModelAnimator*> animators;
};

 

 

 

 

 

 

 

GetAnimationBoneDemo.cpp


더보기
#include "stdafx.h"
#include "GetAnimationBoneDemo.h"

void GetAnimationBoneDemo::Initialize()
{
	Context::Get()->GetCamera()->RotationDegree(20, 0, 0);
	Context::Get()->GetCamera()->Position(1, 36, -85);
	

	shader = new Shader(L"55_Render.fx");

	sky = new CubeSky(L"Environment/GrassCube1024.dds");

	Mesh();
	Airplane();
	Kachujin();
	KachujinCollider();
}

void GetAnimationBoneDemo::Destroy()
{
	SafeDelete(shader);
	
	SafeDelete(sky);
	SafeDelete(cube);
	SafeDelete(cylinder);
	SafeDelete(sphere);
	SafeDelete(grid);

	SafeDelete(floor);
	SafeDelete(stone);
	SafeDelete(brick);
	SafeDelete(wall);

	SafeDelete(airplane); 
	SafeDelete(kachujin);
}

void GetAnimationBoneDemo::Update()
{
	sky->Update();

	cube->Update();
	grid->Update();
	cylinder->Update();
	sphere->Update();

	airplane->Update();
	kachujin->Update();

	for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
	{
		// 카추진 위치 얻어옴(업데이트 시킬)
		Matrix attach;
		kachujin->GetAttachTransform(i, &attach);

		// 얼마만큼 이동할지
		colliders[i]->Collider->GetTransform()->World(attach);
		colliders[i]->Collider->Update();
	}
}

void GetAnimationBoneDemo::Render()
{
	sky->Render();
	
	Pass(0, 1, 2);

	wall->Render();
	sphere->Render();

	brick->Render();
	cylinder->Render();

	stone->Render();
	cube->Render();

	floor->Render();
	grid->Render();

	airplane->Render();
	kachujin->Render();

	for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
		colliders[i]->Collider->Render();
}

void GetAnimationBoneDemo::Mesh()
{
	//Create Material
	{
		floor = new Material(shader);
		floor->DiffuseMap("Floor.png");
		//floor->SpecularMap("Floor_Specular.png");
		//floor->NormalMap("Floor_Normal.png");
		//floor->Specular(1, 1, 1, 20);

		stone = new Material(shader);
		stone->DiffuseMap("Stones.png");
		//stone->SpecularMap("Stones_Specular.png");
		//stone->NormalMap("Stones_Normal.png");
		//stone->Specular(1, 1, 1, 20);

		brick = new Material(shader);
		brick->DiffuseMap("Bricks.png");
		//brick->SpecularMap("Bricks_Specular.png");
		//brick->NormalMap("Bricks_Normal.png");
		//brick->Specular(1, 0.3f, 0.3f, 20);

		wall = new Material(shader);
		wall->DiffuseMap("Wall.png");
		//wall->SpecularMap("Wall_Specular.png");
		//wall->NormalMap("Wall_Normal.png");
		//wall->Specular(1, 1, 1, 20);
	}

	//Create Mesh
	{
		Transform* transform = NULL;

		cube = new MeshRender(shader, new MeshCube());
		transform = cube->AddTransform();
		transform->Position(0, 5, 0);
		transform->Scale(20, 10, 20);

		grid = new MeshRender(shader, new MeshGrid(5, 5));
		transform = grid->AddTransform();
		transform->Position(0, 0, 0);
		transform->Scale(12, 1, 12);

		cylinder = new MeshRender(shader, new MeshCylinder(0.5f, 3.0f, 20, 20));
		sphere = new MeshRender(shader, new MeshSphere(0.5f, 20, 20));
		for (UINT i = 0; i < 5; i++)
		{
			transform = cylinder->AddTransform();
			transform->Position(-30, 6, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);

			transform = cylinder->AddTransform();
			transform->Position(30, 6, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);


			transform = sphere->AddTransform();
			transform->Position(-30, 15.5f, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);

			transform = sphere->AddTransform();
			transform->Position(30, 15.5f, -15.0f + (float)i * 15.0f);
			transform->Scale(5, 5, 5);
		}
	}

	sphere->UpdateTransforms();
	cylinder->UpdateTransforms();
	cube->UpdateTransforms();
	grid->UpdateTransforms();

	// 렌더링 할 것들을 추가
	meshes.push_back(sphere);
	meshes.push_back(cylinder);
	meshes.push_back(cube);
	meshes.push_back(grid);
}

void GetAnimationBoneDemo::Airplane()
{
	airplane = new ModelRender(shader);
	airplane->ReadMesh(L"B787/Airplane");
	airplane->ReadMaterial(L"B787/Airplane");

	Transform* transform = airplane->AddTransform();
	transform->Position(2.0f, 9.91f, 2.0f);
	transform->Scale(0.004f, 0.004f, 0.004f);
	airplane->UpdateTransforms();

	models.push_back(airplane);
}

void GetAnimationBoneDemo::Kachujin()
{
	kachujin = new ModelAnimator(shader);
	kachujin->ReadMesh(L"Kachujin/Mesh");
	kachujin->ReadMaterial(L"Kachujin/Mesh");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Idle");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Walk");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Run");
	kachujin->ReadClip(L"Kachujin/Sword And Shield Slash");
	kachujin->ReadClip(L"Kachujin/Salsa Dancing");


	Transform* transform = NULL;

	transform = kachujin->AddTransform();
	transform->Position(0, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(0, 0, 1.0f);

	transform = kachujin->AddTransform();
	transform->Position(-15, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(1, 1, 1.0f);

	transform = kachujin->AddTransform();
	transform->Position(-30, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(2, 2, 0.75f);

	transform = kachujin->AddTransform();
	transform->Position(15, 0, -30);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayBlendMode(3, 0, 1, 2);
	kachujin->SetBlendAlpha(3, 1.5f);

	transform = kachujin->AddTransform();
	transform->Position(30, 0, -32.5f);
	transform->Scale(0.075f, 0.075f, 0.075f);
	kachujin->PlayTweenMode(4, 4, 0.75f);

	kachujin->UpdateTransforms();
	// 오른손 쪽(40번 본)
	kachujin->SetAttachTransform(40);

	animators.push_back(kachujin);
}

void GetAnimationBoneDemo::KachujinCollider()
{
	// 인스턴싱 개수
	UINT count = kachujin->GetTransformCount();

	colliders = new ColliderObject*[count];

	for (UINT i = 0; i < count; i++)
	{
		colliders[i] = new ColliderObject();

		// 기준 위치
		colliders[i]->Init = new Transform();
		colliders[i]->Init->Position(0, 0, 0);
		colliders[i]->Init->Scale(10, 30, 10);

		colliders[i]->Transform = new Transform();
		colliders[i]->Collider = new Collider(colliders[i]->Transform, colliders[i]->Init);
	}

}

void GetAnimationBoneDemo::Pass(UINT mesh, UINT model, UINT anim)
{
	for (MeshRender* temp : meshes)
		temp->Pass(mesh);

	for (ModelRender* temp : models)
		temp->Pass(model);

	for (ModelAnimator* temp : animators)
		temp->Pass(anim);
}

 

 

 

 

 

63_GetAnimationBone.fx


더보기
#include "00_Global.fx"
#include "00_Render.fx"

// Structured Buffer는 반드시 입출력이 구조체가 된다.
struct InputDesc
{
    // Matrix로 구조체이긴 하지만 그 맴버를 셰디어 쪽에서는
    // 무조건 구조체로 다시 한번 묶어줘야 사용 가능
    matrix Bone;
};

StructuredBuffer<InputDesc> Input;

struct OutputDesc
{
    matrix Result;
};

RWStructuredBuffer<OutputDesc> Output;

// 어느 본을 구할건지(본 번호를 통해)
cbuffer CB_AttachBone
{
    uint AttachBoneIndex;
};

// 해당 본만구할꺼라서 간단하게
// 스레드의 번호는 인스턴스의 번호와 같도록 매칭해놈
matrix TweenMode(uint index)
{
    uint boneIndex[2];
    matrix result = 0;
    
    
    // 현재 프레임
    
    // 본 하나만 구할 거라서 이렇게 해놈
    // MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS 한 페이지 수
    // Clip(면), KeyFrame(행), 그 결과에서 몇 번 열 (Transform)까지 가야 하는지를 계산
    // 면 번호를 건너뜀
    boneIndex[0] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
    // y 방향으로 이동
    // 이 갯수만큼 건너뛰어야함
    // 프레임 건너뜀
    boneIndex[0] += (TweenFrames[index].Curr.CurrFrame * MAX_MODEL_TRANSFORMS);
    // x 방향 만큼만 이동
    boneIndex[0] += AttachBoneIndex;

    // 다음 프레임
    
    boneIndex[1] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
    boneIndex[1] += (TweenFrames[index].Curr.NextFrame * MAX_MODEL_TRANSFORMS);
    boneIndex[1] += AttachBoneIndex;
    
    matrix currFrame = Input[boneIndex[0]].Bone;
    matrix nextFrame = Input[boneIndex[1]].Bone;
    
    // 이전에 애니메이션 할때는 전체를 했지만
    // 우리가 리턴받을 본 하나만 가져옴(이번에는 하나만 구한다고 했음)
    // 현재 프레임과 다음 프레임 구해줌
    result = lerp(currFrame, nextFrame, TweenFrames[index].Curr.Time);
    
    // 다음 클립이 있다면 다음 프레임과 보간 해줌
    [flatten]
    if(TweenFrames[index].Next.Clip > -1)
    {
        boneIndex[0] = (TweenFrames[index].Next.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        boneIndex[0] += (TweenFrames[index].Next.CurrFrame * MAX_MODEL_TRANSFORMS);
        boneIndex[0] += AttachBoneIndex;
    
        boneIndex[1] = (TweenFrames[index].Next.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        boneIndex[1] += (TweenFrames[index].Next.NextFrame * MAX_MODEL_TRANSFORMS);
        boneIndex[1] += AttachBoneIndex;
        
        matrix currFrame = Input[boneIndex[0]].Bone;
        matrix nextFrame = Input[boneIndex[1]].Bone;
        
        matrix nextAnim = lerp(currFrame, nextFrame, TweenFrames[index].Next.Time);
        
        result = lerp(result, nextAnim, TweenFrames[index].TweenTime);
    }
    
    return result;
}

matrix BlendMode(uint index)
{
    uint boneIndex[2];
    matrix animation[3];
    
    
    BlendFrame frame = BlendFrames[index];
    
    
    // 여기선 정점의 가중치(BlendWeight)가 필요 없다. 공간만 가져오면 된다.
    // 기존에는 본들 다그려져야 해서 다 구행와야 했다.(모든 본이 다 돌았지만)
    // 여기선 필요한 본 1개만 가져옴
    
    [unroll(3)]
    for (int i = 0; i < 3; i++)
    {
        boneIndex[0] = (frame.Clip[i].Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        boneIndex[0] += (frame.Clip[i].CurrFrame * MAX_MODEL_TRANSFORMS);
        boneIndex[0] += AttachBoneIndex;
    
        boneIndex[1] = (frame.Clip[i].Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
        boneIndex[1] += (frame.Clip[i].NextFrame * MAX_MODEL_TRANSFORMS);
        boneIndex[1] += AttachBoneIndex;
    
        matrix currFrame = Input[boneIndex[0]].Bone;
        matrix nextFrame = Input[boneIndex[1]].Bone;
    
        animation[i] = lerp(currFrame, nextFrame, TweenFrames[index].Curr.Time);
    }
    
    int clipA = (int) frame.Alpha;
    int clipB = clipA + 1;
        
    float alpha = frame.Alpha;
    if (alpha >= 1.0f)
    {
        alpha = frame.Alpha - 1.0f;
            
        if (frame.Alpha >= 2.0f)
        {
            clipA = 1;
            clipB = 2;
        }
    }
        
    return lerp(animation[clipA], animation[clipB], alpha);
}


// x방향을 인스턴스로 사용, 따라서 Numthreads의 x값을 500을 준다.
// 500개의 스레드를 한번에 동작
// 0번 스레드는 0번 인스턴스....
// SV_GroupIndex : 0번부터 쭈르륵 순번 붙음(인스턴스 번호로 취급할 것이다.)
[numthreads(MAX_MODEL_INSTANCE, 1, 1)]
void CS(uint GroupIndex : SV_GroupIndex)
{
    matrix result = 0;
    if(BlendFrames[GroupIndex].Mode == 0)
        result = TweenMode(GroupIndex);
    else
        result = BlendMode(GroupIndex);
    
    Output[GroupIndex].Result = result;
}

technique11 T0
{
    pass P0
    {
        SetVertexShader(NULL);
        SetPixelShader(NULL);

        SetComputeShader(CompileShader(cs_5_0, CS()));
    }
}

 

 

 

 

 

 

 

 

 

 

 

결과