C++ Algorithm & Study/Game Math & DirectX 11

[Direct11] 10. Direct3D Effect Framework

GameChoi 2023. 6. 14. 19:30

1. Direct3D Effect Framework

1.1 Effect Framework

 - 특정한 렌더링 효과를 구현하는 데 함께 쓰이는 셰이더 프로그램

   - 렌더 상태들을 효과라고 부르는 단위로 조직화하고 관리하는 틀을 제공하는 편의용 코드 집합

     - 물을 렌더링하기 위한 셰이더 프로그램들과 렌더 상태들을 하나의 효과로 둘 수 있음

       - 구름, 금속 물체, 캐릭터 애니메이션을 위한 것들을 각각 개별적인 효과로 두어서 관리

         - 하나의 효과는 하나의 정점 셰이더 & 하나의 픽셀 셰이더, 그 효과를 구현하는데 필요한 렌더 상태로 이루어짐

1.1.1 Effect File

 - 셰이더 코드와 상수 버퍼의 내용을 담을 뿐아니라 하나의 기법 정의 & 패스를 포함

   - technique11로 시작하는 Section은 하나의 기법을 정의

     - 특정 렌더링 기법을 구현하는 데 쓰이는 하나 이상의 패스들로 구성

       - 각 패스마다 기하구조를 다른 방식으로 렌더링 & 각 패스의 결과를 특정 방식으로 결합

   - pass로 시작하는 Section은 하나의 패스를 정의

     - 하나의 패스는 하나의 정점 셰이더 & 픽셀 셰이더, 렌더 상태로 구성

       - 추가적으로 기하 셰이더와 테셀레이션 관련 셰이더들이 포함될 수 있음

         - 이 패스에서 기하구조를 어떻게 처리하고 색을 입힐 것인지 규정

technique11 ColorTech
{
    pass PO
    {
        SetVertexShader(CompileShader(vs_5_0, VS()));
        SetPixelShader(CompileShader(ps_5_0, PS()));
    }
}

   - Render State 또한 패스의 한 구성요소

     - 직접 상태 집합을 생성하고 설정하는 것이 가능하고 구체적인 렌더 상태하에서 작동하는 효과에 유용

RasterizerState WireframeRS { FillMode = Wireframe; CullMode = Back; FrontCounterClockwise = false; }
technique11 ColorTech
{
technique11 T0
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_5_0, VS()));
        SetPixelShader(CompileShader(ps_5_0, PS()));
        
        SetRasterizerState(WireframeRS);
    }
}

1.1.2 Complie Shader

 - 위의 설정 효과를 실제로 사용하려면 fx파일 안에 셰이더 프로그램들을 컴파일해야 함

   - 밑의 함수를 사용하여 컴파일 실행

HRESULT D3DX11CompileFromFile;

     - File Name, Shader Main Function, Shader Version, Blob 구조체 등 필요

   - 효과 파일에 대해 성공적으로 컴파일이 된다면 다음 함수를 이용하여 효과 자체를 나타내는 객체를 생성

HRESULT D3DXllCreateEffectFromMemory;

 - Direct3D 자원의 생성은 비용이 큰 연산이므로 항상 응용 프로그램의 주 루프가 아닌 초기화 시점에 수행

1.1.3 C++ Code & Effect File

 - 응용 프로그램은 상수 버퍼의 변수들을 갱신

   - 밑의 코드와 같이 상수 버퍼가 정의되어 있으면 효과 객체를 통해 상수 버퍼 변수에 대한 포인터를 얻음

cbuffer cbPerObject { float4x4 gWVP; }
ID3DXllEffectMatrixVariable* fxWVPVar;
fxWVPVar = mFX->GetVariableByName("gWVP")->AsMatrix();

   - 위의 코드로 인해 상수 버퍼에 대한 포인터를 알 수 있으므로 포인터를 사용하여 값 변경

fxWVPVar->SetMatrix((float*)&M);

     - 효과 객체의 내부 캐시가 갱신되는 것일 뿐 GPU메모리에 있는 실제 상수 버퍼가 갱신되는 것은 아님

       - 실질적인 갱신은 렌더링 패스를 수행할 때 일어남
   - 렌더링을 수행하려면 효과 객체에 있는 기법 객체를 가리키는 포인터도 얻어야 함

ID3DXllEffectTechnique* mTech; mTech = mFX->GetTechniqueByName("ColorTech");

1.1.4 Effect File & Drawing

 - 상수 버퍼의 변수들을 적절히 갱신 후 루프로 기법의 각 패스를 훑으면서 각 패스를 적용하여 기하구조를 그림

   - 하나의 패스에서 기하구조를 그릴 때에는 그 패스에 설정된 셰이더들과 렌더 상태들이 적용

     - 주어진 Index를 가리키는 포인터를 사용하여 GPU 메모리에 저장된 상수 버퍼를 새 변수 값들로 갱신

     - 패스에 설정된 셰이더 프로그램들을 파이프라인에 묶고, 패스에 설정된 렌더 상태들을 적용

for (uint32 p = 0; p < techDesc.Passes; ++p)
{
    _tech->GetPassByIndex(p)->Apply(0, _deviceContext.Get());
    _deviceContext->DrawIndexed(36, 0, 0);
}