DirectX/[AssortRock] DirectX11 2D

230116_D2D 삼각형 그리기

헛둘이 2023. 1. 16. 19:50

D3DCompileFromFile은 쉐이더코드를 컴파일해서 바이너리로 만들어주는 함수
ID3DBlob에 저장됨

ID3DBlob은 컴파일된 쉐이더 코드를 저장하는데 사용된다.

 

1. Device, Context 생성

 - 초기화 단계
2. SwapChain 생성

 - 생성되면서 BackBuffer를 가져오고 GetBuffer 함수를 통해 가져올 수 있다.
3. SwapChain을 통해 RenderTargetView 생성

 - 가져온 BackBuffer를 통해 RenderTargetView를 생성할 수 있다.

4. 쉐이더 컴파일 및 쉐이더 생성 (Vertex, Pixel)

 - 쉐이더 코드 컴파일 (ID3DBlob에 저장됨) 후 그 코드를 통해 Shader를 만들 수 있다.

ID3DBlob* vsBlob;
ID3D11VertexShader* vertexShader;
{
    ID3DBlob* shaderCompileErrorsBlob;
    HRESULT hResult = D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr, "vs_main", "vs_5_0", 0, 0, &vsBlob, &shaderCompileErrorsBlob);
    if(FAILED(hResult))
    {
        const char* errorString = NULL;
        if(hResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
            errorString = "Could not compile shader; file not found";
        else if(shaderCompileErrorsBlob){
            errorString = (const char*)shaderCompileErrorsBlob->GetBufferPointer();
            shaderCompileErrorsBlob->Release();
        }
        MessageBoxA(0, errorString, "Shader Compiler Error", MB_ICONERROR | MB_OK);
        return 1;
    }

    hResult = d3d11Device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, &vertexShader);
    assert(SUCCEEDED(hResult));
}

 

5. InputLayout 생성 (쉐이더에 전달할 데이터 규격 정의)

ID3D11InputLayout* inputLayout;
{
    D3D11_INPUT_ELEMENT_DESC inputElementDesc[] =
    {
        { "POS", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "COL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
    };

    HRESULT hResult = 
        d3d11Device->CreateInputLayout(
            inputElementDesc, 
            ARRAYSIZE(inputElementDesc),
            vsBlob->GetBufferPointer(), 
            vsBlob->GetBufferSize(), 
            &inputLayout);

    assert(SUCCEEDED(hResult));
    vsBlob->Release();
}


6. Vertex Buffer를 통해 정점 전달

ID3D11Buffer* vertexBuffer;
UINT numVerts;
UINT stride;
UINT offset;
{
    float vertexData[] = { // x, y, r, g, b, a
        0.0f,  0.5f, 0.f, 1.f, 0.f, 1.f,
        0.5f, -0.5f, 1.f, 0.f, 0.f, 1.f,
        -0.5f, -0.5f, 0.f, 0.f, 1.f, 1.f
    };
    stride = 6 * sizeof(float);
    numVerts = sizeof(vertexData) / stride;
    offset = 0;

    D3D11_BUFFER_DESC vertexBufferDesc = {};
    vertexBufferDesc.ByteWidth = sizeof(vertexData);
    vertexBufferDesc.Usage     = D3D11_USAGE_IMMUTABLE;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;

    D3D11_SUBRESOURCE_DATA vertexSubresourceData = { vertexData };

    HRESULT hResult = d3d11Device->CreateBuffer(&vertexBufferDesc, &vertexSubresourceData, &vertexBuffer);
    assert(SUCCEEDED(hResult));
}


7. ViewPort 정의 (Rasterizer 단계): 화면에 표시할 영역 설정

RECT winRect;
GetClientRect(hwnd, &winRect);
D3D11_VIEWPORT viewport = { 0.0f, 0.0f, (FLOAT)(winRect.right - winRect.left), (FLOAT)(winRect.bottom - winRect.top), 0.0f, 1.0f };
d3d11DeviceContext->RSSetViewports(1, &viewport);


8. RenderTarget에 연결시키기

d3d11DeviceContext->OMSetRenderTargets(1, &d3d11FrameBufferView, nullptr);


9. Context의 ubResource 구조체에 Map을 통해 데이터를 묶어준다.(정점 버퍼와, 쓰기 등 옵션)
 - 뚜껑을 열고 닫는 느낌
 - 복사가 끝나면 Unmap을 뚜껑을 닫아준다

(튜토리얼 예제에서는 없었으나 필요한 공정)

 

10. Context의 IASetVertexBuffer를 통해 버퍼를 전달한다

d3d11DeviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);


11. Context의 IAInputLayout으로 레이아웃(쉐이더에 데이터 규격 명세) 전달

d3d11DeviceContext->IASetInputLayout(inputLayout);


12. Context의 IASetPrimitiveTopology를 통해 어떻게 그릴 것인지 전달(보통 게임은 삼각형)

d3d11DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);


13. Context의 VSSetShader, PSSetShader로 만들어둔 쉐이더 전달 (쉐이더는 컴파일된 바이너리로 생성됨)

d3d11DeviceContext->VSSetShader(vertexShader, nullptr, 0);
d3d11DeviceContext->PSSetShader(pixelShader, nullptr, 0);


14. Context의 Draw를 통해 RenderTarget에 그려준다

d3d11DeviceContext->Draw(numVerts, 0);


15. RenderTarget에 그려진 그림을 Present를 통해 Blt 또는 Flip으로 화면에 뿌려준다

d3d11SwapChain->Present(1, 0);