MOONSUN
[D3D] DirectX 11에서 HLSL 셰이더 컴파일 2가지 방법 본문
셰이더 ( Shader )
DirectX에서 셰이더는 GPU에서 실행되는 작은 프로그램
- 버텍스 셰이더(Vertex Shader, VS): 정점 데이터를 받아서 변환
- 픽셀 셰이더(Pixel Shader, PS): 픽셀 단위로 색상을 계산
셰이더는 HLSL 파일(.hlsl)로 작성된다.
하지만 GPU가 바로 HLSL 코드를 이해하지 못하기 때문에 컴파일이 필요하다.
DirectX 11에서
HLSL(High-Level Shader Language) 셰이더를 컴파일하는 방법은 2가지가 있다.
1. 런타임 컴파일 (D3DCompile)
- 프로그램이 실행될 때 .hlsl 파일을 읽어서 바로 컴파일
- 장점: 수정 후 바로 테스트 가능
- 단점: 실행 시 컴파일 오버헤드, 배포 시 HLSL 파일 필요
2. 사전 컴파일 (.cso, Compiled Shader Object)
- Visual Studio나 fxc.exe로 미리 컴파일해 .cso 파일로 생성
- 프로그램 실행 시 바로 로드
- 장점: 빠름, 배포 시 HLSL 파일 필요 없음
- 단점: HLSL 수정 후 다시 빌드해야 함
현재 나는 개발 편의성을 위해 런타임에 컴파일하는 방식을 사용하고 있고,
배포용으로는 .cso를 미리 만들어서 사용하는 것이 일반적이라고 한다.
다음과 같이 런타임 컴파일을 진행하고 있다.
// [ HLSL 셰이더를 파일에서 컴파일 ]
HRESULT CompileShaderFromFile(
const WCHAR* szFileName, // 셰이더 파일 이름
LPCSTR szEntryPoint, // 진입점 함수 (ex. "main")
LPCSTR szShaderModel, // 셰이더 모델 (ex. "ps_5_0")
ID3DBlob** ppBlobOut // 결과 셰이더 바이트코드
);
HRESULT CompileShaderFromFile(const WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
// 디버그 모드일 경우: 디버깅을 쉽게 하기 위해 최적화 끔
dwShaderFlags |= D3DCOMPILE_DEBUG;
dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
ID3DBlob* pErrorBlob = nullptr;
hr = D3DCompileFromFile(szFileName, nullptr, D3D_COMPILE_STANDARD_FILE_INCLUDE, szEntryPoint, szShaderModel,
dwShaderFlags, 0, ppBlobOut, &pErrorBlob);
if (FAILED(hr))
{
if (pErrorBlob)
{
MessageBoxA(NULL, (char*)pErrorBlob->GetBufferPointer(), "CompileShaderFromFile", MB_OK);
pErrorBlob->Release();
}
return hr;
}
if (pErrorBlob) pErrorBlob->Release();
return S_OK;
}
// ================================================================
// 버텍스 셰이더(Vertex Shader) 컴파일 및 생성
// ================================================================
ComPtr<ID3DBlob> vertexShaderBuffer; // 컴파일된 버텍스 셰이더 코드(hlsl) 저장 버퍼
// ' HLSL 파일에서 main 함수를 vs_4_0 규격으로 컴파일 '
HR_T(CompileShaderFromFile(L"RectangleVertexShader.hlsl", "main", "vs_4_0", vertexShaderBuffer.GetAddressOf()));
// 버텍스 셰이더 객체 생성
HR_T(m_pDevice->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), nullptr, m_pVertexShader.GetAddressOf()));
// ================================================================
// 픽셀 셰이더(Pixel Shader) 컴파일 및 생성
// ================================================================
ComPtr<ID3DBlob> pixelShaderBuffer; // 컴파일된 버텍스 픽셀 코드(hlsl) 저장 버퍼
// ' HLSL 파일에서 main 함수를 ps_4_0 규격으로 컴파일 '
HR_T(CompileShaderFromFile(L"RectanglePixelShader.hlsl", "main", "ps_4_0", pixelShaderBuffer.GetAddressOf()));
// 픽셀 셰이더 객체 생성
HR_T(m_pDevice->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), nullptr, m_pPixelShader.GetAddressOf()));'D3D' 카테고리의 다른 글
| [D3D 이론] OpenGL vs DirectX 행렬 표현 차이 및 DirectX의 행렬 불일치로 인한 Transpose (0) | 2025.09.10 |
|---|---|
| [D3D 이론] 기저벡터(Basis Vector)와 행렬(Matrix) (0) | 2025.09.10 |
| [D3D] Comptr 사용해보자 (0) | 2025.09.05 |
| [D3D] Comptr(COM Smart Pointer) 란? (1) | 2025.09.05 |
| [Error] Invalid vs_2_0 output semantic 'SV_TARGET’ (0) | 2025.09.04 |