[DirectX11] 063 Compute Shader - GetAnimationBone 구현하기
Compute Shader는 DirectX 11의 도구로 GPU 상에서 복잡한 연산을 수행할 수 있으며, 애니메이션의 경우 Compute Shader를 사용하여 Skeletal Animation System에서 Bone의 변환을 효율적으로 계산할 수 있어 CPU 오버헤드를 최소화하면서 실시간 애니메이션을 구현할 수 있다.
목차
Compute Shader - GetAnimationBone 구현하기
컴퓨팅 셰이더(Compute Shader)는 그래픽 렌더링에 주로 사용되는 정점 및 픽셀 셰이더와 같은 다른 유형의 셰이더와 달리, Compute Shader는 더 유연하고 다용도적으로 설계되어 있다.
Compute Shader에서는 GPU 상의 여러 스레드(multiple threads)에 걸쳐 복잡한 연산을 병렬로 수행하는 코드를 작성할 수 있으며, 이는 물리 시뮬레이션, 데이터 처리, 머신 러닝 알고리즘 등 다양한 작업에 유용할 수 있다.
DirectX 11의 애니메이션에 관해서는 Compute Shader를 사용하여 3D 모델의 이동과 관련된 계산을 수행할 수 있다. 구체적으로, Compute Shader는 skeletal animation system에서 뼈의 변환을 계산하는 데 사용될 수 있다.
Skeletal Animation System에서 3D 모델은 일련의 상호 연결된 뼈로 구성된다. 각 Bone에는 부모 Bone에 대한 위치, 방향 및 척도를 결정하는 고유한 변환 행렬이 있다. 모형에 있는 모든 골격의 변환 행렬을 결합하여 망사의 각 정점의 최종 위치를 계산할 수 있다.
이러한 계산을 효율적으로 수행하기 위해 컴퓨팅 셰이더를 사용하여 GPU 상의 여러 스레드(Multiple Threads)에 걸쳐 각 골격의 변환을 병렬로 계산할 수 있다. 이를 통해 CPU에 미치는 성능 영향을 최소화하면서 애니메이션을 실시간으로 수행할 수 있다.
Compute Shader는 DirectX 11의 강력한 도구로 GPU 상에서 복잡한 연산을 수행할 수 있으며, 애니메이션의 경우 Compute Shader를 사용하여 Skeletal Animation System에서 Bone의 변환을 효율적으로 계산할 수 있어 CPU 오버헤드를 최소화하면서 실시간 애니메이션을 구현할 수 있다.
Structure Buffer - 구조체 1차원 배열로 넘김.
Bone 번호를 주고 해당 Bone의 위치(SRT)를 Compute Shader를 통해서 구해준다.
충돌체(Bounding Box)를 삽입하여 추후에 마우스클릭이 가능하도록 만든다. 이 때 투영의 개념을 이해하여야 한다. 마우스 클릭은 OBB 개념을 활용하여 OBB Ray와 OBB rock을 사용한다.
Shader | |
RawBuffer.fx GetAnimationBone.fx 생성 |
|
Framework | |
Render | |
Buffer.h .cpp Render2D.h .cpp |
|
UnitTest | |
DirectCompute | |
RawBufferDemo.h .cpp | |
Main.h .cpp |
GetAnimationBone.fx
GetAnimationBone.fx
#include "00_Global.fx"
#include "00_Render.fx"
struct InputDesc
{
matrix Bone;
};
StructuredBuffer<InputDesc> Input; //입력받을 구조체가 들어옴
struct OutputDesc
{
matrix Result;
};
RWStructuredBuffer<OutputDesc> Output;
cbuffer CB_AttachBone
{
uint AttachBoneIndex; //어느 Bone 번호를 구할건지
};
matrix TweenMode(uint index)
{
uint boneIndex[2];
matrix result = 0;
//.Curr.Clip(=한 면) * MAX_MODEL_KEYFRAMES(=Y) * MAX_MODEL_TRANSFORMS(=X) //전체크기
boneIndex[0] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
//.Curr.CurrFrame(=Y) * MAX_MODEL_TRANSFORMS(=건너뛸 크기(Y프레임 개수))
boneIndex[0] += (TweenFrames[index].Curr.CurrFrame * MAX_MODEL_TRANSFORMS);
//AttachBoneIndex(=X방향)
boneIndex[0] += AttachBoneIndex;
boneIndex[1] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
boneIndex[1] += (TweenFrames[index].Curr.NextFrame* MAX_MODEL_TRANSFORMS);
boneIndex[1] += AttachBoneIndex;
matrix currFrame = Input[boneIndex[0]].Bone; //현재 프레임
matrix nextFrame = Input[boneIndex[1]].Bone; //다음 프레임
result = lerp(currFrame, nextFrame, TweenFrames[index].Curr.Time);
[flatten]
if(TweenFrames[index].Next.Clip > -1)
{
boneIndex[0] = (TweenFrames[index].Next.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
boneIndex[0] += (TweenFrames[index].Next.CurrFrame * MAX_MODEL_TRANSFORMS);
boneIndex[0] += AttachBoneIndex;
boneIndex[1] = (TweenFrames[index].Next.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
boneIndex[1] += (TweenFrames[index].Next.NextFrame * MAX_MODEL_TRANSFORMS);
boneIndex[1] += AttachBoneIndex;
matrix currFrame = Input[boneIndex[0]].Bone;
matrix nextFrame = Input[boneIndex[1]].Bone;
matrix nextAnim = lerp(currFrame, nextFrame, TweenFrames[index].Next.Time);
result = lerp(result, nextAnim, TweenFrames[index].TweenTime);
}
return result;
}
matrix BlendMode(uint index)
{
uint boneIndex[2];
matrix animation[3];
BlendFrame frame = BlendFrames[index];
[unroll(3)]
for (int i = 0; i < 3; i++)
{
boneIndex[0] = (frame.Clip[i].Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
boneIndex[0] += (frame.Clip[i].CurrFrame * MAX_MODEL_TRANSFORMS);
boneIndex[0] += AttachBoneIndex;
boneIndex[1] = (frame.Clip[i].Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
boneIndex[1] += (frame.Clip[i].NextFrame * MAX_MODEL_TRANSFORMS);
boneIndex[1] += AttachBoneIndex;
matrix currFrame = Input[boneIndex[0]].Bone;
matrix nextFrame = Input[boneIndex[1]].Bone;
animation[i] = lerp(currFrame, nextFrame, TweenFrames[index].Curr.Time);
}
int clipA = (int) frame.Alpha;
int clipB = clipA + 1;
float alpha = frame.Alpha;
if (alpha >= 1.0f)
{
alpha = frame.Alpha - 1.0f;
if (frame.Alpha >= 2.0f)
{
clipA = 1;
clipB = 2;
}
}
return lerp(animation[clipA], animation[clipB], alpha);
}
//최대 스레드의 개수를 사용한다. 스레드 하나 당 instance 하나를 대입하여 실행한다.
[numthreads(MAX_MODEL_INSTANCE, 1, 1)]
void CS(uint GroupIndex : SV_GroupIndex)
{
matrix result = 0;
if(BlendFrames[GroupIndex].Mode == 0)
result = TweenMode(GroupIndex);
else
result = BlendMode(GroupIndex);
Output[GroupIndex].Result = result;
}
technique11 T0
{
pass P0
{
SetVertexShader(NULL);
SetPixelShader(NULL);
SetComputeShader(CompileShader(cs_5_0, CS()));
}
}
핵심코드
matrix TweenMode(uint index)
{
uint boneIndex[2];
matrix result = 0;
////.Curr.Clip(=한 면) * MAX_MODEL_KEYFRAMES(=Y) * MAX_MODEL_TRANSFORMS(=X) //전체크기
boneIndex[0] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
////.Curr.CurrFrame(=Y) * MAX_MODEL_TRANSFORMS(=건너뛸 크기(Y프레임 개수))
boneIndex[0] += (TweenFrames[index].Curr.CurrFrame * MAX_MODEL_TRANSFORMS);
//AttachBoneIndex(=X방향)
boneIndex[0] += AttachBoneIndex;
boneIndex[1] = (TweenFrames[index].Curr.Clip * MAX_MODEL_KEYFRAMES * MAX_MODEL_TRANSFORMS);
boneIndex[1] += (TweenFrames[index].Curr.NextFrame* MAX_MODEL_TRANSFORMS);
boneIndex[1] += AttachBoneIndex;
matrix currFrame = Input[boneIndex[0]].Bone; //현재 프레임
matrix nextFrame = Input[boneIndex[1]].Bone; //다음 프레임
result = lerp(currFrame, nextFrame, TweenFrames[index].Curr.Time);
...
return result;
}
//최대 스레드의 개수를 사용한다. 스레드 하나 당 instance 하나를 대입하여 실행한다.
[numthreads(MAX_MODEL_INSTANCE, 1, 1)]
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 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; }
private:
UINT width, height, arraySize;
DXGI_FORMAT format;
ID3D11ShaderResourceView* outputSRV;
};
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 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;
};
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);
}
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;
}
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 = (ID3D11Texture2D*)output;
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, &outputSRV));
}
//inputData=구조체 초기화 데이터(입력받는 데이터의 크기), inputStride=구조체 하나의 크기, inputCount=구조체 개수(배열의 개수), outputStride=출력될 구조체 하나의 크기, outputCount=출력될 구조체의 개수
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; //Resource는 전부 SRV로 연결된다.
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
desc.StructureByteStride = inputStride;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = inputData;
Check(D3D::GetDevice()->CreateBuffer(&desc, inputData != NULL ? &subResource : NULL, &buffer));
input = (ID3D11Resource *)buffer;
}
void StructuredBuffer::CreateSRV()
{
ID3D11Buffer* buffer = (ID3D11Buffer *)input;
D3D11_BUFFER_DESC desc;
buffer->GetDesc(&desc);
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc.BufferEx.NumElements = inputCount; //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; //UNKOWN 포맷으로 설정.
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);
}
'⭐ DirectX > DirectX11 3D' 카테고리의 다른 글
[DirectX11] 066 3D 공간에서 충돌체 선택하기 (0) | 2023.03.08 |
---|---|
[DirectX11] 064~65 Bone 위치에 충돌체 삽입하기 (0) | 2023.03.06 |
[DirectX11] 062 Texture Buffer (0) | 2023.03.03 |
[DirectX11] 061 Thread Group, SV_GroupID (0) | 2023.03.02 |
[DirectX11] 060 Compute Shader (0) | 2023.02.28 |
댓글
이 글 공유하기
다른 글
-
[DirectX11] 066 3D 공간에서 충돌체 선택하기
[DirectX11] 066 3D 공간에서 충돌체 선택하기
2023.03.08 -
[DirectX11] 064~65 Bone 위치에 충돌체 삽입하기
[DirectX11] 064~65 Bone 위치에 충돌체 삽입하기
2023.03.06 -
[DirectX11] 062 Texture Buffer
[DirectX11] 062 Texture Buffer
2023.03.03 -
[DirectX11] 061 Thread Group, SV_GroupID
[DirectX11] 061 Thread Group, SV_GroupID
2023.03.02