본문 바로가기

DirectX11 3D/기본 문법

<DirectX11 3D> 71 - GetMultiBones

 

필요한 개념


 

본을 전체적으로 한번에 계산해서 리턴받아오는 작업함

Dispatch(1, Instance, 1) - 스레드 그룹은 인스턴싱을 개수만큼 생성 -> 500 개의 스레드가 만들어짐
Numthreads(Transform, 1, 1) - 스레드 그룹 내의 개수는 트렌스폼 개수만큼 생성 -> 250개의 스레드 그룹이 만들어짐
최종 스레드의 개수 Instance * Transform -> 총 250 x 500개의 스레드가 만들어짐

한 그룹내에서 스레드를 1024개 사용할 수 있으니까 가능

Buffer를 2종류로 넘길 것이다. Input으로
하나는 world를 하나는 본들을 넘김(둘 다 StructuredBuffer로 넘김)

출력용 버퍼로는 TextureBuffer로 받을 것이다.

1장이면 충분 -> 현재 거를 넘길 거라서

TextureBuffer의 Input과 output이 약간 달라질 수 있어서 수정(출력으로 Texture2D로 하도록 수정)

Transform(기준 본) * Result(애니메이션 행렬) * world 계산을 Shader에서 수행(이전에는 ModelAnimator에서 수행했다.)


Transform -> InputBoneBuffer를 통해 Shader로 넘어감
result -> TransformsSRV를 통해 Shader로 넘어감
world -> InputWorldBuffer로 Shader로 넘어감

InputWorldBuffer - 인스턴스의 월드 행렬(y)
InputBoneBuffer - 기준 본 행렬(x)
기준 본 * 애니메이션 행렬 * 월드 행렬

 


Y축으로 500개의 그룹을 만들고 각 250개의 스레드를 만드는데
SV_DispatchThreadID를 사용하면 그대로 쭉이어진다.

CurrAnim : 현재 애니메이션 된 행렬

기준 본 * 애니메이션 행렬 * 월드 행렬 

ModelAnimator.h에서 SetAttachTransform()이 더이상 필요가 없다.
이 함수는 하나의 본 만을 계산할때 본 번호를 지정하려고 사용했었다. 현재는 한번에 전부를 계산하므로 필요가 없어진 함수다.

WeaponInitTransform -> 무기의 기준 본
ColliderInitTransform-> 충돌체의 기준 본

 

 

 

Buffers.h 수정된 내용


더보기
///////////////////////////////////////////////////////////////////////////////

class TextureBuffer : public CsResource
{
public:
	TextureBuffer(ID3D11Texture2D* src);
	~TextureBuffer();

private:
	void CreateSRV() override;

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

	void CreateResult() override;

public:
	UINT Width() { return width; }
	UINT Height() { return height; }
	UINT ArraySize() { return arraySize; }

	ID3D11Texture2D* Output() { return (ID3D11Texture2D*)output; }
	ID3D11ShaderResourceView* OutputSRV() { return outputSRV; }

	void CopyToInput(ID3D11Texture2D* texture);
	ID3D11Texture2D* CopyFromOutput();
	ID3D11Texture2D* Result() { return (ID3D11Texture2D*)result; }

private:
	UINT width, height, arraySize;
	DXGI_FORMAT format;

	ID3D11ShaderResourceView* outputSRV;
};

 

 

 

 

 

 

 

Buffers.cpp 수정된 내용


더보기
///////////////////////////////////////////////////////////////////////////////


TextureBuffer::TextureBuffer(ID3D11Texture2D* src)
{
	D3D11_TEXTURE2D_DESC srcDesc;
	src->GetDesc(&srcDesc);

	width = srcDesc.Width;
	height = srcDesc.Height;
	arraySize = srcDesc.ArraySize;
	format = srcDesc.Format;


	D3D11_TEXTURE2D_DESC desc;
	ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
	desc.Width = width;
	desc.Height = height;
	desc.ArraySize = arraySize;
	desc.Format = format;
	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	desc.MipLevels = 1;
	desc.SampleDesc.Count = 1;

	ID3D11Texture2D* texture = NULL;
	Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));
	D3D::GetDC()->CopyResource(texture, src);

	input = (ID3D11Resource*)texture;

	CreateBuffer();
}

