Mesh는 정점으로 이루어진 물체이다.
D3D12_HEAP_PROPERTIES heapProperty = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(bufferSize);
DEVICE->CreateCommittedResource(
&heapProperty,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&_vertexBuffer));
// Copy the triangle data to the vertex buffer.
void* vertexDataBuffer = nullptr;
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
_vertexBuffer->Map(0, &readRange, &vertexDataBuffer);
::memcpy(vertexDataBuffer, &buffer[0], bufferSize);
_vertexBuffer->Unmap(0, nullptr);
// Initialize the vertex buffer view.
_vertexBufferView.BufferLocation = _vertexBuffer->GetGPUVirtualAddress();
_vertexBufferView.StrideInBytes = sizeof(Vertex); // 정점 1개 크기
_vertexBufferView.SizeInBytes = bufferSize; // 버퍼의 크기
Mesh를 초기화할 때 CreateCommitedResource로 GPU에 데이터를 복사하기 위한 공간을 마련한다. _vertexBuffer 데이터를 vertexBuffer로 mapping하고 memcpy로 CPU에서 GPU로 메모리를 복사한다. 복사가 끝나면 _vertexBuffer을 unmap한다. 그 후 버퍼를 묘사하기 위해 View를 설정한다.
CMD_LIST->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
CMD_LIST->IASetVertexBuffers(0, 1, &_vertexBufferView);
CMD_LIST->DrawInstanced(_vertexCount, 1, 0, 0);
초기화를 마치고 Mesh::Render에서 실제로 그림을 그린다. Render은 CommandQueue의 RenderBegin과 RenderEnd사이에 껴서 매 Update마다 실행된다. RenderBegin에서는 CommandQueue를 열어 수행할 일감들을 받고 RenderEnd에서는 CommandQueue를 닫고 받은 일감들을 수행한다.
CreateVertexShader(path, "VS_Main", "vs_5_0");
CreatePixelShader(path, "PS_Main", "ps_5_0");
D3D12_INPUT_ELEMENT_DESC desc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
_pipelineDesc.InputLayout = { desc, _countof(desc) };
_pipelineDesc.pRootSignature = ROOT_SIGNATURE.Get();
_pipelineDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
_pipelineDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
_pipelineDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
_pipelineDesc.SampleMask = UINT_MAX;
_pipelineDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
_pipelineDesc.NumRenderTargets = 1;
_pipelineDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
_pipelineDesc.SampleDesc.Count = 1;
_pipelineDesc.DSVFormat = GEngine->GetDepthStencilBuffer()->GetDSVFormat();
DEVICE->CreateGraphicsPipelineState(&_pipelineDesc, IID_PPV_ARGS(&_pipelineState));
Shader은 외주 인력들이 뭘 해야 할지 기술하는 일감 기술서이다. Shader는 hlsl 형식의 파일을 컴파일해서 그 안의 명령들을 실행한다. Shader::Init에서 CreateShader로 쉐이더 파일을 읽고 (일감 목록) 어떻게 처리할지 pipelineDesc에 저장한다. VertexShader은 정점 정보, PixelShader은 색상(픽셀) 정보를 가지고 있다.
void Shader::Update()
{
CMD_LIST->SetPipelineState(_pipelineState.Get());
}
그리고 Mesh::Render 전에 Shader::Update를 실행하는데, SetPipelineState로 어떻게 외주를 할지 전달한다.
어떤 Root Signature을 사용할지도 여기서 결정한다.
// 파일 확장자 얻기
wstring ext = fs::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);
HRESULT hr = ::CreateTexture(DEVICE.Get(), _image.GetMetadata(), &_tex2D);
if (FAILED(hr))
assert(nullptr);'그래픽스' 카테고리의 다른 글
| [DX12] Normal Mapping (0) | 2022.02.28 |
|---|---|
| [DX12] Projection, Screen 변환 행렬 (0) | 2022.02.26 |
| [DX12] World, View 변환 행렬 (0) | 2022.02.26 |
| [DX12] 좌표계 변환 행렬 (0) | 2022.02.25 |
| [DX12] 장치 초기화 개요 (0) | 2022.02.20 |