230116_D2D 삼각형 그리기
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);