필요한 개념
본을 전체적으로 한번에 계산해서 리턴받아오는 작업함
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()));
}
}
결과
'DirectX11 3D > 기본 문법' 카테고리의 다른 글
<DirectX11 3D> 75 - Lighting(Ambient, Diffuse, Specular, Emissive) (0) | 2022.03.09 |
---|---|
<DirectX11 3D> 74 - Instancing (0) | 2022.03.09 |
<DirectX11 3D> 70 - Obb Collision(OBB와 OBB 충돌) (0) | 2022.03.02 |
<DirectX11 3D> 69 - OBB Raycast(OBB와 반직선 교차) (0) | 2022.03.02 |
<DirectX11 3D> 68 - Unprojection (0) | 2022.03.02 |