[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
댓글을 사용할 수 없습니다.