TextureBuffer::~TextureBuffer()
{

}

void TextureBuffer::CreateSRV()
{
	ID3D11Texture2D* texture = (ID3D11Texture2D*)input;

	D3D11_TEXTURE2D_DESC desc;
	texture->GetDesc(&desc);

	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	srvDesc.Format = desc.Format;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
	srvDesc.Texture2DArray.MipLevels = 1;
	srvDesc.Texture2DArray.ArraySize = arraySize;

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

void TextureBuffer::CreateOutput()
{
	ID3D11Texture2D* texture = NULL;

	D3D11_TEXTURE2D_DESC desc;
	ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
	desc.Width = width;
	desc.Height = height;
	desc.ArraySize = arraySize;
	desc.Format = format;
	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
	desc.MipLevels = 1;
	desc.SampleDesc.Count = 1;
	Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));

	output = (ID3D11Resource*)texture;


	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	srvDesc.Format = desc.Format;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
	srvDesc.Texture2DArray.MipLevels = 1;
	srvDesc.Texture2DArray.ArraySize = arraySize;

	Check(D3D::GetDevice()->CreateShaderResourceView(texture, &srvDesc, &outputSRV));
}

void TextureBuffer::CreateUAV()
{
	ID3D11Texture2D* texture = (ID3D11Texture2D*)output;

	D3D11_TEXTURE2D_DESC desc;
	texture->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_TEXTURE2DARRAY;
	uavDesc.Texture2DArray.ArraySize = arraySize;

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

void TextureBuffer::CreateResult()
{
	ID3D11Texture2D* texture;

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

	Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));

	result = (ID3D11Resource*)texture;
}

// 초기값이 안들어가서 만들경우 넣어줘야한다.(다시 값 쓸 수 있도록)
void TextureBuffer::CopyToInput(ID3D11Texture2D* texture)
{
	D3D::GetDC()->CopyResource(input, texture);
}

// 리턴받아오기 위한 것(Texture로)
ID3D11Texture2D* TextureBuffer::CopyFromOutput()
{
	D3D::GetDC()->CopyResource(result, output);

	return (ID3D11Texture2D*)result;
}

 

 

ModelAnimator.h 추가된 내용


더보기
#pragma once

class ModelAnimator
{
private:
	// 연산량이 많아서
	// 30프레임으로 제한해서 한다.
	const float frameRate = 30.0f;
	// 프레임 계산할 frameTime
	float frameTime = 0.0f;


	/*Buffer를 2종류로 넘길 것이다.Input으로
		하나는 world를 하나는 본들을 넘김*/

	Shader* computeShader;
	// tranform을 넘기기 위해
	// Shader가 달라지기에 하나더 만듬
	ID3DX11EffectShaderResourceVariable* sTransformsSRV;

	StructuredBuffer* inputWorldBuffer;
	ID3DX11EffectShaderResourceVariable* sInputWorldSRV;

	StructuredBuffer* inputBoneBuffer;
	ID3DX11EffectShaderResourceVariable* sInputBoneSRV;


	// Return은 TextureBuffer로 받는다.
	TextureBuffer* outputBuffer;
	ID3DX11EffectUnorderedAccessViewVariable* sOutputUAV;

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

 

 

 

 

 

 

 

ModelAnimator.cpp 추가된 내용


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

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


	// Compute(CS)용 Shader
	{
		computeShader = new Shader(L"71_GetMultiBones.fx");
		
		// world 들을 넘기고 CS에서는 y 참조(인스턴싱 번호)로 이를 이용할 것이다.
		inputWorldBuffer = new StructuredBuffer(worlds, sizeof(Matrix), MAX_MODEL_INSTANCE);
		sInputWorldSRV = computeShader->AsSRV("InputWorlds");

		// 지금 bone 계산된게 없어서 NULL 줌
		inputBoneBuffer = new StructuredBuffer(NULL, sizeof(Matrix), MAX_MODEL_TRANSFORMS);
		sInputBoneSRV = computeShader->AsSRV("InputBones");
		
		// CS에 Texture를 넘김(Bone과 인스턴스를 넘기기 위해)
		ID3D11Texture2D* texture;
		D3D11_TEXTURE2D_DESC desc;
		ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
		desc.Width = MAX_MODEL_TRANSFORMS * 4;
		desc.Height = MAX_MODEL_INSTANCE;
		desc.ArraySize = 1; // 1장
		desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
		desc.MipLevels = 1;
		desc.SampleDesc.Count = 1;
		Check(D3D::GetDevice()->CreateTexture2D(&desc, NULL, &texture));

		outputBuffer = new TextureBuffer(texture);
		SafeRelease(texture);

		sOutputUAV = computeShader->AsUAV("Output");

		// cs에게 Transforms 넘길려고 하는 것임
		sTransformsSRV = computeShader->AsSRV("TransformsMap");
		sComputeTweenBuffer = computeShader->AsConstantBuffer("CB_TweenFrame");
		sComputeBlendBuffer = computeShader->AsConstantBuffer("CB_BlendFrame");
	}
}

