본문 바로가기

그래픽스

[그래픽스] 렌더링 엔진 구조 변경

DX12에서는 렌더링할 때 필요한 쉐이더, State들을 PSO(Pipeline State Object)에 담아서 관리한다.

DX11에서도 그 방식을 따라 구조를 변경해보도록 하자.

 

class GraphicsPSO {
  public:
    void operator=(const GraphicsPSO &pso);
    void SetBlendFactor(const float blendFactor[4]);

  public:
    ComPtr<ID3D11VertexShader> m_vertexShader;
    ComPtr<ID3D11PixelShader> m_pixelShader;
    ComPtr<ID3D11HullShader> m_hullShader;
    ComPtr<ID3D11DomainShader> m_domainShader;
    ComPtr<ID3D11GeometryShader> m_geometryShader;
    ComPtr<ID3D11InputLayout> m_inputLayout;

    ComPtr<ID3D11BlendState> m_blendState;
    ComPtr<ID3D11DepthStencilState> m_depthStencilState;
    ComPtr<ID3D11RasterizerState> m_rasterizerState;

    float m_blendFactor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
    UINT m_stencilRef = 0;

    D3D11_PRIMITIVE_TOPOLOGY m_primitiveTopology =
        D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
};

 

렌더링할 때 필요한 모든 쉐이더들, State들, primitiveTopology 들을 설정할 수 있다. 

여러가지 GraphicsPSO들을 설정하기 위해서 필요한 부품들은 GraphicsCommon에 있다. 

 

 

// Samplers
extern ComPtr<ID3D11SamplerState> linearWrapSS;
...

// Rasterizer States
extern ComPtr<ID3D11RasterizerState> solidRS;
...

// Depth Stencil States
extern ComPtr<ID3D11DepthStencilState> drawDSS; // 일반적으로 그리기
extern ComPtr<ID3D11DepthStencilState> maskDSS; // 스텐실버퍼에 표시
extern ComPtr<ID3D11DepthStencilState> drawMaskedDSS; // 스텐실 표시된 곳만

// Shaders
extern ComPtr<ID3D11VertexShader> basicVS;
...

// Input Layouts
extern ComPtr<ID3D11InputLayout> basicIL;
...

// Blend States
extern ComPtr<ID3D11BlendState> mirrorBS;

// Graphics Pipeline States
extern GraphicsPSO defaultSolidPSO;

 

PSO에 특정 상황마다 필요한 부품들, 그리고 마지막에 PSO가 선언되어 있다. 모든 변수들이 extern으로 설정되어

있으므로 cpp에서 정의를 한번 더 해줘야 한다. 이것들은 모두 Graphics namespace 안에 선언되어 있다.

 

 

void Graphics::InitCommonStates(ComPtr<ID3D11Device> &device) {

    InitShaders(device);
    InitSamplers(device);
    InitRasterizerStates(device);
    InitBlendStates(device);
    InitDepthStencilStates(device);
    InitPipelineStates(device);
}

void Graphics::InitSamplers(ComPtr<ID3D11Device> &device) {
    D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory(&sampDesc, sizeof(sampDesc));
    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
    device->CreateSamplerState(&sampDesc, linearWrapSS.GetAddressOf());
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
    device->CreateSamplerState(&sampDesc, linearClampSS.GetAddressOf());

    // 샘플러 순서가 "Common.hlsli"에서와 일관성 있어야 함
    sampleStates.push_back(linearWrapSS.Get());
    sampleStates.push_back(linearClampSS.Get());
}

 

GraphicsCommon.cpp에서 h에서 선언한 변수들을 다시 선언하고 Init 함수들로 초기화를 해준다.

sampleStates(list)에 샘플러들을 다 넣어주고 render할 때 쉐이더에 setsampler할 때 모든 sampler들을 넣어준다.

 

 

    // 거울에 반사되면 삼각형의 Winding이 바뀌기 때문에 CCW로 그려야함
    rastDesc.FrontCounterClockwise = true;
    ThrowIfFailed(
        device->CreateRasterizerState(&rastDesc, solidCCWRS.GetAddressOf()));

    rastDesc.FillMode = D3D11_FILL_MODE::D3D11_FILL_WIREFRAME;
    ThrowIfFailed(
        device->CreateRasterizerState(&rastDesc, wireCCWRS.GetAddressOf()));

    rastDesc.FrontCounterClockwise = false;
    ThrowIfFailed(
        device->CreateRasterizerState(&rastDesc, wireRS.GetAddressOf()));

 

rasterizeState도 설정에 따라 각각 다른 State에 넣어준다. 다른 State나 쉐이더도 이렇게 쭉 만들어준다.

 

 

    // defaultSolidPSO;
    defaultSolidPSO.m_vertexShader = basicVS;
    defaultSolidPSO.m_inputLayout = basicIL;
    defaultSolidPSO.m_pixelShader = basicPS;
    defaultSolidPSO.m_rasterizerState = solidRS;
    defaultSolidPSO.m_primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;

    // defaultWirePSO
    defaultWirePSO = defaultSolidPSO;
    defaultWirePSO.m_rasterizerState = wireRS;

    // stencilMarkPSO;
    stencilMaskPSO = defaultSolidPSO;
    stencilMaskPSO.m_depthStencilState = maskDSS;
    stencilMaskPSO.m_stencilRef = 1;
    stencilMaskPSO.m_pixelShader = simplePS;

 

그리고 상태들을 조합해서 각각 다른 PSO들을 만들어서 넣어주면 된다. 

'그래픽스' 카테고리의 다른 글

[그래픽스] 그림자  (0) 2023.07.23
[그래픽스] Depth Map  (0) 2023.07.23
[그래픽스] HDR 파이프라인  (0) 2023.07.22
[그래픽스] HDRI(High Dynamic Range Image)  (0) 2023.07.22
[그래픽스] Height Map  (0) 2023.07.21