오늘은 블렌딩 클래스의 코드를 분석해보자.

우선 실행을 해보면 키보드에서 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 즉 최종적인 색상에 안개의 색상을 섞에서 반환해주면 된다.

+ Recent posts