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();
}

 

이렇게 해준 다음 실행해주면 색이 반전된 구들이 나오게 된다.

 

+ Recent posts