이번강좌는 네모를 그려보자.
우선 지난장에서 했던것 중에 확인해야 할 것은
void Game::Init(const WindowInfo& info)
{
GEngine->Init(info);
vector<Vertex> vec(3);
vec[0].pos = Vec3(0.f, 0.5f, 0.5f);
vec[0].color = Vec4(1.f, 0.f, 0.f, 1.f);
vec[1].pos = Vec3(0.5f, -0.5f, 0.5f);
vec[1].color = Vec4(0.f, 1.0f, 0.f, 1.f);
vec[2].pos = Vec3(-0.5f, -0.5f, 0.5f);
vec[2].color = Vec4(0.f, 0.f, 1.f, 1.f);
mesh->Init(vec); // Mesh 정보를 한 번만 Init한다.
shader->Init(L"..\\Resources\\Shader\\default.hlsli");
GEngine->GetCmdQueue()->WaitSync();
}
삼각형은 2개가 나오는데 실제로 선언한 mesh는 1개이다??
mesh를 두 번 할당해서 삼각형을 두 번 그리는 것이 아니라 mesh를 재활용해서 그릴 수 있다.
(참고로 mesh를 할당(Init)하는 과정에서 컴퓨터 자원의 소모가 크다.)
void Game::Update()
{
GEngine->RenderBegin();
shader->Update();
{
Transform t;
t.offset = Vec4(0.75f, 0.f, 0.f, 0.f);
mesh->SetTransform(t);
mesh->Render();
}
{
Transform t;
t.offset = Vec4(0.f, 0.75f, 0.f, 0.f);
mesh->SetTransform(t);
mesh->Render();
}
GEngine->RenderEnd();
}
좀더 설명하자면
void Mesh::Init(vector<Vertex>& vec)
{
_vertexCount = static_cast<uint32>(vec.size());
uint32 bufferSize = _vertexCount * sizeof(Vertex);
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, &vec[0], bufferSize);
_vertexBuffer->Unmap(0, nullptr);
// Initialize the vertex buffer view.
_vertexBufferView.BufferLocation = _vertexBuffer->GetGPUVirtualAddress();
_vertexBufferView.StrideInBytes = sizeof(Vertex); // 정점 1개 크기
_vertexBufferView.SizeInBytes = bufferSize; // 버퍼의 크기
}
Vertext가 들어오면 _vertexBuffer를 할당하고 _vertexBufferView을 통해 컨트롤하는 구조
void Mesh::Render()
{
CMD_LIST->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
CMD_LIST->IASetVertexBuffers(0, 1, &_vertexBufferView); // Slot: (0~15)
// ...
렌더링 하는 과정에서도
- Input Assembly 삼각형으로 Mesh를 그리겠다 선언 (
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST
) - Input Assemble 에서 _vertexBufferView의 mesh를 쓰겠다고 알려줌.
네모를 그려보자.
그럼 이번엔 네모를 그려보자.
void Game::Init(const WindowInfo& info)
{
GEngine->Init(info);
vector<Vertex> vec(6);
vec[0].pos = Vec3(-0.5f, 0.5f, 0.5f);
vec[0].color = Vec4(1.f, 0.f, 0.f, 1.f);
vec[1].pos = Vec3(0.5f, 0.5f, 0.5f);
vec[1].color = Vec4(0.f, 1.f, 0.f, 1.f);
vec[2].pos = Vec3(0.5f, -0.5f, 0.5f);
vec[2].color = Vec4(0.f, 0.f, 1.f, 1.f);
vec[3].pos = Vec3(0.5f, -0.5f, 0.5f);
vec[3].color = Vec4(0.f, 0.f, 1.f, 1.f);
vec[4].pos = Vec3(-0.5f, -0.5f, 0.5f);
vec[4].color = Vec4(0.f, 1.f, 0.f, 1.f);
vec[5].pos = Vec3(-0.5f, 0.5f, 0.5f);
vec[5].color = Vec4(1.f, 0.f, 0.f, 1.f);
// ...
이렇게 해도 되긴한데 … 너무 무식하지 않나??
index buffer 등장
우선 정점 네 개로 사각형을 표현시 삼각형이 어떻게 붙어있는지에 대한 정보를 넘겨야 한다.
이를 index buffer를 통해 넘긴다.
void Game::Init(const WindowInfo& info)
{
GEngine->Init(info);
// 4개의 정점을 넘기고
vector<Vertex> vec(4);
vec[0].pos = Vec3(-0.5f, 0.5f, 0.5f);
vec[0].color = Vec4(1.f, 0.f, 0.f, 1.f);
vec[1].pos = Vec3(0.5f, 0.5f, 0.5f);
vec[1].color = Vec4(0.f, 1.f, 0.f, 1.f);
vec[2].pos = Vec3(0.5f, -0.5f, 0.5f);
vec[2].color = Vec4(0.f, 0.f, 1.f, 1.f);
vec[3].pos = Vec3(-0.5f, -0.5f, 0.5f);
vec[3].color = Vec4(0.f, 1.f, 0.f, 1.f);
/*
[0]-------------[1]
| |
| |
| |
| |
[3]-------------[2]
*/
// 삼각형이 어떻게 세트인지 index buffer를 통해 넘긴다.
vector<uint32> indexVec;
{
// 우/상단을 index로 넣음
// 정점의 순서는 삼각형이 어떠한 순서로 구성되어있는지 알림.
indexVec.push_back(0);
indexVec.push_back(1);
indexVec.push_back(2);
}
{
// 좌/하단을 index로 넣음
indexVec.push_back(0);
indexVec.push_back(2);
indexVec.push_back(3);
}
mesh->Init(vec, indexVec);
shader->Init(L"..\\Resources\\Shader\\default.hlsli");
GEngine->GetCmdQueue()->WaitSync();
}
void Mesh::Init(const vector<Vertex>& vertexBuffer, const vector<uint32>& indexBuffer)
{
CreateVertexBuffer(vertexBuffer);
CreateIndexBuffer(indexBuffer);
}
void Mesh::CreateVertexBuffer(const vector<Vertex>& buffer)
{
_vertexCount = static_cast<uint32>(buffer.size());
uint32 bufferSize = _vertexCount * sizeof(Vertex);
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; // 버퍼의 크기
}
void Mesh::CreateIndexBuffer(const vector<uint32>& buffer)
{
_indexCount = static_cast<uint32>(buffer.size());
uint32 bufferSize = _indexCount * sizeof(uint32);
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(&_indexBuffer));
void* indexDataBuffer = nullptr;
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
_indexBuffer->Map(0, &readRange, &indexDataBuffer);
::memcpy(indexDataBuffer, &buffer[0], bufferSize);
_indexBuffer->Unmap(0, nullptr);
_indexBufferView.BufferLocation = _indexBuffer->GetGPUVirtualAddress();
_indexBufferView.Format = DXGI_FORMAT_R32_UINT;
_indexBufferView.SizeInBytes = bufferSize;
}
void Mesh::Render()
{
CMD_LIST->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
CMD_LIST->IASetVertexBuffers(0, 1, &_vertexBufferView); // Slot: (0~15)
CMD_LIST->IASetIndexBuffer(&_indexBufferView); // 렌더시에도 IndexBuffer를 알린다.
// ...
CMD_LIST->DrawIndexedInstanced(_indexCount, 1, 0, 0, 0);