서의 공간

제9장 혼합 본문

Graphics API/DirectX 11 - Luna

제9장 혼합

홍서의 2020. 12. 23. 02:08

목표

1. 혼합의 작동 방식과 Direct3D에서 혼합을 사용하는 법을 이해한다.

2. Direct3D가 지원하는 여러 가지 혼합 모드를 배운다.

3. 기본도형의 투명도를 알파 성분을 이용해서 조절하는 방법을 파악한다.

4. HLSL의 clip함수를 이용해서 한 픽셀이 후면 버퍼에 아예 그려지지 않게 만드는 방법을 배운다.

9.1 혼합 공식

현재 래스터화 중인 \(ij\)번째 픽셀, 즉 원본(source) 픽셀에 대해 픽셀 셰이더가 출력한 색상이 \(\mathbf{C_{src}}\)라고 하자. 그리고 현재 후면 버퍼에 있는 \(ij\)번째 픽셀, 즉 대상(destination) 픽셀의 색상이 \(\mathbf{C_{dst}}\)라고 하자. 혼합을 사용하지 않으면 \(\mathbf{C_{src}}\)가 \(\mathbf{C_{dst}}\)를 덮어써서(원본의 깊이·스텐실 판정을 통과했다고 할 때) 후면 버퍼의 \(ij\)번째 픽셀의 새로운 색상이 된다. 그러나 혼합을 사용하면 \(\mathbf{C_{src}}\)와 \(\mathbf{C_{dst}}\)를 일정한 공식에 따라 혼합해서 얻은 새로운 색상 \(\mathbf{C}\)가 \(\mathbf{C_{dst}}\)를 덮어쓴다(즉, 혼합된 색상 \(\mathbf{C}\)가 후면 버퍼의 새로운 색이 된다). Direct3D는 다음과 같은 혼합 공식을 이용해서 원본 픽셀 색상과 대상 픽셀 색상을 섞는다.

\[\mathbf{C}=\mathbf{C_{src}}\otimes\mathbf{F_{src}}\boxplus\mathbf{C_{dst}}\otimes\mathbf{F_{dst}}\]

\(\mathbf{F_{src}}\)와 \(\mathbf{F_{dst}}\)는 각각 원본 혼합 계수(blend factor)와 대상 혼합 계수로, \(\S9.3\)에 나올 색상 벡터들 중 하나이다. 연산자\(\boxplus\)는 \(\S9.2\)에 정의된 이항 연산자들 중 하나이다.

위의 혼합 공식은 색상의 RGB 성분들에만 적용된다. 알파 성분에는 비슷하지만 구별되는 공식이 적용된다.

\[A=A_{src}F_{src}\boxplus A_{dst}F_{dst}\]

공식 자체는 동일하나, 색상 혼합의 것과는 다른 혼합 계수들과 이항 연산자를 사용할 수 있다. RGB와 알파를 이처럼 분리한 이유는 그냥 그 둘을 독립적으로, 따라서 다른 방식으로 처리할 수 있게 하기 위한 것이다.

9.2 혼합 연산

다음은 혼합 공식이 이항 \(\boxplus\)연산자로 사용할 수 있는 연산자들이다.

typedef enum D3D11_BLEND_OP
{
	D3D11_BLEND_OP_ADD = 1,
    D3D11_BLEND_OP_SUBTRACT = 2,
    D3D11_BLEND_OP_REV_SUBTRACT = 3,
    D3D11_BLEND_OP_MIN = 4,
    D3D11_BLEND_OP_MAX = 5,
} D3D11_BLEND_OP;

순서대로

\(\mathbf{C}=\mathbf{C_{src}}\otimes\mathbf{F_{src}}+\mathbf{C_{dst}}\otimes\mathbf{F_{dst}}\)

\(\mathbf{C}=\mathbf{C_{dst}}\otimes\mathbf{F_{dst}}-\mathbf{C_{src}}\otimes\mathbf{F_{src}}\)

\(\mathbf{C}=\mathbf{C_{src}}\otimes\mathbf{F_{src}}-\mathbf{C_{dst}}\otimes\mathbf{F_{dst}}\)

\(\mathbf{C}=\text{min}(\mathbf{C_{src}},\mathbf{C_{dst}})\)

\(\mathbf{C}=\text{max}(\mathbf{C_{src}},\mathbf{C_{dst}})\)

