[DirectX] Output Merge
in Study on WinAPI&DirectX
쉐이더의 마지막 단계인 Output Merge (이하 OM)단계를 위해서
Depth Stencil State와 Blend State를 지정해주어야 한다.
Depth Stencil State
오브젝트의 픽셀 하나하나 마다 깊이 값이 지정되어있다. 여기서 지정된 깊이값을 비교하면서 어떤 색상을 출력할지 판정을 한다.
깊이 판정을 하는 경우는 아래와 같다.
- Less : 제일 기본 옵션, 카메라에서 더 가까운 경우 출력
- Less_equal : Less 옵션에서 같은 깊이 값을 가진 경우까지 출력
- Greater : 오히려 카메라에서 더 멀리 있는 경우가 출력된다.
- Greater_equal : Greater 옵션에서 같은 깊이 값을 가진 경우까지 출력
Blend State
입력된 색상을 어떤 효과를 주어서 출력할 지 결정하는 단계이다.
- DEFAULT : 기본적으로, 블렌딩을 진행하지 않고 그 색상 그대로 출력한다.
- MASK : 알파 블렌드에서 AlphaCoverage 옵션은 true인 상태
- ALPHABLEND : 투명도를 부여한다. 기존 색상과 뒤에 있는 색상을 섞어 출력한다.
- ONE_ONE : 1대1 비율로 혼합해서 출력함. 검은 배경의 이미지에서 주로 사용.
define 헤더의 변화
DS State와 BS State의 종류를 지정해준다.
// 코드 추가
enum class DS_TYPE
{
LESS,
LESS_EQUAL,
GREATER,
GREATER_EQUAL,
NO_WRITE, // LESS 판정, DepthWrite는 하지않음.
NO_TEST_NO_WRITE, // 깊이 테스트도 하지 않음.
END
}
enum class BS_TYPE
{
DEFAULT, // No Blending
MASK, // Alpha Coverage 옵션 킨 것
ALPHA_BLEND, // Alpha 계수
ONE_ONE, // 1대 1 혼합
END
}
CDevice 클래스의 변화
// 헤더파일 코드 추가
private:
// DepthStencilState
ComPtr<ID3D11DepthStencilState> m_DSState[(UINT)DS_TYPE::END];
// BlendState
ComPtr<ID3D11BlendState> m_BSState[(UINT)BS_TYPE::END];
private:
int CreateBlendState();
int CreateDepthStencilState();
// cpp파일
int CDevice::CreateDepthStencilState()
{
// Less
m_DSState[(UINT)DS_TYPE::LESS] = nullptr;
// Less Equal
D3D11_DEPTH_STENCIL_DESC Desc = {};
Desc.DepthEnable = true;
Desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
Desc.StencilEnable = false;
Desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
DEVICE->CreateDepthStencilState(&Desc, m_DSState[(UINT)DS_TYPE::LESS_EQUAL].GetAddressOf());
// Greater
Desc.DepthEnable = true;
Desc.DepthFunc = D3D11_COMPARISON_GREATER;
Desc.StencilEnable = false;
Desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
DEVICE->CreateDepthStencilState(&Desc, m_DSState[(UINT)DS_TYPE::GREATER].GetAddressOf());
// Greater Equal
Desc.DepthEnable = true;
Desc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL;
Desc.StencilEnable = false;
Desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
DEVICE->CreateDepthStencilState(&Desc, m_DSState[(UINT)DS_TYPE::GREATER_EQUAL].GetAddressOf());
// No Write
Desc.DepthEnable = true;
Desc.DepthFunc = D3D11_COMPARISON_LESS;
Desc.StencilEnable = false;
Desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
DEVICE->CreateDepthStencilState(&Desc, m_DSState[(UINT)DS_TYPE::NO_WRITE].GetAddressOf());
// NoTest NoWrite
Desc.DepthEnable = false;
Desc.StencilEnable = false;
Desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
DEVICE->CreateDepthStencilState(&Desc, m_DSState[(UINT)DS_TYPE::NO_TEST_NO_WRITE].GetAddressOf());
return S_OK;
}
int CDevice::CreateBlendState()
{
// No Blend
m_BSState[(UINT)BS_TYPE::DEFAULT] = nullptr;
// Mask
D3D11_BLEND_DESC Desc = {};
Desc.AlphaToCoverageEnable = true;
Desc.IndependentBlendEnable = false;
Desc.RenderTarget[0].BlendEnable = false;
DEVICE->CreateBlendState(&Desc, m_BSState[(UINT)BS_TYPE::MASK].GetAddressOf());
// Alpha Blend
Desc.AlphaToCoverageEnable = false;
Desc.IndependentBlendEnable = false;
Desc.RenderTarget[0].BlendEnable = true;
Desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
Desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
Desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
Desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
DEVICE->CreateBlendState(&Desc, m_BSState[(UINT)BS_TYPE::ALPHA_BLEND].GetAddressOf());
// One One
Desc.AlphaToCoverageEnable = false;
Desc.IndependentBlendEnable = false;
Desc.RenderTarget[0].BlendEnable = true;
Desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
Desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
Desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
Desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
Desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
Desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
Desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
DEVICE->CreateBlendState(&Desc, m_BSState[(UINT)BS_TYPE::ONE_ONE].GetAddressOf());
return S_OK;
}
각 상황에 맞는 DS State와 BS State를 제작한다.
그리고 DepthStencilState와 BlendState를 Device에서 생성, 호출한다.
Alpha Blend 사용하기
CResMgr.cpp
CResMgr.cpp에서 CreateDefaultGraphicsShader에서 SetBSType를 통해 ALPHABLEND로 세팅해준다.
Ptr<CGraphicsShader> pShader = nullptr;
// ===========
// Test Shader
// ===========
pShader = new CGraphicsShader;
pShader->SetKey(L"TestShader");
pShader->CreateVertexShader(L"shader\\test.fx", "VS_Test");
pShader->CreatePixelShader(L"shader\\test.fx", "PS_Test");
pShader->SetRSType(RS_TYPE::CULL_NONE);
pShader->SetDSType(DS_TYPE::NO_WRITE); // 깊이 테스트 진행, 깊이 기록 X
pShader->SetBSType(BS_TYPE::ALPHA_BLEND);
pShader->SetDomain(SHADER_DOMAIN::DOMAIN_TRANSPARENT);
AddRes(L"TestShader", pShader);
CGraphicsShader.cpp
CGraphicsShader.cpp에서 UpdataData함수도 수정해준다.
CONTEXT->IASetInputLayout(m_Layout.Get());
CONTEXT->IASetPrimitiveTopology(m_eTopology);
CONTEXT->VSSetShader(m_VS.Get(), nullptr, 0);
//CONTEXT->HSSetShader(m_HS.Get(), nullptr, 0);
//CONTEXT->DSSetShader(m_DS.Get(), nullptr, 0);
//CONTEXT->GSSetShader(m_GS.Get(), nullptr, 0);
CONTEXT->PSSetShader(m_PS.Get(), nullptr, 0);
CONTEXT->RSSetState(CDevice::GetInst()->GetRSState(m_RSType).Get());
CONTEXT->OMSetDepthStencilState(CDevice::GetInst()->GetDSState(m_DSType).Get(), 0);
CONTEXT->OMSetBlendState(CDevice::GetInst()->GetBSState(m_BSType).Get(), Vec4(0.f, 0.f, 0.f, 0.f), 0xffffffff);