DX11 HLSL과 Input Layout 연결
C++ 정점 구조체가 Shader 입력으로 들어가는 과정
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
DirectX 11에서 정점 버퍼만 만든다고 삼각형이 나타나지는 않는다. 정점의 위치를 처리하는 Vertex Shader와 픽셀 색을 결정하는 Pixel Shader가 필요하다.
기본 HLSL
struct VSInput
{
float3 Position : POSITION;
float4 Color : COLOR;
};
struct VSOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR;
};
VSOutput VSMain(VSInput Input)
{
VSOutput Output;
Output.Position = float4(Input.Position, 1.0f);
Output.Color = Input.Color;
return Output;
}
float4 PSMain(VSOutput Input) : SV_TARGET
{
return Input.Color;
}
POSITION과 COLOR는 C++ 정점 데이터가 어떤 의미인지 알려주는 Semantic이다. SV_POSITION은 래스터라이저가 반드시 필요로 하는 화면 위치이고, SV_TARGET은 렌더 타깃에 기록할 색이다.
Shader 컴파일
ID3DBlob* VSBlob = nullptr;
ID3DBlob* PSBlob = nullptr;
ID3DBlob* ErrorBlob = nullptr;
D3DCompileFromFile(
L"Triangle.hlsl", nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"VSMain", "vs_5_0", 0, 0, &VSBlob, &ErrorBlob
);
D3DCompileFromFile(
L"Triangle.hlsl", nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE,
"PSMain", "ps_5_0", 0, 0, &PSBlob, &ErrorBlob
);
Device->CreateVertexShader(
VSBlob->GetBufferPointer(), VSBlob->GetBufferSize(),
nullptr, &VertexShader
);
Device->CreatePixelShader(
PSBlob->GetBufferPointer(), PSBlob->GetBufferSize(),
nullptr, &PixelShader
);
컴파일이 실패하면 ErrorBlob의 문자열을 출력해야 원인을 알 수 있다. 파일 경로나 Entry Point 오타를 확인하지 않고 HRESULT만 보면 디버깅하기 어렵다.
Input Layout 연결
D3D11_INPUT_ELEMENT_DESC Elements[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,
0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,
0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
Device->CreateInputLayout(
Elements,
static_cast<UINT>(std::size(Elements)),
VSBlob->GetBufferPointer(),
VSBlob->GetBufferSize(),
&InputLayout
);
C++ Vertex 구조체의 실제 메모리 배치와 Input Layout의 Format, Offset이 같아야 한다. Position은 12 Byte이므로 Color의 Offset은 12다.
DX11 삼각형 예제의 핵심은 API 호출을 외우는 것이 아니다. CPU의 정점 구조체, Input Layout, Vertex Shader 입력이 정확히 같은 계약을 가져야 한다는 점이다.