오늘은 블렌딩 클래스의 코드를 분석해보자.
우선 실행을 해보면 키보드에서 1,2,3을 누르는 것에 따라 기본 색만 적용된 버전과 텍스처가 적용된 버전, 안개가 있는 버전이 출력되는 것을 볼 수 있다.
여기서 블렌딩은 안개가 적용되어서 흐릿하게 보이는 것에 적용되어 있다. 만약 물을 반투명하게 만든다면 블렌딩이 적용되어야 할 것이다.
블렌딩은 말 그대로 색을 섞는 것이다. 이 블렌딩은 OM단계에서 연산이 된다.
OM단계에서는 텍스처가 적용되어 있는 단계로 이 텍스처를 덮어쓸 지 아니면 색을 섞어 줄 지 계산 식을 통해 정해주면 된다.
텍스처클래스때와 달라진 점을 중점으로 살펴보자
우선 Init부분을 보면
Effects::InitAll(_device, L"../Shaders/10. Basic.fx");
InputLayouts::InitAll(_device);
RenderStates::InitAll(_device);
Effects를 통해 shader파일을 불러오고 InputLayouts 클래스를 통해 정점이 어떻게 생겼는지에 대한 정보를 넘겨주고 있다.
void InputLayouts::InitAll(ComPtr<ID3D11Device> device)
{
D3DX11_PASS_DESC passDesc;
//
// Basic32
//
Effects::BasicFX->Light1Tech->GetPassByIndex(0)->GetDesc(&passDesc);
HR(device->CreateInputLayout(InputLayoutDesc::Basic32, 3, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &Basic32));
//
// TreePointSprite
//
Effects::TreeSpriteFX->Light3Tech->GetPassByIndex(0)->GetDesc(&passDesc);
HR(device->CreateInputLayout(InputLayoutDesc::TreePointSprite, 2, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &TreePointSprite));
}
또한 지금 블렌딩은 리소스를 사용해주는 단계이기 때문에 그려주는 단계에서 InputLayout쪽을 설정해주는 것을 볼 수 있다.
void BlendDemo::DrawScene()
{
_deviceContext->IASetInputLayout(InputLayouts::Basic32.Get());
}
그리고 RenderStates 부분을 보면 BlendState 변수가 나오는데 여기서 블렌딩상태를 묘사하는 리소스를 만들어주고 이를 바탕으로 연산을 해주게 된다.
class RenderStates
{
public:
static ComPtr<ID3D11BlendState> AlphaToCoverageBS;
static ComPtr<ID3D11BlendState> TransparentBS;
static ComPtr<ID3D11BlendState> NoRenderTargetWritesBS;
};
결국 핵심은 이 BlendState를 어떻게 묘사하고 사용하는 지이다.
void RenderStates::InitAll(ComPtr<ID3D11Device> device)
{
//
// TransparentBS
//
D3D11_BLEND_DESC transparentDesc = { 0 };
transparentDesc.AlphaToCoverageEnable = false;
transparentDesc.IndependentBlendEnable = false;
transparentDesc.RenderTarget[0].BlendEnable = true; //블렌딩 사용
transparentDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; // src :a
transparentDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; //dst : 1-a
transparentDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; //계산 : +
transparentDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; //가중치src *1
transparentDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; //가중치dst *2
transparentDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
transparentDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
HR(device->CreateBlendState(&transparentDesc, &TransparentBS));
}
코드에서 만약 저렇게 사용한다고 하면 각 옵션의 사용법은 주석의 내용과 같다.
이렇게 묘사하는 것을 만들어주고 연결해주는 부분이 필요한데 이 부분은 OM단계의 코드를 보면 알 수 있다.
void BlendDemo::DrawScene()
{
_deviceContext->OMSetBlendState(RenderStates::TransparentBS.Get(), blendFactor, 0xffffffff);
}
그리고 쉐이더에서 안개를 구현하는 쪽 코드를 살펴보자면 아래와 같다.
if (gFogEnabled)
{
float fogLerp = saturate((distToEye - gFogStart) / gFogRange);
// Blend the fog color and the lit color.
litColor = lerp(litColor, gFogColor, fogLerp);
}
식을 보면 카메라에서 물체까지의 거리를 판별하고 안개의 시작점통해 연산을 해주는 것으로 안개가 어디서 부터 시작하고 최소 범위와 최대 범위를 통해 연산해주면 0~1사이의 값, 비율로 나오게 될 것이다. 이를 통해 litColor 즉 최종적인 색상에 안개의 색상을 섞에서 반환해주면 된다.
'게임공부 > Directx11(물방울책)' 카테고리의 다른 글
[Directx11][C++][물방울]7. Geometry Shader (1) | 2024.10.22 |
---|---|
[Directx11][C++][물방울]6. Stencil (1) | 2024.10.21 |
[Directx11][C++][물방울]4. 텍스쳐 (1) | 2024.10.18 |
[Directx11][C++][물방울]3. 조명 (3) | 2024.10.16 |
[Directx11][C++][물방울]2.Direct3D의 그리기 연산 (1) | 2024.10.15 |