ModelAnimator::~ModelAnimator()
{
	SafeDelete(model);

	SafeDeleteArray(clipTransforms);
	SafeRelease(texture);
	SafeRelease(srv);

	SafeDelete(tweenBuffer);
	SafeDelete(blendBuffer);

	SafeDelete(instanceBuffer);

	SafeDelete(computeShader);

	SafeDelete(inputWorldBuffer);
	SafeDelete(inputBoneBuffer);
	SafeDelete(outputBuffer);
}

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

		CreateTexture();


		// CS에 넘겨줄 자료형 만듬

		// 최초의 본(애니메이션이 적용되지 않은)이다.
		// Shader에서 기준본에서 애니메이션 행렬만큼 처리
		// 기준에서 현재 애니메이션 행렬 계산해서 InputTransform
		// 3개를 다 한번에 CS에서 계산해서 리턴해줌
		Matrix bones[MAX_MODEL_TRANSFORMS];
		for (UINT i = 0; i < model->BoneCount(); i++)
			bones[i] = model->BoneByIndex(i)->Transform();

		inputBoneBuffer->CopyToInput(bones);
	}

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

	// CS를 매 프레임 동작시켜도 되지만 애니메이션의 프레임 레이트에
	// 맞춰서 동작시키는 것이 효율적이다.
	frameTime += Time::Delta();
	// 30프레임이 지나갔다는 얘기
	if (frameTime > (1.0f / frameRate))
	{
		sComputeTweenBuffer->SetConstantBuffer(tweenBuffer->Buffer());
		sComputeBlendBuffer->SetConstantBuffer(blendBuffer->Buffer());

		// ClipTransform에 대한 정보를 가지고 있는 srv를 넘겨줌
		sTransformsSRV->SetResource(srv);
		sInputWorldSRV->SetResource(inputWorldBuffer->SRV());
		sInputBoneSRV->SetResource(inputBoneBuffer->SRV());
		sOutputUAV->SetUnorderedAccessView(outputBuffer->UAV());


		computeShader->Dispatch(0, 0, 1, MAX_MODEL_INSTANCE, 1);
		
		outputBuffer->CopyFromOutput();

		// 본 위치를 리턴할 것이다. 거기다가 충돌체를 붙일 것이다.
	}
	// 나눈 나머지
	frameTime = fmod(frameTime, (1.0f / frameRate));

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

void ModelAnimator::UpdateTransforms()
{
	for (UINT i = 0; i < transforms.size(); i++)
		memcpy(worlds[i], transforms[i]->World(), sizeof(Matrix));

	D3D11_MAPPED_SUBRESOURCE subResource;
	D3D::GetDC()->Map(instanceBuffer->Buffer(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
	{
		memcpy(subResource.pData, worlds, sizeof(Matrix) * MAX_MESH_INSTANCE);
	}
	D3D::GetDC()->Unmap(instanceBuffer->Buffer(), 0);


	// world를 Shader에넘겨준다.
	inputWorldBuffer->CopyToInput(worlds);
}

 

 

GetMultiBoneDemo.h


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

class GetMultiBoneDemo : 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 KachujinWeapon();

	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;
	Transform* colliderInitTransforms;
	ColliderObject** colliders;




	// 무기 추가
	ModelRender* weapon = NULL;
	// 무기 Transform
	Transform* weaponInitTransform;

	vector<MeshRender*> meshes;
	vector<ModelRender*> models;
	vector<ModelAnimator*> animators;
};

 

 

 

 

 

 

 

GetMultiBoneDemo.cpp


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

void GetMultiBoneDemo::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();
	KachujinWeapon();
}

