[directx11]알파 블렌딩
카테고리: DirectX
알파 블렌딩
알파 블렌딩
z버퍼는 카메라의 시점을 기준으로 깊이를 나타내는 정보를 저장하는 버퍼이다.
렌더링파이프라인을 어느정도 이해하고 있다면, 프레임워크에서는 먼저 그려진
객체의 위에 나중에 그려진 객체가 그려지기 때문에

이렇게 같은 시점에서 이미지가 그려질 때, 투명도가 없으면 바로 가려진 상태로 보여지게 된다.
그렇기 때문에 투명도인 알파 값을 사용하여 뒤에 있는 물체의 RGB 색상과 혼합하게 된다.
이 과정은 OM 단계에서 이루어진다. 거두절미하고 수식을 보여주겠다.
반투명 공식
아래 식들의 back 은 new 와 같은 뜻이고, front는 old 와 동의어로 생각하면 된다.
\[R = (R_back * (1 - α) + R_front * α)\] \[G = (G_back * (1 - α) + G_front * α)\] \[B = (B_back * (1 - α) + B_front * α)\]아래는 매우 쉬운 방법으로, 2D 게임 등에서 매우 효과적이고 간단하게 투명도를 표현할 수 있다.
\(R = (R_back / 2) + (R_front / 2)\)
만약 50퍼센트의 블렌딩이 들어간다고 하면 위와 같은 수식으로 표현될 수 있는 것이다.
DirectX11에서는 아래와 같은 함수들이 사용된다.
//알파 블렌딩
D3D11_BLEND_DESC blendDesc = {};
blendDesc.AlphaToCoverageEnable = false;
blendDesc.IndependentBlendEnable = false;
blendDesc.RenderTarget[0].BlendEnable = true;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
ID3D11BlendState* blendState;
device->CreateBlendState(&blendDesc, &blendState);
deviceContext->OMSetBlendState(blendState, nullptr, 0xffffffff);
// 가산 블렌딩
D3D11_BLEND_DESC blendDesc = {};
blendDesc.AlphaToCoverageEnable = false;
blendDesc.IndependentBlendEnable = false;
blendDesc.RenderTarget[0].BlendEnable = true;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
ID3D11BlendState* blendState;
device->CreateBlendState(&blendDesc, &blendState);
deviceContext->OMSetBlendState(blendState, nullptr, 0xffffffff);
//곱셈 블렌딩
D3D11_BLEND_DESC blendDesc = {};
blendDesc.AlphaToCoverageEnable = false;
blendDesc.IndependentBlendEnable = false;
blendDesc.RenderTarget[0].BlendEnable = true;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_DEST_COLOR;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
ID3D11BlendState* blendState;
device->CreateBlendState(&blendDesc, &blendState);
deviceContext->OMSetBlendState(blendState, nullptr, 0xffffffff);
//뺄셈 블렌딩
D3D11_BLEND_DESC blendDesc = {};
blendDesc.AlphaToCoverageEnable = false;
blendDesc.IndependentBlendEnable = false;
blendDesc.RenderTarget[0].BlendEnable = true;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_REV_SUBTRACT;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
ID3D11BlendState* blendState;
device->CreateBlendState(&blendDesc, &blendState);
deviceContext->OMSetBlendState(blendState, nullptr, 0xffffffff);
위의 코드에서 blendDesc 구조체의 필드 값을 조정하면 사용자 정의 모드의 블렌딩을 구현할 수 있다.
또한, 아래의 수식으로 알파 값이 1이라면 최적화하여 알파 블렌딩을 수행하지 않도록 만들어, 오버헤드를 줄일 수 있다.
// 알파 블렌딩 설정
D3D11_BLEND_DESC blendDesc;
ZeroMemory(&blendDesc, sizeof(blendDesc));
blendDesc.RenderTarget[0].BlendEnable = TRUE;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
// 알파 값이 1인 경우에 대한 최적화 처리
blendDesc.RenderTarget[0].BlendEnable = FALSE;
// 블렌딩 상태를 생성
ID3D11BlendState* blendState;
device->CreateBlendState(&blendDesc, &blendState);
// 렌더링 시 블렌딩 상태를 설정
context->OMSetBlendState(blendState, nullptr, 0xFFFFFFFF);
\[R = R_back R + R_front R\] \[G = G_back G + G_front G\] \[B = B_back B + B_front B\]광원효과 공식
대신 이 공식은 RGB의 한계가 255이기 때문에, 255를 초과하는 상황에서는 적합하지 않을 수 있다.
따라서 255가 넘게 되면 255로 값을 고정해주는 등의 처리를 하게 된다.
한계 처리는 아래와 같이 진행된다.
-
RGB 값의 한계 처리
RGB 값의 한계가 255인 경우, 클램핑(clamping) 처리를 추가해야 한다.
예를 들어, 밝은 광원의 색상이 (255, 255, 255)이라면 이 값을 (1.0, 1.0, 1.0)로나누어
RGB 값을 1 이하로 조정할 수 있다.
클램핑은 RGB 값을 특정 범위로 제한하는 방법이다.
만약 RGB 값이 255를 초과하면, 이를 255로 제한하여 최대값으로 유지한다.
예를 들어, RGB 값이 (300, 200, 150)이라면 이를 (255, 200, 150)으로 클램핑할 수 있다.
// 아래는 클램핑 예시 코드이다
def clamp(value, min_val, max_val):
return max(min(value, max_val), min_val)
r = 300
g = 200
b = 150
r = clamp(r, 0, 255)
g = clamp(g, 0, 255)
b = clamp(b, 0, 255)
광원효과는 DirectX11에서 아래의 코드로 구현하게 된다.
ID3D11ShaderResourceView* lightTextureView; // 광원에 사용되는 텍스처 뷰 객체
deviceContext->PSSetShaderResources(slot, 1, &lightTextureView);
위의 코드에서 slot은 텍스처 슬롯 번호를 나타내고, lightTextureView는 광원에 사용되는 텍스처 뷰 객체를 가리킨다.
이 함수를 호출하여 픽셀 쉐이더에 광원에 필요한 텍스처 리소스를 설정할 수 있다.
ID3D11Buffer* lightBuffer; // 광원에 사용되는 상수 버퍼 객체
deviceContext->PSSetConstantBuffers(slot, 1, &lightBuffer);
댓글 남기기