[DirectX 12] #2-6. Index Buffer
들어가며
DX에서 3D 모델을 사용할 때, 같은 객체를 여러 번 생성한다고 해서 매번 메쉬 정보를 다시 로드하지 않는다. 한 번 로드된 메쉬 데이터를 여러 객체가 공유하여 성능을 최적화한다.
이전 코드에서는 다음과 같은 방식으로 렌더링했다.
- Mesh를 생성할 때 정점 정보를 저장
- vertex buffer를 생성하고 vertex buffer view를 생성
- Input Assembler에 vertex buffer view 전달
- 쉐이더에서 정점 정보를 받아 연산 수행
- 삼각형 단위로 화면에 렌더링
이번 수업에서는 vertex buffer와 index buffer를 함께 사용해서 Input Assembler에 전달하여 사각형을 렌더링 하는 방법을 배운다.
사각형 그리기
vertex buffer만 사용해서 사각형을 그리는 방식과 vertex buffer + index buffer를 사용해 사각형을 그리는 방식을 코드로 구현해보자.
vertex buffer only
vertex buffer만 사용할 경우, 사각형을 두 개의 삼각형으로 나눠 총 6개의 정점을 저장해야 한다.
- 정점 데이터 수정 (
Clinet
프로젝트의Game::Init()
)- 정점 데이터 6개
```cpp
vector
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);
- 정점 데이터 6개
```cpp
vector
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);
mesh->Init(vec);
- 결과
- 6개의 정점을 사용하여 삼각형 두 개가 생성됐고, 사각형이 출력 됐다.
- 문제점
- 중복된 정점이 있어 메모리의 낭비가 발생한다.
- index buffer를 사용하면 정점 데이터 낭비를 줄일 수 있다.
vertex buffer + index buffer
index buffer에는 정점을 그리는 순서를 저장하고, vertex buffer에는 정점의 정보를 저장하여 정점 정보가 중복 저장되는 문제점을 해결할 수 있다.
- 정점 데이터 수정 (
Clinet
프로젝트의Game::Init()
)- vertex 데이터 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);
- index 데이터
vector<uint32> indexVec; indexVec.push_back(0); indexVec.push_back(1); indexVec.push_back(2); indexVec.push_back(0); indexVec.push_back(2); indexVec.push_back(3);
- vertex 데이터 4개
Mesh
클래스 수정- index buffer 지원을 위해 index buffer 관련 멤버 변수를 추가한다.
ComPtr<ID3D12Resource> _indexBuffer; D3D12_INDEX_BUFFER_VIEW _indexBufferView; uint32 _indexCount = 0;
- index buffer를 생성하는
Mesh::CreateIndexBuffer()
를 생성한다._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); _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;
- 기존의
Mesh::Init()
수정- 기존의 코드는
CreateVertexBuffer()
로 바꾼다. CreateVertexBuffer()
와CreateIndexBuffer()
를 호출한다.
- 기존의 코드는
Mesh::Render()
수정CMD_LIST->IASetIndexBuffer(&_indexBufferView); CMD_LIST->DrawIndexedInstanced(_indexCount, 1, 0, 0, 0);
- index buffer 지원을 위해 index buffer 관련 멤버 변수를 추가한다.
- 결과
- 똑같은 사각형이 출력되지만, 정점을 그리는 방식에 차이가 있다.
- 차이점
- vertex buffer만 사용할 경우
- 정점이 6개 필요하다.
- 중복된 점으로 메모리가 낭비된다.
- vertex buffer와 index buffer를 같이 사용한 경우
- 정점이 4개 필요하다.
- 메모리를 절약해 렌더링할 수 있다.
- 고퀄리티 3D 모델을 다룰 때 큰 성능 차이를 보인다.
- vertex buffer만 사용할 경우
마치며
이번 시간에 배운 것
- vertex buffer만 사용해서 삼각형을 그리는 방법
- vertex buffer와 index buffer를 사용하여 효율적으로 렌더링하는 방법
Leave a comment