DirectX 11 스터디 - 래스터라이저 스테이트, 샘플 스테이트, 블렌드 스테이트
1. 래스터라이저 스테이트를 생성/설정하고 Render() 함수에서 전달해준다.
ID3D11RasterizerState 를 생성하고, ~_DESC 에 설정값을 담아 생성한다.
그리고 Render() 함수에서 Pixel Shader 에 적용되도록 전달함.
ComPtr<ID3D11RasterizerState> _rasterizerState;
void Game::CreateRasterizerState()
{
D3D11_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_BACK;
desc.FrontCounterClockwise = false; // 시계방향/반시계방향 = Clockwise / CounterClockwise
HRESULT hr = _device->CreateRasterizerState(&desc, _rasterizerState.GetAddressOf());
CHECK(hr);
}
Render()
{
// ...
// Vertex Shader
_deviceContext->VSSetShader(_vertexShader.Get(), nullptr, 0);
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
// Rasterizer Stage
_deviceContext->RSSetState(_rasterizerState.Get());
// Pixel Shader
_deviceContext->PSSetShader(_pixelShader.Get(), nullptr, 0);
_deviceContext->PSSetShaderResources(0, 1, _shaderResourceView0.GetAddressOf());
_deviceContext->PSSetShaderResources(1, 1, _shaderResourceView1.GetAddressOf());
// ...
}
위 CreateRasterizerState() 에서 FillMode 를 ~_WIREFRAME 으로 설정하면 아래와 같이 폴리손의 와이어프레임을 볼 수 있음.
2. SamplerState, BlendState
이번에는 샘플러 스테이트(SamplerState)와 블랜드 스테이트(BlendState) 를 생성해서 연결해준다.
모든 디바이스 오브젝트와 동일한 절차로 생성해준다. 아래처럼 껍데기를 먼저 만들어주고, _DESC 를 적절한 값들로 채우면 된다. 이쯤되면 Device::Create~ 시리즈들은 인터페이스일 뿐이고, 진짜 중요한 내용들은 모두 ~_DESC 구조체 안에 들어있다 보면 됨.
ComPtr<ID3D11BlendState> _blendState;
ComPtr<ID3D11SamplerState> _samplerState;
void Game::CreateSamplerState()
{
D3D11_SAMPLER_DESC desc;
HRESULT hr = _device->CreateSamplerState(&desc, _samplerState.GetAddressOf());
}
void Game::CreateBlendSTate()
{
D3D11_BLEND_DESC desc;
HRESULT hr = _device->CreateBlendState(&desc, _blendState.GetAddressOf());
}
먼저 SamplerState 는 PiexelShader 에 넘겨주는 샘플러스테이트 그것이 맞다. 기존에 만들었전 픽셀셰이더 코드를 다시 보면 이렇게 생김. 여기서 s0~ 레지스터로 넘어가는 SamplerState 가 그것. 텍스쳐를 어떻게 샘플링 할지에 대한 규칙이 담겨있음.
Texture2D texture0 : register(t0); // t0, s0 은 레지스터 이름.
Texture2D texture1 : register(t1); // t0, s0 은 레지스터 이름.
SamplerState sampler0 : register(s0);
float4 PS(VS_OUTPUT input) : SV_Target
{
//return input.color;
//float4 color = ceil(input.color * 5) / 5.0f;
float4 color = texture0.Sample(sampler0, input.uv);
color = color * texture1.Sample(sampler0, input.uv);
return color;
}
D3D11_SAMPLER_DESC 내용을 적절히 채우고 변경해가면서 설정값을 이해하는 게 중요. 아래는 샘플 설정값. 텍스쳐 샘플링 필터 옵션과 UVW 주소 모드, BORDER 모드일 때의 Border 색상값 등의 설정을 담아준다. AddressU,V,W 모드를 ~_WRAP 으로 설정하면, 유니티엔진 등에서 볼 수 있는 Tiling 옵션으로 동작함.
void Game::CreateSamplerState()
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
desc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
desc.BorderColor[0] = 1;
desc.BorderColor[1] = 0;
desc.BorderColor[2] = 0;
desc.BorderColor[3] = 1;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MaxAnisotropy = 16;
desc.MaxLOD = FLT_MAX;
desc.MinLOD = FLT_MIN;
desc.MipLODBias = 0.0f;
HRESULT hr = _device->CreateSamplerState(&desc, _samplerState.GetAddressOf());
}
Render()
{
...
// Pixel Shader
...
_deviceContext->PSSetSamplers(0, 1, _samplerState.GetAddressOf()); //< 여기 추가
...
}
~_MIRROR 는 좌우 대칭이 반복되고, CLAMP 는 자르기, BORDER 는 경계 바깥을 BorderColor 로 채우는 모드 등.
아래는 D3D11_SAMPLER_DESC 구조체 API 문서.
https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/ns-d3d11-d3d11_sampler_desc
마지막으로 BlendState 생성.
말 그대로 텍스쳐를 블랜딩하는 옵션을 설정해줄 수 있는 상태. BlendState 를 생성하고 Output Merger 단계에서 사용할 수 있도록 Render() 함수에서 전달을 해주면 됨. 다른 오브젝트들과 마찬가지로 D3D11_BLEND_DESC 를 생성해서 적절히 설정해주면 되는데, 자세한 설명은 스킵하고 아래 샘플처럼 적당히 설정하고 진행하도록 함.
void Game::CreateBlendSTate()
{
D3D11_BLEND_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.AlphaToCoverageEnable = false;
desc.IndependentBlendEnable = false;
desc.RenderTarget[0].BlendEnable = true;
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
HRESULT hr = _device->CreateBlendState(&desc, _blendState.GetAddressOf());
CHECK(hr);
}
Render()
{
...
// Output Merger
_deviceContext->OMSetBlendState(_blendState.Get(), nullptr, 0xFFFFFF);
...
}
블랜드 스테이트로 알파블랜딩 설정을 하고 다시 실행해보면, 아래 이미지와 같이 검은색 영역이 투명하게 뚫려서 보이는 걸 확인할 수 있음.
아래는 D3D11_BLEND_DESC 구조체 API 문서
https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/ns-d3d11-d3d11_blend_desc
그리고 BLEND_DESC 의 핵심인 D3D11_RENDER_TARGET_BLEND_DESC 구조체
https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/ns-d3d11-d3d11_render_target_blend_desc
.
참조
OutputMerger(출력 병합기) State
정리
RS, SS, BS 즉, RasterizerState, SamplerState, BlendState 는 옵셔널한 성격이 있기 때문에 디폴트로 동작하는 셋팅이 있어서 설정하지 않아도 기본 렌더 파이프라인은 동작함. 세부 설정 변경이 필요한 경우에 추가해서 사용하면 되는 것들이기 때문에 기억하고 있을 필요는 있음.
기본적인 렌더링 파이프라인 객체들을 먼저 완전히 익힌 뒤에 RS, SS, BS 를 익히는 것이 정석적인 순서.
<리얼-타임 렌더링(REAL-TIME RENDERING) 4/e> 구입 링크
https://link.coupang.com/a/8VWas
<DirectX 12를 이용한 3D 게임 프로그래밍 입문> 구입 링크
https://link.coupang.com/a/8V4Wq
유니티 에셋 스토어 링크
https://assetstore.unity.com?aid=1011lvz7h
(링크를 통해 도서/에셋 구입시 일정액의 수수료를 지급받습니다.)