[DirectX11] 071~73 Get MultiBones
DirectX 11에서 Multibones는 스켈레탈 애니메이션을 구현하는 데 사용되는 기술이다. 스켈레탈 애니메이션은 3D 모델의 뼈대와 관련된 것으로, 모델이 움직이는 동안 뼈대가 움직이며 모델을 변형시킨다. Multibones는 여러 개의 뼈대를 사용하여 더욱 자연스러운 애니메이션을 만들어낸다. 이를 통해 모델의 각 부분에 대해 다양한 뼈대를 지정할 수 있으며, 더 복잡한 동작을 만들어낼 수 있다.
목차
Get Multibones
DirectX 11에서 Multibones는 스켈레탈 애니메이션을 구현하는 데 사용되는 기술이다. 스켈레탈 애니메이션은 3D 모델의 뼈대와 관련된 것으로, 모델이 움직이는 동안 뼈대가 움직이며 모델을 변형시킨다.
Multibones는 여러 개의 뼈대를 사용하여 더욱 자연스러운 애니메이션을 만들어낸다. 이를 통해 모델의 각 부분에 대해 다양한 뼈대를 지정할 수 있으며, 더 복잡한 동작을 만들어낼 수 있다.
Multibones를 구현하려면 각 뼈대의 정보를 정의하는 뼈대 행렬들을 생성해야 한다. 이 행렬들은 모델의 뼈대들 사이의 계층 구조와 연관되어 있다. 이러한 뼈대 행렬들은 GPU에서 계산되며, 각 프레임마다 각 뼈대의 위치와 회전을 계산하여 모델의 애니메이션을 만든다.
Multibones를 사용하여 더욱 자연스러운 애니메이션을 만들 수 있지만, 이를 구현하기 위해서는 더 많은 계산이 필요하며, 따라서 프로세서와 그래픽 카드의 성능이 더욱 중요해진다.
Shader | |
GetMultiBones.fx | |
Framework | |
Model | |
ModelAnimator.h .cpp | |
Renders | |
Buffers.h .cpp | |
UnitTest | |
DirectCompute | |
GetMultiBoneDemo |
GetMultiBones.fx
GetMultiBones.fx
#include "00_Global.fx"
#include "00_Light.fx"
#include "00_Render.fx"
struct WorldDesc
{
matrix Transform;
};
StructuredBuffer<WorldDesc> InputWorlds;//inputWorldBuffer //Model Animator에 있는 Compute Shader
struct BoneDesc
{
matrix Transform;
};
StructuredBuffer<BoneDesc> InputBones;//inputBoneBuffer
// 한장인데 그냥 2DArray사용
RWTexture2DArray<float4> Output;
void SetTweenBones(inout matrix world, uint3 id)
{
// 공간을 계산할꺼라 가중치가 필요없음
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;
// 본은 x에 매핑
c0 = TransformsMap.Load(int4(id.x * 4 + 0, currFrame[0], clip[0], 0));
c1 = TransformsMap.Load(int4(id.x * 4 + 1, currFrame[0], clip[0], 0));
c2 = TransformsMap.Load(int4(id.x * 4 + 2, currFrame[0], clip[0], 0));
c3 = TransformsMap.Load(int4(id.x * 4 + 3, currFrame[0], clip[0], 0));
curr = matrix(c0, c1, c2, c3);
n0 = TransformsMap.Load(int4(id.x * 4 + 0, nextFrame[0], clip[0], 0));
n1 = TransformsMap.Load(int4(id.x * 4 + 1, nextFrame[0], clip[0], 0));
n2 = TransformsMap.Load(int4(id.x * 4 + 2, nextFrame[0], clip[0], 0));
n3 = TransformsMap.Load(int4(id.x * 4 + 3, nextFrame[0], clip[0], 0));
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));
c1 = TransformsMap.Load(int4(id.x * 4 + 1, currFrame[1], clip[1], 0));
c2 = TransformsMap.Load(int4(id.x * 4 + 2, currFrame[1], clip[1], 0));
c3 = TransformsMap.Load(int4(id.x * 4 + 3, currFrame[1], clip[1], 0));
curr = matrix(c0, c1, c2, c3);
n0 = TransformsMap.Load(int4(id.x * 4 + 0, nextFrame[1], clip[1], 0));
n1 = TransformsMap.Load(int4(id.x * 4 + 1, nextFrame[1], clip[1], 0));
n2 = TransformsMap.Load(int4(id.x * 4 + 2, nextFrame[1], clip[1], 0));
n3 = TransformsMap.Load(int4(id.x * 4 + 3, nextFrame[1], clip[1], 0));
next = matrix(n0, n1, n2, n3);
nextAnim = lerp(curr, next, time[1]);
currAnim = lerp(currAnim, nextAnim, TweenFrames[id.y].TweenTime);
}
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;
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));
c1 = TransformsMap.Load(int4(id.x * 4 + 1, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
c2 = TransformsMap.Load(int4(id.x * 4 + 2, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
c3 = TransformsMap.Load(int4(id.x * 4 + 3, frame.Clip[k].CurrFrame, frame.Clip[k].Clip, 0));
curr = matrix(c0, c1, c2, c3);
n0 = TransformsMap.Load(int4(id.x * 4 + 0, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
n1 = TransformsMap.Load(int4(id.x * 4 + 1, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
n2 = TransformsMap.Load(int4(id.x * 4 + 2, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
n3 = TransformsMap.Load(int4(id.x * 4 + 3, frame.Clip[k].NextFrame, frame.Clip[k].Clip, 0));
next = matrix(n0, n1, n2, n3);
currAnim[k] = lerp(curr, next, frame.Clip[k].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;
}
}
anim = lerp(currAnim[clipA], currAnim[clipB], alpha);
world = mul(anim, world);
}
[numthreads(MAX_MODEL_TRANSFORMS, 1, 1)]
void CS(uint3 id : SV_DispatchThreadID)
{
//기준본 * 애니메이션 * 월드
// SV_DispatchThreadID을 사용하면 그룹에 상관없이 번호가 이어짐 1대1로
// y가 트랜스폼 ID와 일치함
matrix world = InputWorlds[id.y].Transform;
if (BlendFrames[id.y].Mode == 0)
SetTweenBones(world, id);
else
SetBlendBones(world, id);
world = mul(InputBones[id.x].Transform, world);
// desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
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;
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()));
}
}
Dispatcher Thread ID를 사용하면 그룹에 상관없이 ID와 Texture를 펼친것(=Instance Id)이 1:1로 대응하게 된다.
Model Animator
ModelAnimator.h
#pragma once
class ModelAnimator
{
public:
ModelAnimator(Shader* shader);
~ModelAnimator();
void Update();
private:
void UpdateTweenMode(UINT index);
void UpdateBlendMode(UINT index);
public:
void Render();
public:
void ReadMesh(wstring file);
void ReadMaterial(wstring file);
void ReadClip(wstring file);
Model* GetModel() { return model; }
void Pass(UINT pass);
Transform* AddTransform();
Transform* GetTransform(UINT index) { return transforms[index]; }
void UpdateTransforms();
UINT GetTransformCount() { return transforms.size(); }
void PlayTweenMode(UINT index, UINT clip, float speed = 1.0f, float takeTime = 1.0f);
void PlayBlendMode(UINT index, UINT clip, UINT clip1, UINT clip2);
void SetBlendAlpha(UINT index, float alpha);
void GetAttachTransform(UINT instance, Matrix* outResult);
private:
void CreateTexture();
void CreateClipTransform(UINT index);
private:
struct ClipTransform
{
Matrix** Transform;
ClipTransform()
{
Transform = new Matrix*[MAX_MODEL_KEYFRAMES];
for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
Transform[i] = new Matrix[MAX_MODEL_TRANSFORMS];
}
~ClipTransform()
{
for (UINT i = 0; i < MAX_MODEL_KEYFRAMES; i++)
SafeDeleteArray(Transform[i]);
SafeDeleteArray(Transform);
}
};
ClipTransform* clipTransforms = NULL;
ID3D11Texture2D* texture = NULL;
ID3D11ShaderResourceView* srv = NULL;
private:
struct KeyframeDesc
{
int Clip = 0;
UINT CurrFrame = 0;
UINT NextFrame = 0;
float Time = 0.0f;
float RunningTime = 0.0f;
float Speed = 1.0f;
Vector2 Padding;
}; // keyframeDesc;
struct TweenDesc
{
float TakeTime = 1.0f;
float TweenTime = 0.0f;
float ChangeTime = 0.0f;
float Padding;
KeyframeDesc Curr;
KeyframeDesc Next;
TweenDesc()
{
Curr.Clip = 0;
Next.Clip = -1;
}
} tweenDesc[MAX_MODEL_INSTANCE];
ConstantBuffer* tweenBuffer;
ID3DX11EffectConstantBuffer* sTweenBuffer;
private:
struct BlendDesc
{
UINT Mode = 0;
float Alpha = 0;
Vector2 Padding;
KeyframeDesc Clip[3];
} blendDesc[MAX_MODEL_INSTANCE];
ConstantBuffer* blendBuffer;
ID3DX11EffectConstantBuffer* sBlendBuffer;
private:
Shader* shader;
Model* model;
vector<Transform *> transforms;
Matrix worlds[MAX_MODEL_INSTANCE];
VertexBuffer* instanceBuffer;
private:
struct CS_InputDesc
{
Matrix Bone;
};
struct CS_OutputDesc
{
Matrix Result;
};
private:
const float frameRate = 30.0f; //매 프레임 마다 계산하면 계산양이 많아서 30프레임으로 설정.
float frameTime = 0.0f;
Shader* computeShader;
ID3DX11EffectShaderResourceVariable* sTransformsSRV;
StructuredBuffer* inputWorldBuffer;
ID3DX11EffectShaderResourceVariable* sInputWorldSRV; //입력용 버퍼
StructuredBuffer* inputBoneBuffer;
ID3DX11EffectShaderResourceVariable* sInputBoneSRV; //입력용 버퍼
TextureBuffer* outputBuffer;
ID3DX11EffectUnorderedAccessViewVariable* sOutputUAV;//출력용 버퍼
ID3DX11EffectConstantBuffer* sComputeTweenBuffer; //Tween 정보
ID3DX11EffectConstantBuffer* sComputeBlendBuffer; //Blend 정보
};
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);
//Create Compute Shader
{
computeShader = new Shader(L"71_GetMultiBones.fx");
inputWorldBuffer = new StructuredBuffer(worlds, sizeof(Matrix), MAX_MODEL_INSTANCE);
sInputWorldSRV = computeShader->AsSRV("InputWorlds");
inputBoneBuffer = new StructuredBuffer(NULL, sizeof(Matrix), MAX_MODEL_TRANSFORMS);
sInputBoneSRV = computeShader->AsSRV("InputBones");
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;
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");
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()
{
if (texture == NULL)
{
for (ModelMesh* mesh : model->Meshes())
mesh->SetShader(shader);
CreateTexture();
Matrix bones[MAX_MODEL_TRANSFORMS];
for (UINT i = 0; i < model->BoneCount(); i++)
bones[i] = model->BoneByIndex(i)->Transform(); //최초의 기준Bone에서 현재 애니메이션의 행렬을 계산
inputBoneBuffer->CopyToInput(bones);//계산해서 넣어줌
}
for (UINT i = 0; i < transforms.size(); i++)
blendDesc[i].Mode == 0 ? UpdateTweenMode(i) : UpdateBlendMode(i);
tweenBuffer->Render();
blendBuffer->Render();
frameTime += Time::Delta();
if (frameTime > (1.0f / frameRate))
{
sComputeTweenBuffer->SetConstantBuffer(tweenBuffer->Buffer());
sComputeBlendBuffer->SetConstantBuffer(blendBuffer->Buffer());
sTransformsSRV->SetResource(srv); //srv는 ClipTransform의 정보를 가지고 있다.
sInputWorldSRV->SetResource(inputWorldBuffer->SRV());
sInputBoneSRV->SetResource(inputBoneBuffer->SRV());
sOutputUAV->SetUnorderedAccessView(outputBuffer->UAV());
computeShader->Dispatch(0, 0, 1, MAX_MODEL_INSTANCE, 1);//y를 instance로 사용
outputBuffer->CopyFromOutput();
}
frameTime = fmod(frameTime, (1.0f / frameRate));
if (Keyboard::Get()->Down(VK_SPACE))
{
ID3D11Texture2D* temp = outputBuffer->CopyFromOutput();
FILE* src;
fopen_s(&src, "../src.csv", "w");
Matrix id[MAX_MODEL_TRANSFORMS];
for (UINT y = 0; y < MAX_MODEL_INSTANCE; y++)
{
D3D11_MAPPED_SUBRESOURCE subResource;
D3D::GetDC()->Map(temp, 0, D3D11_MAP_READ, 0, &subResource);
{
void* p = (BYTE *)subResource.pData + y * subResource.RowPitch;
memcpy(id, p, MAX_MODEL_TRANSFORMS * sizeof(Matrix));
}
D3D::GetDC()->Unmap(temp, 0);
for (UINT x = 0; x < MAX_MODEL_TRANSFORMS; x++)
{
Matrix destMatrix = id[x];
fprintf(src, "%f,%f,%f,%f,", destMatrix._11, destMatrix._12, destMatrix._13, destMatrix._14);
fprintf(src, "%f,%f,%f,%f,", destMatrix._21, destMatrix._22, destMatrix._23, destMatrix._24);
fprintf(src, "%f,%f,%f,%f,", destMatrix._31, destMatrix._32, destMatrix._33, destMatrix._34);
fprintf(src, "%f,%f,%f,%f\n", destMatrix._41, destMatrix._42, destMatrix._43, destMatrix._44);
}
}
fclose(src);
}
for (ModelMesh* mesh : model->Meshes())
mesh->Update();
}
void ModelAnimator::UpdateTweenMode(UINT index)
{
TweenDesc& desc = tweenDesc[index];
//현재 애니메이션
{
ModelClip* clip = model->ClipByIndex(desc.Curr.Clip);
desc.Curr.RunningTime += Time::Delta();
float time = 1.0f / clip->FrameRate() / desc.Curr.Speed;
if (desc.Curr.Time >= 1.0f)
{
desc.Curr.RunningTime = 0;
desc.Curr.CurrFrame = (desc.Curr.CurrFrame + 1) % clip->FrameCount();
desc.Curr.NextFrame = (desc.Curr.CurrFrame + 1) % clip->FrameCount();
}
desc.Curr.Time = desc.Curr.RunningTime / time;
}
if (desc.Next.Clip > -1)
{
desc.ChangeTime += Time::Delta();
desc.TweenTime = desc.ChangeTime / desc.TakeTime;
if (desc.TweenTime >= 1.0f)
{
desc.Curr = desc.Next;
desc.Next.Clip = -1;
desc.Next.CurrFrame = 0;
desc.Next.NextFrame = 0;
desc.Next.Time = 0;
desc.Next.RunningTime = 0.0f;
desc.ChangeTime = 0.0f;
desc.TweenTime = 0.0f;
}
else
{
ModelClip* clip = model->ClipByIndex(desc.Next.Clip);
desc.Next.RunningTime += Time::Delta();
float time = 1.0f / clip->FrameRate() / desc.Next.Speed;
if (desc.Next.Time >= 1.0f)
{
desc.Next.RunningTime = 0;
desc.Next.CurrFrame = (desc.Next.CurrFrame + 1) % clip->FrameCount();
desc.Next.NextFrame = (desc.Next.CurrFrame + 1) % clip->FrameCount();
}
desc.Next.Time = desc.Next.RunningTime / time;
}
}
}
void ModelAnimator::UpdateBlendMode(UINT index)
{
BlendDesc& desc = blendDesc[index];
for (UINT i = 0; i < 3; i++)
{
ModelClip* clip = model->ClipByIndex(desc.Clip[i].Clip);
desc.Clip[i].RunningTime += Time::Delta();
float time = 1.0f / clip->FrameRate() / desc.Clip[i].Speed;
if (desc.Clip[i].Time >= 1.0f)
{
desc.Clip[i].RunningTime = 0;
desc.Clip[i].CurrFrame = (desc.Clip[i].CurrFrame + 1) % clip->FrameCount();
desc.Clip[i].NextFrame = (desc.Clip[i].CurrFrame + 1) % clip->FrameCount();
}
desc.Clip[i].Time = desc.Clip[i].RunningTime / time;
}
}
void ModelAnimator::Render()
{
sTweenBuffer->SetConstantBuffer(tweenBuffer->Buffer());
sBlendBuffer->SetConstantBuffer(blendBuffer->Buffer());
instanceBuffer->Render();
for (ModelMesh* mesh : model->Meshes())
mesh->Render(transforms.size());
}
void ModelAnimator::ReadMesh(wstring file)
{
model->ReadMesh(file);
}
void ModelAnimator::ReadMaterial(wstring file)
{
model->ReadMaterial(file);
}
void ModelAnimator::ReadClip(wstring file)
{
model->ReadClip(file);
}
void ModelAnimator::Pass(UINT pass)
{
for (ModelMesh* mesh : model->Meshes())
mesh->Pass(pass);
}
void ModelAnimator::PlayTweenMode(UINT index, UINT clip, float speed, float takeTime)
{
blendDesc[index].Mode = 0;
tweenDesc[index].TakeTime = takeTime;
tweenDesc[index].Next.Clip = clip;
tweenDesc[index].Next.Speed = speed;
}
void ModelAnimator::PlayBlendMode(UINT index, UINT clip, UINT clip1, UINT clip2)
{
blendDesc[index].Mode = 1;
blendDesc[index].Clip[0].Clip = clip;
blendDesc[index].Clip[1].Clip = clip1;
blendDesc[index].Clip[2].Clip = clip2;
}
void ModelAnimator::SetBlendAlpha(UINT index, float alpha)
{
alpha = Math::Clamp(alpha, 0.0f, 2.0f);
blendDesc[index].Alpha = alpha;
}
void ModelAnimator::GetAttachTransform(UINT instance, Matrix * outResult)
{
ID3D11Texture2D* texture = outputBuffer->Result();
D3D11_MAPPED_SUBRESOURCE subResource;
D3D::GetDC()->Map(texture, 0, D3D11_MAP_READ, 0, &subResource);
{
//instance 크기 만큼 이동한 후에 한줄의 크기(sizeof(Matrix)*MAX_MODEL_TRANSFORMS) 만큼 가져온다.
memcpy(outResult, (BYTE *)subResource.pData + (instance * subResource.RowPitch), sizeof(Matrix) * MAX_MODEL_TRANSFORMS);
}
D3D::GetDC()->Unmap(texture, 0);
}
void ModelAnimator::CreateTexture()
{
//Matrix matrix[MAX_MODEL_KEYFRAMES][MAX_MODEL_TRANSFORMS];
clipTransforms = new ClipTransform[model->ClipCount()];
for (UINT i = 0; i < model->ClipCount(); i++)
CreateClipTransform(i);
//Create Texture
{
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.Width = MAX_MODEL_TRANSFORMS * 4;
desc.Height = MAX_MODEL_KEYFRAMES;
desc.ArraySize = model->ClipCount();
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; //16Byte * 4 = 64Byte
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
UINT pageSize = MAX_MODEL_TRANSFORMS * 4 * 16 * MAX_MODEL_KEYFRAMES;
//void* p = malloc(pageSize * model->ClipCount());
void* p = VirtualAlloc(NULL, pageSize * model->ClipCount(), MEM_RESERVE, PAGE_READWRITE);
//MEMORY_BASIC_INFORMATION, VirtualQuery
for (UINT c = 0; c < model->ClipCount(); c++)
{
UINT start = c * pageSize;
for (UINT k = 0; k < MAX_MODEL_KEYFRAMES; k++)
{
void* temp = (BYTE *)p + MAX_MODEL_TRANSFORMS * k * sizeof(Matrix) + start;
VirtualAlloc(temp, MAX_MODEL_TRANSFORMS * sizeof(Matrix), MEM_COMMIT, PAGE_READWRITE);
memcpy(temp, clipTransforms[c].Transform[k], MAX_MODEL_TRANSFORMS * sizeof(Matrix));
}
}//for(c)
D3D11_SUBRESOURCE_DATA* subResources = new D3D11_SUBRESOURCE_DATA[model->ClipCount()];
for (UINT c = 0; c < model->ClipCount(); c++)
{
void* temp = (BYTE *)p + c * pageSize;
subResources[c].pSysMem = temp;
subResources[c].SysMemPitch = MAX_MODEL_TRANSFORMS * sizeof(Matrix);
subResources[c].SysMemSlicePitch = pageSize;
}
Check(D3D::GetDevice()->CreateTexture2D(&desc, subResources, &texture));
SafeDeleteArray(subResources);
VirtualFree(p, 0, MEM_RELEASE);
}
//Create SRV
{
D3D11_SHADER_RESOURCE_VIEW_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MipLevels = 1;
desc.Texture2DArray.ArraySize = model->ClipCount();
Check(D3D::GetDevice()->CreateShaderResourceView(texture, &desc, &srv));
}
for (ModelMesh* mesh : model->Meshes())
mesh->TransformsSRV(srv);
}
void ModelAnimator::CreateClipTransform(UINT index)
{
Matrix* bones = new Matrix[MAX_MODEL_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)
}
Transform * ModelAnimator::AddTransform()
{
Transform* transform = new Transform();
transforms.push_back(transform);
return transform;
}
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);
inputWorldBuffer->CopyToInput(worlds);
}
Buffers
Buffers.h
#pragma once
class VertexBuffer
{
public:
VertexBuffer(void* data, UINT count, UINT stride, UINT slot = 0, bool bCpuWrite = false, bool bGpuWrite = false);
~VertexBuffer();
UINT Count() { return count; }
UINT Stride() { return stride; }
ID3D11Buffer* Buffer() { return buffer; }
void Render();
private:
ID3D11Buffer* buffer;
void* data;
UINT count;
UINT stride;
UINT slot;
bool bCpuWrite;
bool bGpuWrite;
};
class IndexBuffer
{
public:
IndexBuffer(void* data, UINT count);
~IndexBuffer();
UINT Count() { return count; }
ID3D11Buffer* Buffer() { return buffer; }
void Render();
private:
ID3D11Buffer* buffer;
void* data;
UINT count;
};
class ConstantBuffer
{
public:
ConstantBuffer(void* data, UINT dataSize);
~ConstantBuffer();
ID3D11Buffer* Buffer() { return buffer; }
void Render();
private:
ID3D11Buffer* buffer;
void* data;
UINT dataSize;
};
class CsResource
{
public:
CsResource();
virtual ~CsResource();
protected:
virtual void CreateInput() {}
virtual void CreateSRV() {}
virtual void CreateOutput() {}
virtual void CreateUAV() {}
virtual void CreateResult() {}
void CreateBuffer();
public:
ID3D11ShaderResourceView* SRV() { return srv; }
ID3D11UnorderedAccessView* UAV() { return uav; }
protected:
ID3D11Resource* input = NULL;
ID3D11ShaderResourceView* srv = NULL; //Input
ID3D11Resource* output = NULL;
ID3D11UnorderedAccessView* uav = NULL; //Output
ID3D11Resource* result = NULL;
};
class RawBuffer : public CsResource
{
public:
RawBuffer(void* inputData, UINT inputByte, UINT outputByte);
~RawBuffer();
private:
void CreateInput() override;
void CreateSRV() override;
void CreateOutput() override;
void CreateUAV() override;
void CreateResult() override;
public:
void CopyToInput(void* data);
void CopyFromOuput(void* data);
private:
void* inputData;
UINT inputByte;
UINT outputByte;
};
class StructuredBuffer : public CsResource
{
public:
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;
};
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
#include "Framework.h"
#include "Buffers.h"
VertexBuffer::VertexBuffer(void * data, UINT count, UINT stride, UINT slot, bool bCpuWrite, bool bGpuWrite)
: data(data), count(count), stride(stride), slot(slot)
, bCpuWrite(bCpuWrite), bGpuWrite(bGpuWrite)
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = stride * count;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
if (bCpuWrite == false && bGpuWrite == false)
{
desc.Usage = D3D11_USAGE_IMMUTABLE; //GPU 읽기
}
else if (bCpuWrite == true && bGpuWrite == false)
{
desc.Usage = D3D11_USAGE_DYNAMIC; //CPU 쓰기, GPU 읽기
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
}
else if (bCpuWrite == false && bGpuWrite == true)
{
//CPU 쓰기 가능 - UpdateSubResource
desc.Usage = D3D11_USAGE_DEFAULT;
}
else
{
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
}
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = data;
Check(D3D::GetDevice()->CreateBuffer(&desc, &subResource, &buffer));
}
VertexBuffer::~VertexBuffer()
{
SafeRelease(buffer);
}
void VertexBuffer::Render()
{
UINT offset = 0;
D3D::GetDC()->IASetVertexBuffers(slot, 1, &buffer, &stride, &offset);
}
IndexBuffer::IndexBuffer(void * data, UINT count)
: data(data), count(count)
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = sizeof(UINT) * count;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.Usage = D3D11_USAGE_IMMUTABLE;
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = data;
Check(D3D::GetDevice()->CreateBuffer(&desc, &subResource, &buffer));
}
IndexBuffer::~IndexBuffer()
{
SafeRelease(buffer);
}
void IndexBuffer::Render()
{
D3D::GetDC()->IASetIndexBuffer(buffer, DXGI_FORMAT_R32_UINT, 0);
}
///////////////////////////////////////////////////////////////////////////////
ConstantBuffer::ConstantBuffer(void * data, UINT dataSize)
: data(data), dataSize(dataSize)
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = dataSize;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
}
ConstantBuffer::~ConstantBuffer()
{
SafeRelease(buffer);
}
void ConstantBuffer::Render()
{
D3D11_MAPPED_SUBRESOURCE subResource;
D3D::GetDC()->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
{
memcpy(subResource.pData, data, dataSize);
}
D3D::GetDC()->Unmap(buffer, 0);
}
CsResource::CsResource()
{
}
CsResource::~CsResource()
{
SafeRelease(input);
SafeRelease(srv);
SafeRelease(output);
SafeRelease(uav);
SafeRelease(result);
}
void CsResource::CreateBuffer()
{
CreateInput();
CreateSRV();
CreateOutput();
CreateUAV();
CreateResult();
}
RawBuffer::RawBuffer(void * inputData, UINT inputByte, UINT outputByte)
: CsResource()
, inputData(inputData), inputByte(inputByte), outputByte(outputByte)
{
CreateBuffer();
}
RawBuffer::~RawBuffer()
{
}
void RawBuffer::CreateInput()
{
if (inputByte < 1) return;
ID3D11Buffer* buffer = NULL;
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = inputByte;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
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 RawBuffer::CreateSRV()
{
if (inputByte < 1) return;
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_R32_TYPELESS;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
srvDesc.BufferEx.NumElements = desc.ByteWidth / 4;
Check(D3D::GetDevice()->CreateShaderResourceView(buffer, &srvDesc, &srv));
}
void RawBuffer::CreateOutput()
{
ID3D11Buffer* buffer = NULL;
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
desc.ByteWidth = outputByte;
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
output = (ID3D11Resource *)buffer;
}
void RawBuffer::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_R32_TYPELESS;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
uavDesc.Buffer.NumElements = desc.ByteWidth / 4;
Check(D3D::GetDevice()->CreateUnorderedAccessView(buffer, &uavDesc, &uav));
}
void RawBuffer::CreateResult()
{
ID3D11Buffer* buffer;
D3D11_BUFFER_DESC desc;
((ID3D11Buffer *)output)->GetDesc(&desc);
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = D3D11_USAGE_DEFAULT;
desc.MiscFlags = 0;
Check(D3D::GetDevice()->CreateBuffer(&desc, NULL, &buffer));
result = (ID3D11Resource *)buffer;
}
void RawBuffer::CopyToInput(void * data)
{
D3D11_MAPPED_SUBRESOURCE subResource;
D3D::GetDC()->Map(input, 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
{
memcpy(subResource.pData, data, inputByte);
}
D3D::GetDC()->Unmap(input, 0);
}
void RawBuffer::CopyFromOuput(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, outputByte);
}
D3D::GetDC()->Unmap(result, 0);
}
StructuredBuffer::StructuredBuffer(void* inputData, UINT inputStride, UINT inputCount, UINT outputStride, UINT outputCount)
: CsResource()
, inputData(inputData)
, inputStride(inputStride), inputCount(inputCount)
, outputStride(outputStride), outputCount(outputCount)
{
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;
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;
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);
}
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);
}
ID3D11Texture2D * TextureBuffer::CopyFromOutput()
{
D3D::GetDC()->CopyResource(result, output);
return (ID3D11Texture2D *)result;
}
GetMultiBoneDemo
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; //무기에 대한 Transform
ColliderObject** colliders;
ModelRender* weapon = NULL;
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::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();
Matrix worlds[MAX_MODEL_TRANSFORMS];
for (UINT i = 0; i < kachujin->GetTransformCount(); i++)
{
kachujin->GetAttachTransform(i, worlds);
colliders[i]->Collider->GetTransform()->World(worlds[40]);
colliders[i]->Collider->Update();
//만들어둔 기준(weaponInitTransform->World())에서 이동한 만큼(worlds[40]) 곱해준다.
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];
colliderInitTransforms = new Transform();
colliderInitTransforms->Position(-2.9f, 1.45f, -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);
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);
}
무기에 Collider를 붙여주었다.
실행화면
'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 075~77 Lighting, HLSL (0) | 2023.03.18 |
---|---|
[DirectX11] 074 Instancing (0) | 2023.03.18 |
[DirectX11] 070 OBB(Oriented Bounding Box) collision (3) | 2023.03.14 |
[DirectX11] 069 Collider (0) | 2023.03.13 |
[DirectX11] 068 Unprojection - 2D 좌표를 3D 좌표로 변환 (0) | 2023.03.13 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 075~77 Lighting, HLSL
[DirectX11] 075~77 Lighting, HLSL
2023.03.18 -
[DirectX11] 074 Instancing
[DirectX11] 074 Instancing
2023.03.18 -
[DirectX11] 070 OBB(Oriented Bounding Box) collision
[DirectX11] 070 OBB(Oriented Bounding Box) collision
2023.03.14 -
[DirectX11] 069 Collider
[DirectX11] 069 Collider
2023.03.13