Instancing
Instancing
-
동일한 개체를 여러개 렌더링해야할 경우 개체 하나 하나를 렌더링하는 것은 굉장히 많은 연산을 요구하게 된다.
-
이에 대한 해결방안으로 Draw Call을 그려야할 개체 수 만큼 하지 않고 한번의 Draw Call로 여러개의 개체를 그리도록 요청하는 기술을 Instancing이라고 한다.
//InstancingManager.cpp
void InstancingManager::Render(vector<shared_ptr<GameObject>>& gameObjects)
{
map<uint64, vector<shared_ptr<GameObject>>> cache;
for (shared_ptr<GameObject>& gameObject : gameObjects)
{
const uint64 instanceId = gameObject->GetMeshRenderer()->GetInstanceID();
cache[instanceId].push_back(gameObject);
}
for (auto& pair : cache)
{
const vector<shared_ptr<GameObject>>& vec = pair.second;
// 물체가 하나
if (vec.size() == 1)
{
vec[0]->GetMeshRenderer()->Render();
}
else // 물체가 두개 이상
{
const uint64 instanceId = pair.first;
for (const shared_ptr<GameObject>& gameObject : vec)
{
InstancingParams params;
params.matWorld = gameObject->GetTransform()->GetLocalToWorldMatrix();
params.matWV = params.matWorld * Camera::S_MatView;
params.matWVP = params.matWorld * Camera::S_MatView * Camera::S_MatProjection;
AddParam(instanceId, params);
}
shared_ptr<InstancingBuffer>& buffer = _buffers[instanceId];
vec[0]->GetMeshRenderer()->Render(buffer);
}
}
}
void InstancingManager::ClearBuffer()
{
for (auto& pair : _buffers)
{
shared_ptr<InstancingBuffer>& buffer = pair.second;
buffer->Clear();
}
}
void InstancingManager::AddParam(uint64 instanceId, InstancingParams& data)
{
if (_buffers.find(instanceId) == _buffers.end())
_buffers[instanceId] = make_shared<InstancingBuffer>();
_buffers[instanceId]->AddData(data);
}
//MeshRender.cpp
void MeshRenderer::Render()
{
GetTransform()->PushData();
_material->PushGraphicsData();
_mesh->Render();
}
void MeshRenderer::Render(shared_ptr<InstancingBuffer>& buffer)
{
buffer->PushData();
_material->PushGraphicsData();
_mesh->Render(buffer);
}
// InstancingBuffer.cpp
void InstancingBuffer::PushData()
{
const uint32 dataCount = GetCount();
if (dataCount > _maxCount)
Init(dataCount);
const uint32 bufferSize = dataCount * sizeof(InstancingParams);
void* dataBuffer = nullptr;
D3D12_RANGE readRange{ 0, 0 };
_buffer->Map(0, &readRange, &dataBuffer);
memcpy(dataBuffer, &_data[0], bufferSize);
_buffer->Unmap(0, nullptr);
_bufferView.BufferLocation = _buffer->GetGPUVirtualAddress();
_bufferView.StrideInBytes = sizeof(InstancingParams);
_bufferView.SizeInBytes = bufferSize;
}
-
InstancingManager.cpp 를 보면 하나의 개체에 대한 렌더링 요청과 두개 이상의 개체에 대한 렌더링 요청을 오버로딩된 Render함수를 사용하여 각기 다른 방식으로 처리하는 것을 알 수 있다.
-
MeshRenderer.cpp 를 통해 Instancing 객체의 PushData를 활용하여 Instance의 개수를 버퍼에 넣어준다.
- Instancing을 활용하지 않은 방식: FPS 가 380이 나오고 있다.
- Instancing을 활용한 방식: FPS 가 666이 나오고 있다.
Author And Source
이 문제에 관하여(Instancing), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sansam41/Instancing저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)