이다.

9.3 혼합 계수

다음은 \(\mathbf{F_{src}}\)와 \(\mathbf{F_{dst}}\) 모두에 적용되는 기본적인 혼합 계수들이다. 다음 목록에서 \(\mathbf{C_{src}}=(r_s,g_s,b_s),\ A_{src}=a_s\text{(픽셀 셰이더가 출력한 RGBA 값들)}\)이고 \(\mathbf{C_{dst}}=(r_d,g_d,b_d),\ A_{dst}=a_d\text{(렌더 대상에 이미 저장되어 있는 RGBA 값들)}\)이며, \(\mathbf{F}\)는 \(\mathbf{F_{src}}\)또는 \(\mathbf{F_{dst}}\)이고 \(F\text{(최종 알파 성분)}\)는 \(F_{src}\)또는 \(F_{dst}\)이다.

D3D11_BLEND_ZERO: \(\mathbf{F}=(0,0,0),F=0\)
D3D11_BLEND_ONE: \(\mathbf{F}=(1,1,1),F=1\)
D3D11_BLEND_SRC_COLOR: \(\mathbf{F}=(r_s,g_s,b_s)\)
D3D11_BLEND_INV_SRC_COLOR: \(\mathbf{F}=(1-r_s,1-g_s,1-b_s)\)
D3D11_BLEND_SRC_ALPHA:  \(\mathbf{F}=(a_s,a_s,a_s),F=a_s\)
D3D11_BLEND_INV_SRC_ALPHA: \(\mathbf{F}=(1-a_s,1-a_s,1-a_s),F=1-a_s\)
D3D11_BLEND_DEST_ALPHA: \(\mathbf{F}=(a_d, a_d, a_d),F=a_d\)
D3D11_BLEND_INV_DEST_ALPHA: \(\mathbf{F}=(1-a_d, 1-a_d, 1-a_d),F=1-a_d\)
D3D11_BLEND_DEST_COLOR: \(\mathbf{F}=(r_d, g_d, b_d)\)
D3D11_BLEND_INV_DEST_COLOR: \(\mathbf{F}=(1-r_d, 1-g_d, 1-b_d)\)
D3D11_BLEND_SRC_ALPHA_SAT: \(\mathbf{F}=(a'_s, a'_s, a'_s), F=a'_s, \text{여기서 }a'_s=\text{clamp}(a_s, 0, 1)\)
D3D11_BLEND_BLEND_FACTOR: \(\mathbf{F}=(r,g,b),F=a,\) 여기서 색상 \((r,g,b,a)\)는 ID3D11DeviceContext::OMSetBlendState 메서드의 둘째 매개변수로 주어진 색상이다. 이를 통해 응용 프로그램에서 혼합 계수 색상을 직접 지정할 수 있다. 이 색상은 혼합 상태를 다시 변경하기 전까지는 변하지 않는다.
D3D11_BLEND_INV_BLEND_FACTOR: \(\mathbf{F}=(1-r, 1-g, 1-b),F=1-a,\) 여기서 색상 \((r,g,b,a)\)는 ID3D11DeviceContext::OMSetBlendState 메서드의 둘째 매개변수로 주어진 색상이다. 이를 통해 응용 프로그램에서 혼합 계수 색상을 직접 지정할 수 있다. 이 색상은 혼합 상태를 다시 변경하지 전까지는 변하지 않는다.

9.4 혼합 상태

Direct3D응용 프로그램에서 혼합 연산자와 혼합 계수를 렌더 상태의 하나의 혼합 상태(blend state)를 나타내는 ID3D11BlendState 인터페이스로 제어한다. 이 인터페이스를 얻으려면 D3D11_BLEND_DESC 구조체를 채우고 ID3D11Device::CreateBlendState 메서드를 호출해야 한다. 이렇게 생성한 혼합 상태 객체는 출력 병합기 단계에 묶어야 한다. ID3D11Device::OMSetBlendState 메서드를 사용한다. HLSL에서 BlendState를 정의하고 설정하는 것도 가능하다.

 

9.5 예제

9.6 알파 채널

9.7 픽셀 자르기

원본 픽셀을 더 이상의 처리 없이 완전히 잘라내야(폐기) 할 때가 있다. 그런 경우 HLSL의 내장 명령인 clip(x) 함수를 이용하면 된다. 픽셀 셰이더에서만 호출할 수 있는 이 함수는 만일 x<0이면 현재 픽셀을 완전히 폐기해서 더 이상의 처리가 일어나지 않게 한다. 이 함수는 완전히 불투명하거나 완전히 투명한 픽셀들을 렌더링할 때, 이를테면 철망 텍스처를 렌더링할 때 유용하다.

9.8 안개

안개를 적절히 이용하면 먼 거리의 렌더링 결함이나 파핑(popping) 현상을 숨길 수 있다. 파핑은 절두체의 먼 평면 뒤에 있던 물체가 카메라의 이동에 따라 절두체 안으로 들어오면서 갑자기 화면으로 '튀어 나오는(popping)' 것을 말한다.

안개를 구현하는 방법은 다음과 같다. 우선 안개의 색상과 안개가 시작되는 거리(카메라와의), 그리고 안개의 범위(즉 안개 시작 지점에서 물체가 안개에 완전히 가려지는 지점 사이의 거리)를 설정해 둔다. 그리고 렌더링시 삼각형의 한 점의 색상을 원래 색상과 안개 색상의 가중 평균으로 결정한다.

\begin{align}foggedColor&=litColor+s(fogColor-litColor)\\&=(1-s)\cdot litColor+s\cdot fogColor\end{align}

매개변수 \(s\)는 카메라 위치와 표면 점 사이의 거리에 의존하는 0에서 1까지의 값이다. 카메라와 표면 점 사이의 거리가 커짐에 따라 이 값이 1에 가까워지며, 결과적으로 표면 점이 점점 안개에 가려지는 효과가 생긴다.

\[s=\text{saturate}\left(\frac{\text{dist}(\mathbf{p},\mathbf{E})-fogStart}{fogRange}\right)\]

여기서 \(\text{dist}(\mathbf{p},\mathbf{E})\)는 표면 점 \(\mathbf{p}\)와 카메라 위치 \(\mathbf{E}\)사이의 거리다. saturate 함수는 주어진 인수를 [0, 1] 구간으로 한정한다. 즉,

\[saturate(x) =\begin{cases}x,\quad 0\le x\le 1\\0,\quad x<0\\1,\quad x>1\end{cases}\]

이다. 그림 9.1은 거리의 함수로서의 s를 그래프로 그린 것이다.

[그림 9.1] (위) 거리의 함수로서의 s(안개 색 가중치)의 그래프. (아래) 거리의 함수로서의 1-s(조명된 색상의 가중치)의 그래프. (1-s)는 s가 증가한 만큼 감소한다.

\(\text{dist}(\mathbf{p},\mathbf{E})\le fogStart, s=0\)일 때 안개가 적용된 색이 다음과 같이 주어짐을 주목하자.

\[foggedColor = litColor\]

이는 카메라와의 거리가 fogStart보다 작은 표면 점의 색상은 안개 색에 의해 변경되지 않음을 뜻한다.

\(fogEnd=forStart+fogRange\)라고 하자. \(\text{dist}(\mathbf{p},\mathbf{E})\ge fogEnd, s =1\)일 때 안개가 적용된 색은 다음과 같이 주어진다.

\[foggedColor = fogColor\]

다른 말로 하면, 카메라와의 거리가 fogEnd 이상인 표면 점은 안개에 완전히 가려져서 안개색만 보이게 된다.

\(fogStart <\text{dist}(\mathbf{p},\mathbf{E})<fogEnd\)일 때에는 \(\text{dist}(\mathbf{p},\mathbf{E})\)가 \(fogStart\)에서 \(fogEnd\)로 증가함에 따라 \(s\)가 0에서 1로 선형 증가함을 알 수 있다. 이는 거리가 증가함에 따라 안개 색의 가중치가 점차 커지고 원 색상의 가중치가 점점 작아짐을 뜻한다. 결과적으로 거리가 멀어지면서 표면 점이 더 안개에 가려지는 효과가 생긴다.

 

'Graphics API > DirectX 11 - Luna' 카테고리의 다른 글

제12장 계산 셰이더  (0) 2020.12.23
제11장 기하 셰이더  (0) 2020.12.23
제10장 스텐실 적용  (0) 2020.12.23
제8장 텍스처 적용  (0) 2020.12.22
DirectX 11 그래픽스  (0) 2020.12.07
Comments