StructureBuffer를 살펴보기전에 텍스처를 주고받는 형태의 TextureBuffer를 알아보자.
이 버퍼를 가지고 우리가 사용한 텍스처를 간단하게 조작해서 다른 색상을 입힌 결과물을 리턴받는 방식으로 한번 만들어보자.
이 텍스처이미지는 2D로 픽셀 단위이기 때문에 정보가 많다. 이것을 우리가 여러개의 쓰레드가 처리할 수 있게 분산해주자. 일단 RawBuffer를 사용할 때와 마찬가지로 대칭성있게 입력을 받고 입력을 묘사하는 SRV를 만들고 결과를 받고 결과를 묘사하는 UAV를 받고 이를 복사해서 결과를 취합해주는 Result를 가져와주면 된다.
TextureBuffer.h
#pragma once
class TextureBuffer
{
public:
TextureBuffer(ComPtr<ID3D11Texture2D> src);
~TextureBuffer();
public:
void CreateBuffer();
private:
void CreateInput(ComPtr<ID3D11Texture2D> src);
void CreateSRV();
void CreateOutput();
void CreateUAV();
void CreateResult();
public:
uint32 GetWidth() { return _width; }
uint32 GetHeight() { return _height; }
uint32 GetArraySize() { return _arraySize; }
ComPtr<ID3D11Texture2D> GetOutput() { return (ID3D11Texture2D*)_output.Get(); }
ComPtr<ID3D11ShaderResourceView> GetOutputSRV() { return _outputSRV; }
public:
ComPtr<ID3D11ShaderResourceView> GetSRV() { return _srv; }
ComPtr<ID3D11UnorderedAccessView> GetUAV() { return _uav; }
private:
ComPtr<ID3D11Texture2D> _input;
ComPtr<ID3D11ShaderResourceView> _srv; // Input
ComPtr<ID3D11Texture2D> _output;
ComPtr<ID3D11UnorderedAccessView> _uav; // Output
private:
uint32 _width = 0;
uint32 _height = 0;
uint32 _arraySize = 0;
DXGI_FORMAT _format;
ComPtr<ID3D11ShaderResourceView> _outputSRV;
};
TextureBuffer.cpp
#include "pch.h"
#include "TextureBuffer.h"
TextureBuffer::TextureBuffer(ComPtr<ID3D11Texture2D> src)
{
CreateInput(src);
CreateBuffer();
}
TextureBuffer::~TextureBuffer()
{
}
void TextureBuffer::CreateBuffer()
{
CreateSRV();
CreateOutput();
CreateUAV();
CreateResult();
}
void TextureBuffer::CreateInput(ComPtr<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(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;
CHECK(DEVICE->CreateTexture2D(&desc, NULL, _input.GetAddressOf()));
DC->CopyResource(_input.Get(), src.Get());
}
void TextureBuffer::CreateSRV()
{
D3D11_TEXTURE2D_DESC desc;
_input->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(DEVICE->CreateShaderResourceView(_input.Get(), &srvDesc, _srv.GetAddressOf()));
}
void TextureBuffer::CreateOutput()
{
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(DEVICE->CreateTexture2D(&desc, nullptr, _output.GetAddressOf()));
}
void TextureBuffer::CreateUAV()
{
D3D11_TEXTURE2D_DESC desc;
_output->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(DEVICE->CreateUnorderedAccessView(_output.Get(), &uavDesc, _uav.GetAddressOf()));
}
void TextureBuffer::CreateResult()
{
D3D11_TEXTURE2D_DESC desc;
_output->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(DEVICE->CreateShaderResourceView(_output.Get(), &srvDesc, _outputSRV.GetAddressOf()));
}
이렇게 버퍼를 만들어주고 우리가 텍스처를 조작할 때 사용할 수 있도록 텍스처 클래스에 헬퍼함수와 SRV에서 Texture2D를 가져오는 함수를 추가해주자.
Texture.h
#pragma once
#include "ResourceBase.h"
class Texture : public ResourceBase
{
using Super = ResourceBase;
public:
ComPtr<ID3D11Texture2D> GetTexture2D();
void SetSRV(ComPtr<ID3D11ShaderResourceView> srv) { _shaderResourveView = srv; }
};
Texture.cpp
ComPtr<ID3D11Texture2D> Texture::GetTexture2D()
{
//자기 SRV-> TExture2D
ComPtr<ID3D11Texture2D> texture;
_shaderResourveView->GetResource((ID3D11Resource**)texture.GetAddressOf());
return texture;
}
2D Texture를 가지고 조작해볼 것이기 때문에 쓰레드를 2차원으로 설정해주고 고유한 아이디에 해당하는 정보를 가져와서 조작할 수 있도록 쉐이더코드를 만들어주자.
TextureBufferDemo.fx
//RGBA
Texture2DArray<float4> Input;
RWTexture2DArray<float4> Output;
//thread 개수 a*b*c 총합
[numthreads(32,32,1)] //2차원
void CS(uint3 id : SV_DispatchThreadID)
{
float4 color = Input.Load(int4(id, 0)); //쓰레드 넘버링값에 해당하는 정보 추출
//Output[id] = color;
Output[id] = 1.0f - color; //반전
//Output[id] = (color.r + color.g + color.b) / 3.0f; //회색풍
}
technique11 T0
{
Pass P0
{
SetVertexShader(NULL);
SetPixelShader(NULL);
//컴퓨트 쉐이더 세팅
SetComputeShader(CompileShader(cs_5_0, CS()));
}
};
쓰레드를 설정해두고 이에 맞는 픽셀을 가공하는데 이미지 파일은 쓰레드 개수로 딱 떨어지지 않고 훨씬 더 클 것이다.
그래서 여러 단위로 만들어서 작업을 하는데 이렇게 작업을 하다보면 남는 데이터가 있을텐데 이 데이터도 하나로 인식해서 처리해야하기 때문에 만약에 나누었을 때 작게 나오는 것보다는 크게 그룹을 설정해주는게 좋기 때문에 쓰레드 개수 -1
/ 쓰레드 개수 이런식으로 처리해주면 크게 그룹이 설정된다.
TextureBufferDemo.h
#pragma once
#include "IExecute.h"
class TextureBufferDemo : public IExecute
{
public:
void Init() override;
void Update() override;
void Render() override;
private:
shared_ptr<Shader> _shader;
private:
ComPtr<ID3D11ShaderResourceView> MakeComputeShaderTexture();
};
TextureBufferDemo.cpp
#include "pch.h"
#include "TextureBufferDemo.h"
#include "GeometryHelper.h"
#include "Camera.h"
#include "GameObject.h"
#include "CameraScript.h"
#include "MeshRenderer.h"
#include "Mesh.h"
#include "Material.h"
#include "Model.h"
#include "ModelRenderer.h"
#include "ModelAnimator.h"
#include "Mesh.h"
#include "Transform.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "Light.h"
#include "TextureBuffer.h"
void TextureBufferDemo::Init()
{
_shader = make_shared<Shader>(L"23. RenderDemo.fx");
auto newSrv = MakeComputeShaderTexture();
// Camera
{
auto camera = make_shared<GameObject>();
camera->GetOrAddTransform()->SetPosition(Vec3{ 0.f, 0.f, -5.f });
camera->AddComponent(make_shared<Camera>());
camera->AddComponent(make_shared<CameraScript>());
CUR_SCENE->Add(camera);
}
// Light
{
auto light = make_shared<GameObject>();
light->AddComponent(make_shared<Light>());
LightDesc lightDesc;
lightDesc.ambient = Vec4(0.4f);
lightDesc.diffuse = Vec4(1.f);
lightDesc.specular = Vec4(0.1f);
lightDesc.direction = Vec3(1.f, 0.f, 1.f);
light->GetLight()->SetLightDesc(lightDesc);
CUR_SCENE->Add(light);
}
// Mesh
// Material
{
shared_ptr<Material> material = make_shared<Material>();
material->SetShader(_shader);
auto texture = make_shared<Texture>();
texture->SetSRV(newSrv);
material->SetDiffuseMap(texture);
MaterialDesc& desc = material->GetMaterialDesc();
desc.ambient = Vec4(1.f);
desc.diffuse = Vec4(1.f);
desc.specular = Vec4(1.f);
RESOURCES->Add(L"Veigar", material);
}
for (int32 i = 0; i < 100; i++)
{
auto obj = make_shared<GameObject>();
obj->GetOrAddTransform()->SetLocalPosition(Vec3(rand() % 100, 0, rand() % 100));
obj->AddComponent(make_shared<MeshRenderer>());
{
obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));
}
{
auto mesh = RESOURCES->Get<Mesh>(L"Sphere");
obj->GetMeshRenderer()->SetMesh(mesh);
obj->GetMeshRenderer()->SetPass(0);
}
CUR_SCENE->Add(obj);
}
RENDER->Init(_shader);
}
void TextureBufferDemo::Update()
{
}
void TextureBufferDemo::Render()
{
}
ComPtr<ID3D11ShaderResourceView> TextureBufferDemo::MakeComputeShaderTexture()
{
auto shader = make_shared<Shader>(L"26. TextureBufferDemo.fx");
auto texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
shared_ptr<TextureBuffer> textureBuffer = make_shared<TextureBuffer>(texture->GetTexture2D());
shader->GetSRV("Input")->SetResource(textureBuffer->GetSRV().Get());
shader->GetUAV("Output")->SetUnorderedAccessView(textureBuffer->GetUAV().Get());
uint32 width = textureBuffer->GetWidth();
uint32 height = textureBuffer->GetHeight();
uint32 arraySize = textureBuffer->GetArraySize();
uint32 x = max(1, (width + 31) / 32);
uint32 y = max(1, (height + 31) / 32);
shader->Dispatch(0, 0, x, y, arraySize);
return textureBuffer->GetOutputSRV();
}
이렇게 해준 다음 실행해주면 색이 반전된 구들이 나오게 된다.
'게임공부 > Directx11' 카테고리의 다른 글
[Directx11][C++][3D]25. RenderManager 분할 (3) | 2024.10.03 |
---|---|
[Directx11][C++][3D]24. StructureBuffer (0) | 2024.10.02 |
[Directx11][C++][3D]22. RawBuffer (1) | 2024.09.30 |
[Directx11][C++][3D]21. Quaternion (0) | 2024.09.29 |
[Directx11][C++][3D]20. 통합 & 정리 (1) | 2024.09.28 |