void GetMultiBoneDemo::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 GetMultiBoneDemo::Update()
{
	//Weapon
	{
		Vector3 position;
		weaponInitTransform->Position(&position);
		ImGui::SliderFloat3("Weapon Position", position, -20, 20);

		Vector3 scale;
		weaponInitTransform->Scale(&scale);
		ImGui::SliderFloat3("Weapon Scale", scale, 0.1f, 3.0f);

		Vector3 rotation;
		weaponInitTransform->Rotation(&rotation);
		ImGui::SliderFloat3("Weapon Rotation", rotation, -1.0f, 1.0f);

		weaponInitTransform->Position(position);
		weaponInitTransform->Scale(scale);
		weaponInitTransform->Rotation(rotation);
	}

	//Collider
	{
		Vector3 position;
		colliderInitTransforms->Position(&position);
		ImGui::SliderFloat3("Collider Position", position, -20, 20);

		Vector3 scale;
		colliderInitTransforms->Scale(&scale);
		ImGui::SliderFloat3("Collider Scale", scale, 10.0f, 100.0f);

		Vector3 rotation;
		colliderInitTransforms->Rotation(&rotation);
		ImGui::SliderFloat3("Collider Rotation", rotation, -1.0f, 1.0f);

		colliderInitTransforms->Position(position);
		colliderInitTransforms->Scale(scale);
		colliderInitTransforms->Rotation(rotation);
	}


	sky->Update();

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

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

	// world를 한번에 얻어옴
	Matrix worlds[MAX_MODEL_TRANSFORMS];
	for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
	{
		// 카추진 위치 얻어옴(업데이트 시킬)
		/*Matrix attach;
		kachujin->GetAttachTransform(i, &attach);*/

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

		// 한 인스턴스에 대한 전체 본을 가져옴
		kachujin->GetAttachTransform(i, worlds);
		// worlds에는 한 인스턴스에 대한 전체 본의 위치가 들어가 있다.
		// 40번 본에 대한 충돌체를 설정하기 위해 위치를 세팅
		colliders[i]->Collider->GetTransform()->World(worlds[40]);
		colliders[i]->Collider->Update();

		// 기준 * 월드상 본의 위치
		weapon->GetTransform(i)->World(weaponInitTransform->World() * worlds[40]);
	}
	weapon->UpdateTransforms();
	weapon->Update();
}

void GetMultiBoneDemo::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();
	weapon->Render();

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

void GetMultiBoneDemo::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 GetMultiBoneDemo::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 GetMultiBoneDemo::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();

	animators.push_back(kachujin);
}

void GetMultiBoneDemo::KachujinCollider()
{
	// 인스턴싱 개수
	UINT count = kachujin->GetTransformCount();
	colliders = new ColliderObject*[count];

	// 기준이 될 Trnasform 만듬
	colliderInitTransforms = new Transform();
	colliderInitTransforms->Position(-2.9f, 1.45, -50.0f);
	colliderInitTransforms->Scale(5, 5, 75);

	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);
		colliders[i]->Collider = new Collider(colliders[i]->Transform, colliderInitTransforms);
	}

}

void GetMultiBoneDemo::KachujinWeapon()
{
	weapon = new ModelRender(shader);
	weapon->ReadMesh(L"Weapon/Sword");
	weapon->ReadMaterial(L"Weapon/Sword");

	UINT count = kachujin->GetTransformCount();
	for (UINT i = 0; i < count; i++)
		weapon->AddTransform();

	weapon->UpdateTransforms();
	models.push_back(weapon);


	// weapon에 대한 기준 transform
	weaponInitTransform = new Transform();
	weaponInitTransform->Position(-2.9f, 1.45f, -6.45f);
	weaponInitTransform->Scale(0.5f, 0.5f, 0.75f);
	weaponInitTransform->Rotation(0, 0, 1);
}

void GetMultiBoneDemo::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);
}

 

 

 

 

 

 

 

 

 

71_GetMultiBones.fx


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

struct WorldDesc
{
    matrix Transform;
};

// 인스턴스의 월드 행렬 배열
StructuredBuffer<WorldDesc> InputWorlds;

