전통적인 방법인 Forward Rendering의 경우 Mesh 하나를 그릴 때 모든 계산을 한번에 시행하는 방법을 이용한다. 따라서 라이팅 계산수가 Mesh의 수에 비례하게 되고, 빛의 영향을 받지 않은 Mesh에 대해서도 연산을 시행하게 되어 불필요한 연산이 행해지게 되는 단점이 있다.
이러한 단점을 해결하기위해 만든 기술이 Deferred Rendering이 이번 주제이다.
Deferred Rendering이란?
GBuffer와 Light정보로 Position, Normal, Color, Diffuse Light, Specular Light 총 5개의 정보를 저장하고 저번에 만들어 놓은 UI에 출력하도록 설정하였다.
void RenderTargetGroup::Create(RENDER_TARGET_GROUP_TYPE groupType, vector<RenderTarget>& rtVec, shared_ptr<Texture> dsTexture)
{
_groupType = groupType;
_rtVec = rtVec;
_rtCount = static_cast<uint32>(rtVec.size());
_dsTexture = dsTexture;
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
heapDesc.NumDescriptors = _rtCount;
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
heapDesc.NodeMask = 0;
DEVICE->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_rtvHeap));
_rtvHeapSize = DEVICE->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
_rtvHeapBegin = _rtvHeap->GetCPUDescriptorHandleForHeapStart();
_dsvHeapBegin = _dsTexture->GetDSV()->GetCPUDescriptorHandleForHeapStart();
for (uint32 i = 0; i < _rtCount; i++)
{
uint32 destSize = 1;
D3D12_CPU_DESCRIPTOR_HANDLE destHandle = CD3DX12_CPU_DESCRIPTOR_HANDLE(_rtvHeapBegin, i * _rtvHeapSize);
uint32 srcSize = 1;
ComPtr<ID3D12DescriptorHeap> srcRtvHeapBegin = _rtVec[i].target->GetRTV();
D3D12_CPU_DESCRIPTOR_HANDLE srcHandle = srcRtvHeapBegin->GetCPUDescriptorHandleForHeapStart();
DEVICE->CopyDescriptors(1, &destHandle, &destSize, 1, &srcHandle, &srcSize, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}
for (int i = 0; i < _rtCount; ++i)
{
_targetToResource[i] = CD3DX12_RESOURCE_BARRIER::Transition(_rtVec[i].target->GetTex2D().Get(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COMMON);
_resourceToTarget[i] = CD3DX12_RESOURCE_BARRIER::Transition(_rtVec[i].target->GetTex2D().Get(),
D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_RENDER_TARGET);
}
}
void RenderTargetGroup::OMSetRenderTargets(uint32 count, uint32 offset)
{
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = CD3DX12_CPU_DESCRIPTOR_HANDLE(_rtvHeapBegin, offset * _rtvHeapSize);
CMD_LIST->OMSetRenderTargets(count, &rtvHandle, FALSE/*1개*/, &_dsvHeapBegin);
}
void RenderTargetGroup::OMSetRenderTargets()
{
CMD_LIST->OMSetRenderTargets(_rtCount, &_rtvHeapBegin, TRUE/*다중*/, &_dsvHeapBegin);
}
#pragma region Object
{
shared_ptr<GameObject> obj = make_shared<GameObject>();
obj->AddComponent(make_shared<Transform>());
obj->GetTransform()->SetLocalScale(Vec3(100.f, 100.f, 100.f));
obj->GetTransform()->SetLocalPosition(Vec3(0.f, 0.f, 150.f));
shared_ptr<MeshRenderer> meshRenderer = make_shared<MeshRenderer>();
{
shared_ptr<Mesh> sphereMesh = GET_SINGLE(Resources)->LoadSphereMesh();
meshRenderer->SetMesh(sphereMesh);
}
{
shared_ptr<Shader> shader = GET_SINGLE(Resources)->Get<Shader>(L"Deferred");
shared_ptr<Texture> texture = GET_SINGLE(Resources)->Load<Texture>(L"Leather", L"..\\Resources\\Texture\\Leather.jpg");
shared_ptr<Texture> texture2 = GET_SINGLE(Resources)->Load<Texture>(L"Leather_Normal", L"..\\Resources\\Texture\\Leather_Normal.jpg");
shared_ptr<Material> material = make_shared<Material>();
material->SetShader(shader);
material->SetTexture(0, texture);
material->SetTexture(1, texture2);
meshRenderer->SetMaterial(material);
}
obj->AddComponent(meshRenderer);
scene->AddGameObject(obj);
}
#pragma endregion
#pragma region UI_Test
for (int32 i = 0; i < 5; i++)
{
shared_ptr<GameObject> sphere = make_shared<GameObject>();
sphere->SetLayerIndex(GET_SINGLE(SceneManager)->LayerNameToIndex(L"UI")); // UI
sphere->AddComponent(make_shared<Transform>());
sphere->GetTransform()->SetLocalScale(Vec3(100.f, 100.f, 100.f));
sphere->GetTransform()->SetLocalPosition(Vec3(-350.f + (i * 160), 250.f, 500.f));
shared_ptr<MeshRenderer> meshRenderer = make_shared<MeshRenderer>();
{
shared_ptr<Mesh> mesh = GET_SINGLE(Resources)->LoadRectangleMesh();
meshRenderer->SetMesh(mesh);
}
{
shared_ptr<Shader> shader = GET_SINGLE(Resources)->Get<Shader>(L"Texture");
shared_ptr<Texture> texture;
if (i < 3)
texture = GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::G_BUFFER)->GetRTTexture(i);
else
texture = GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::LIGHTING)->GetRTTexture(i - 3);
shared_ptr<Material> material = make_shared<Material>();
material->SetShader(shader);
material->SetTexture(0, texture);
meshRenderer->SetMaterial(material);
}
sphere->AddComponent(meshRenderer);
scene->AddGameObject(sphere);
}
#pragma endregion
*UI의 Texture를 RTG에 저장된 각 Texture로 지정하여 각 UI Box에 그려준다.