본문 바로가기
DirectX/[Inflearn_rookiss] Part2: DirectX12

24. Multi Render Target

by 헛둘이 2023. 2. 4.

- 멀티 렌더타겟은 CCTV같이 화면 안에 화면을 표현할 때 주로 사용되는 기술이다.

- 하나 더 주요한 기능은 텍스쳐에 정보를 저장할 수 있다는 것인데,

- 원래 기존에 픽셀 쉐이더의 결과물이 단순히 색상값이었다면,

- 멀티 렌더타겟을 통해 텍스쳐에 픽셀 쉐이더의 결과를 저장하면 이후에 이 텍스쳐를 통해 그 정보를 재사용할 수 있다.

- 어떤 이점이 있는가?

- A라는 정보를 B, C, D라는 텍스쳐에 적용하고 싶은데 각각 적용하려면 전부 렌더링파이프라인을 처음부터 거쳐서 하나 하나 처리해야 한다.

- 그런데 텍스쳐에 저장해놓으면 한 번 계산된 값을 돌려쓸 수 있는 장점이 생겨서 성능 향상에 도움이 된다.

- 이런 기법을 Deferred Rendering 기법이라고 하고, 기존에 우리가 사용한 방법은 Forward Rendering이라고 한다.

 

struct PS_OUT
{
    float4 position : SV_Target0;
    float4 normal : SV_Target1;
    float4 color : SV_Target2;
};


PS_OUT PS_Main(VS_OUT input)
{
    
    PS_OUT output = (PS_OUT) 0;
    
    float4 color = float4(1.f, 1.f, 1.f, 1.f);
    
    if (g_tex_on_0)
        color = g_tex_0.Sample(g_sam_0, input.uv);
    
    float3 viewNormal = input.viewNormal;
    if (g_tex_on_1)
    {
        // [0~255] 범위에서 [0~1]로 변환
        float3 tangentSpaceNormal = g_tex_1.Sample(g_sam_0, input.uv).xyz;
        // [0~1]을 [-1~1] 범위로 변환
        tangentSpaceNormal = (tangentSpaceNormal - 0.5f) * 2.f;
        // 좌표계 변환 행렬 계산
        float3x3 matTBN = { input.viewTangent, input.viewBinormal, input.viewNormal };
        viewNormal = normalize(mul(tangentSpaceNormal, matTBN));
    }

    output.position = float4(input.viewPos.xyz, 0.f);
    output.normal = float4(viewNormal.xyz, 0.f);
    output.color = color;
    
    return output;
}

- PS_OUT이라는 구조체에 위치값, 노멀값, 색상값을 저장해서 반환하면 그 텍스쳐에 해당 정보가 그려진다.

 

 

#pragma region UI_Test
	for (int i = 0; i < 3; ++i)
	{
		shared_ptr<GameObject> sphere = make_shared<GameObject>();
		sphere->SetLayerIndex(GET_SINGLE(SceneManager)->LayerNameToIndex(L"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"Forward");
			shared_ptr<Texture> texture = GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::G_BUFFER)->GetRTTexture(i);
			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 Test라는 항목에 Texture를 세팅하는 부분에 보면 여기서는 화면에 그려질 이미지를 저장한 텍스쳐를 넣어주는 것을 알 수 있다.

- 그래서 실행해보면 이 UI 3개 항목에 화면의 특정 정보가 그려지는 것을 확인할 수 있다.

 

 

 


이 작업을 하면서 기존에 SwapChain에서 관리하던 RenderTargetView와, DepthStencilBuffer 클래스에서 관리하는 내용들을 전부 RenderTargetGroup이라는 클래스에서 관리하게 되었다.

 

Texture는 그냥 사이즈와 타입만 가지고 화면 사이즈의 픽셀덩어리를 생성할 수 있게끔 Create라는 함수를 내부적으로 가지고 있게 되었고,

또 별도로 SwapChain을 생성하면 함께 동봉되는 Texture를 받아서 사용할 수 있도록 CreateFromResource 함수를 만들었다.

 

이걸 Resource Manager에서도 바로 적용할 수 있도록 함수를 래핑해서 Resource Manager에도 추가해주었다.

 

public:
	// 디퍼드 쉐이더에서 각종 값들을 받아줄 텍스쳐를 로드하는건 좀 오바니까
	// 만들어서 사용하기 위한 함수
	void Create(DXGI_FORMAT format, uint32 width, uint32 height,
		const D3D12_HEAP_PROPERTIES& heapProperty, D3D12_HEAP_FLAGS heapFlags,
		D3D12_RESOURCE_FLAGS resFlags, Vec4 clearColor = Vec4());

	// 리소스를 받아서 텍스쳐를 만들어주는 경우 (스왑 체인같은 경우)
	// SwapChain의 경우 내부에 리소스가 생성되서 그걸 받아와서 사용했음
	// 그 리소스를 받아서 텍스쳐 인스턴스를 생성하는 함수
	void CreateFromResource(ComPtr<ID3D12Resource> tex2D);

 

 

- 그리는 순서는 Scene의 Render에서 우선 G_BUFFER에 그리고 나서, (정보를 담는 버퍼)

- SwapChain의 후면 버퍼에 그린다.

void Scene::Render()
{
	PushLightData();

	int8 backIndex = GEngine->GetSwapChain()->GetBackBufferIndex();
	GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::SWAP_CHAIN)->ClearRenderTargetView(backIndex);

	GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::G_BUFFER)->ClearRenderTargetView();

	for (auto& gameObject : _gameObjects)
	{
		if (nullptr == gameObject->GetCamera())
			continue;

		gameObject->GetCamera()->SortGameObject();

		// Deferred OMSet
		GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::G_BUFFER)->OMSetRenderTargets();
		gameObject->GetCamera()->Render_Deferred();

		// Light OMSet

		// SwapChain OMSet
		GEngine->GetRTGroup(RENDER_TARGET_GROUP_TYPE::SWAP_CHAIN)->OMSetRenderTargets(1, backIndex);
		gameObject->GetCamera()->Render_Forward();
	}
}

 

 

'DirectX > [Inflearn_rookiss] Part2: DirectX12' 카테고리의 다른 글

26. Particle System_1  (0) 2023.02.13
25. Compute Shader  (0) 2023.02.12
23. Orthographic Projection  (0) 2023.02.02
22. Quaternion - 개념과 사용 방법  (0) 2023.02.01
21. Quaternion - 로드리게스 회전  (0) 2023.01.31

댓글