struct BoneDesc
{
    matrix Transform;
};

// 기준 본 행렬 배열
StructuredBuffer<BoneDesc> InputBones;

// output이니까 RW
// 1장만넘기니까 2DArray사용안해도됨
RWTexture2DArray<float4> Output;


// 정점 변환이 아닌 정점 변환하기 위한 공간을 구함
void SetTweenBones(inout matrix world, uint3 id)
{
    // 0번이 현재 동작 1번이 다음동작(Tweening 때문에)
    // 이후 작업 편하게 하려고 변수 선언
    int clip[2];
    int currFrame[2];
    int nextFrame[2];
    float time[2];
    
    clip[0] = TweenFrames[id.y].Curr.Clip;
    currFrame[0] = TweenFrames[id.y].Curr.CurrFrame;
    nextFrame[0] = TweenFrames[id.y].Curr.NextFrame;
    time[0] = TweenFrames[id.y].Curr.Time;
    
    clip[1] = TweenFrames[id.y].Next.Clip;
    currFrame[1] = TweenFrames[id.y].Next.CurrFrame;
    nextFrame[1] = TweenFrames[id.y].Next.NextFrame;
    time[1] = TweenFrames[id.y].Next.Time;

    float4 c0, c1, c2, c3;
    float4 n0, n1, n2, n3;
    
    
    matrix curr = 0, next = 0;
    matrix currAnim = 0;
    matrix nextAnim = 0;
    
    
    
    // 반복문했던이유는 가중치 때문이다. 그런데 이제 필요없다.(공간을 계산하는거지, 정점을 계산하는게 아니기 때문)
    // bone은 id.x에 매핑되어있다.
    c0 = TransformsMap.Load(int4(id.x * 4 + 0, currFrame[0], clip[0], 0)); // 1행
    c1 = TransformsMap.Load(int4(id.x * 4 + 1, currFrame[0], clip[0], 0)); // 2행
    c2 = TransformsMap.Load(int4(id.x * 4 + 2, currFrame[0], clip[0], 0)); // 3행
    c3 = TransformsMap.Load(int4(id.x * 4 + 3, currFrame[0], clip[0], 0)); // 4행
    curr = matrix(c0, c1, c2, c3);
    
    n0 = TransformsMap.Load(int4(id.x * 4 + 0, nextFrame[0], clip[0], 0)); // 1행
    n1 = TransformsMap.Load(int4(id.x * 4 + 1, nextFrame[0], clip[0], 0)); // 2행
    n2 = TransformsMap.Load(int4(id.x * 4 + 2, nextFrame[0], clip[0], 0)); // 3행
    n3 = TransformsMap.Load(int4(id.x * 4 + 3, nextFrame[0], clip[0], 0)); // 4행
    next = matrix(n0, n1, n2, n3);
    
    currAnim = lerp(curr, next, time[0]);
    
    
    [flatten]
    if (clip[1] > -1)
    {
        c0 = TransformsMap.Load(int4(id.x * 4 + 0, currFrame[1], clip[1], 0)); // 1행
        c1 = TransformsMap.Load(int4(id.x * 4 + 1, currFrame[1], clip[1], 0)); // 2행
        c2 = TransformsMap.Load(int4(id.x * 4 + 2, currFrame[1], clip[1], 0)); // 3행
        c3 = TransformsMap.Load(int4(id.x * 4 + 3, currFrame[1], clip[1], 0)); // 4행
        curr = matrix(c0, c1, c2, c3);
    
        n0 = TransformsMap.Load(int4(id.x * 4 + 0, nextFrame[1], clip[1], 0)); // 1행
        n1 = TransformsMap.Load(int4(id.x * 4 + 1, nextFrame[1], clip[1], 0)); // 2행
        n2 = TransformsMap.Load(int4(id.x * 4 + 2, nextFrame[1], clip[1], 0)); // 3행
        n3 = TransformsMap.Load(int4(id.x * 4 + 3, nextFrame[1], clip[1], 0)); // 4행
        next = matrix(n0, n1, n2, n3);
        
        nextAnim = lerp(curr, next, time[1]);
        
        currAnim = lerp(currAnim, nextAnim, TweenFrames[id.y].TweenTime);
    }
    
    // 애니메이션 행렬 -> currAnim
    // world에 Transform을 받아올꺼니까 world랑 해줌
    // (애니메이션 행렬 * 월드 행렬)
    world = mul(currAnim, world);
}


