Deferred Rendering


Deferred Rendering


  • 従来のForward Renderingメソッドでは、Meshを描画するときにすべての計算を一度に実行するメソッドが使用されます.したがって、光線計算数がメッシュ数に比例し、光線の影響を受けないメッシュも演算し、不要な演算を生じるという欠点がある.

  • これらの欠点を解決するために作成された技術DeferredRenderingが今回のトピックです.

  • DeferredRenderingとは?
  • マルチレンダーターゲットを使用して、Gbufferと呼ばれる複数のバッファで不透明なオブジェクトの情報をレンダーします.
  • GBufferの情報には、Diffuse、Screen Space Normal、Spenance、Smootherness、Screen Space Depthなどの情報が記録される.
  • のすべてのオブジェクトのGBufferをレンダリングした後、その情報に従って光源を処理してフレームバッファに出力します.

  • GBufferとLight情報を使用して、Position、Normal、Color、Diffuse Light、Spence-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);
    }
  • RenderTargetの用途は、SWAAPChain、Gbuffer、Lightingの3種類に分けられ、用途に応じて適切な作成と管理が行われています.
  • #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
    
  • の繰延で球を描画し、球のGbufferとLighting情報をRTGに保存します.
  • *UIのTextureをRTGに格納されている各Textureとして指定し、各UI Boxに描画します.

    これは、
  • それぞれのUI Boxにおいて、マルチレンダリングターゲットに含まれる情報を組み合わせたオブジェクトである.
  • Position
  • Normal Vector
  • Color
  • Diffuse Light
  • Specular Light