15 분 소요

🔷 Texture Mapping

🔹 DirectXTex 설정


0. UV 좌표 설정

  • 사진 추가 예정

1. Texture Class

  • 텍스쳐를 불러와 관리해주는 클래스
#pragma once
class Texture
{
public:
	void Init(const wstring& path);

public:
	void CreateTexture(const wstring& path);
	void CreateView();

	D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle() { return _srvHandle; }

private:
	ScratchImage					_image;	// 이미지 또는 이미지 집합을 반환하는 함수의 메모리를 관리하는 도우미 클래스
	ComPtr<ID3D12Resource>			_tex2D;

	ComPtr<ID3D12DescriptorHeap>	_srvHeap;
	D3D12_CPU_DESCRIPTOR_HANDLE		_srvHandle;
};

1) 이미지 파일을 불러온다

  • C++17부터 지원하는 #include <filesystem>을 사용한다.
  • ⚠️ 충돌로 인해 #define _HAS_STD_BYTE 0 필요!
wstring ext = std::filesystem::path(path).extension();

if (ext == L".dds" || ext == L".DDS")
	::LoadFromDDSFile(path.c_str(), DDS_FLAGS_NONE, nullptr, _image);
else if (ext == L".tga" || ext == L".TGA")
	::LoadFromTGAFile(path.c_str(), nullptr, _image);
else // png, jpg, jpeg, bmp
	::LoadFromWICFile(path.c_str(), WIC_FLAGS_NONE, nullptr, _image);

ComPtr<ID3D12Device> device = MyEngine->GetDevice()->GetDevice();
HRESULT hr = ::CreateTexture(device.Get(), _image.GetMetadata(), &_tex2D);
assert(SUCCEEDED(hr));

vector<D3D12_SUBRESOURCE_DATA> subResources;

hr = ::PrepareUpload(
	device.Get(),
	_image.GetImages(),
	_image.GetImageCount(),
	_image.GetMetadata(),
	subResources);

assert(SUCCEEDED(hr));

const uint64 bufferSize = ::GetRequiredIntermediateSize(_tex2D.Get(), 0, static_cast<uint32>(subResources.size()));

D3D12_HEAP_PROPERTIES heapProperty = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(bufferSize);

ComPtr<ID3D12Resource> textureUploadHeap;
hr = device->CreateCommittedResource(
	&heapProperty,
	D3D12_HEAP_FLAG_NONE,
	&desc,
	D3D12_RESOURCE_STATE_GENERIC_READ,
	nullptr,
	IID_PPV_ARGS(textureUploadHeap.GetAddressOf()));

assert(SUCCEEDED(hr));

// 
ComPtr<ID3D12GraphicsCommandList> resCmdList = MyEngine->GetCommandQueue()->GetResourceCommandList();
::UpdateSubresources(
	resCmdList.Get(),
	_tex2D.Get(),
	textureUploadHeap.Get(),
	0, 0,
	static_cast<unsigned int>(subResources.size()),
	subResources.data());

MyEngine->GetCommandQueue()->FlushResourceCommandQueue();

2) 텍스처를 저장하는 Resource 생성

3) 텍스처 Resource를 설명하는 설명자 힙 생성 (SRV)

ComPtr<ID3D12Device> device = MyEngine->GetDevice()->GetDevice();

D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
heapDesc.NumDescriptors = 1;
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_srvHeap));

_srvHandle = _srvHeap->GetCPUDescriptorHandleForHeapStart();

// STV
D3D12_SHADER_RESOURCE_VIEW_DESC viewDesc = {};
viewDesc.Format = _image.GetMetadata().format;
viewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
viewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
viewDesc.Texture2D.MipLevels = 1;
device->CreateShaderResourceView(_tex2D.Get(), &viewDesc, _srvHandle);


2. Mesh 클래스에서 Texture 설정

MyEngine->GetTableDescriptorHeap()->SetShaderResourceView(_tex->GetCpuHandle(), SRV_REGISTER::t0);

2. CommandQueue 설정 및 ResourceList 생성

ComPtr<ID3D12CommandAllocator>		_resCmdAlloc;
ComPtr<ID3D12GraphicsCommandList>	_resCmdList;
// Te
device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&_resCmdAlloc));
device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, _resCmdAlloc.Get(), nullptr, IID_PPV_ARGS(&_resCmdList));
void CommandQueue::FlushResourceCommandQueue()
{
	_resCmdList->Close();

	ID3D12CommandList* cmdListArr[] = { _resCmdList.Get() };
	_cmdQueue->ExecuteCommandLists(_countof(cmdListArr), cmdListArr);

	WaitSync();

	_resCmdAlloc->Reset();
	_resCmdList->Reset(_resCmdAlloc.Get(), nullptr);
}


2. Root Signature 변경 및 Descriptor Table 설정

CD3DX12_DESCRIPTOR_RANGE range[] =
{
    CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, CBV_REGISTER_COUNT, 0),
    CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, SRV_REGISTER_COUNT, 0),
};
...
_samplerDesc = CD3DX12_STATIC_SAMPLER_DESC(0);
D3D12_ROOT_SIGNATURE_DESC desc = CD3DX12_ROOT_SIGNATURE_DESC(_countof(param), param, 1, &_samplerDesc);
void TableDescriptorHeap::SetShaderResourceView(D3D12_CPU_DESCRIPTOR_HANDLE srcHandle, SRV_REGISTER reg)
{
	D3D12_CPU_DESCRIPTOR_HANDLE destHandle = GetCpuHandle(reg);

	uint32 destRange = 1;
	uint32 srcRange = 1;
	MyEngine->GetDevice()->GetDevice()->CopyDescriptors(1, &destHandle, &destRange, 1, &srcHandle, &srcRange, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}


3. HLSL 변경 및 Shader 정보 추가

...
// Texture를 전달받을 수 있는 레지스터 설정
Texture2D tex_0 : register(t0);
SamplerState sam_0 : register(s0);
// uv좌표 추가
struct VS_IN
{
	...
    float2 uv : TEXCOORD;
};

struct VS_OUT
{
	...
    float2 uv : TEXCOORD;
};

VS_OUT VS_Main(VS_IN input)
{
    VS_OUT output = (VS_OUT)0;

    output.pos = float4(input.pos, 1.f);
    output.color = input.color;
    output.uv = input.uv;

    return output;
}

float4 PS_Main(VS_OUT input) : SV_Target
{
    float4 color = tex_0.Sample(sam_0, input.uv);
    return color;
}
D3D12_INPUT_ELEMENT_DESC desc[] =
{
	...
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};


🔹 결과

image


📑. 참고

카테고리:

업데이트:

댓글남기기