void SetBlendBones(inout matrix world, uint3 id)
{
    float4 c0, c1, c2, c3;
    float4 n0, n1, n2, n3;
    
    
    matrix curr = 0, next = 0;
    matrix currAnim[3];
    matrix anim = 0;
    
    // id.y에 인스턴스 매핑됨
    BlendFrame frame = BlendFrames[id.y];
    
    
    [unroll(3)]
    for (int k = 0; k < 3; k++)
    {
        c0 = TransformsMap.Load(int4(id.x * 4 + 0, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0)); // 1행
        c1 = TransformsMap.Load(int4(id.x * 4 + 1, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0)); // 2행
        c2 = TransformsMap.Load(int4(id.x * 4 + 2, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0)); // 3행
        c3 = TransformsMap.Load(int4(id.x * 4 + 3, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0)); // 4행
        curr = matrix(c0, c1, c2, c3);
    
        n0 = TransformsMap.Load(int4(id.x * 4 + 0, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0)); // 1행
        n1 = TransformsMap.Load(int4(id.x * 4 + 1, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0)); // 2행
        n2 = TransformsMap.Load(int4(id.x * 4 + 2, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0)); // 3행
        n3 = TransformsMap.Load(int4(id.x * 4 + 3, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0)); // 4행
        next = matrix(n0, n1, n2, n3);
    
        currAnim[k] = lerp(curr, next, frame.Clip[k].Time);
    }
    
    // 0, 1, 2 구간이 떨어짐
    int clipA = (int) frame.Alpha;
    int clipB = clipA + 1;
    
    float alpha = frame.Alpha;
    
    if (alpha >= 1.0f)
    {
        // 1 ~ 2구간을 가야하니까 -1을 시킴
        // lerp를 하기 위해 0 ~ 1구간을 만들어야 해서 -1을 함
        alpha = frame.Alpha - 1.0f;
        
        // 2를 넘었다면 플레이 구간이 1 ~ 2이다.
        if (frame.Alpha >= 2.0f)
        {
            clipA = 1;
            clipB = 2;
        }
    }
   
    anim = lerp(currAnim[clipA], currAnim[clipB], alpha);
    
    // world랑 곱해줌(world는 Transform이 들어온다.)
    // (애니메이션 행렬 * 월드 행렬)
    world = mul(anim, world);
}


// SV_DispatchThreadID : X,Y 축으로 그룹을 넘어서도 계속 이어져 계산되는 번호
[numthreads(MAX_MODEL_TRANSFORMS, 1, 1)]
void CS(uint3 id : SV_DispatchThreadID)
{
    // 기준 본 * 애니메이션 * 월드
    
    // id.y가 인스턴스 아이디랑 정확히 맞아 떨어짐
    // 월드 행렬
    matrix world = InputWorlds[id.y].Transform;
    
    if (BlendFrames[id.y].Mode == 0)
        SetTweenBones(world, id);
    else
        SetBlendBones(world, id);
    
    // bone은 id.x에 매핑되어있다.
    // 기준 본 * (애니메이션 * 월드)
    world = mul(InputBones[id.x].Transform, world);
    
    // 한픽셀에 RGBA 합쳐서 4개를 사용하도록 세팅했었다.(ModelAnimator에서)
    // 텍스쳐의 한 픽셀은 하나의 행이므로 각 행을 쪼개서 리턴한다.
    // 애니메이션 할때랑 동일
    float4 m0 = world._11_12_13_14;
    float4 m1 = world._21_22_23_24;
    float4 m2 = world._31_32_33_34;
    float4 m3 = world._41_42_43_44;
    
    // 한픽셀당 한 행을 넣음, 4픽셀이 하나의 matrix를 갖도록
    Output[int3(id.x * 4 + 0, id.y, id.z)] = m0;
    Output[int3(id.x * 4 + 1, id.y, id.z)] = m1;
    Output[int3(id.x * 4 + 2, id.y, id.z)] = m2;
    Output[int3(id.x * 4 + 3, id.y, id.z)] = m3;
}


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

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

 

 

 

 

 

 

 

 

 

 

 

결과