(사실 이해했는지 모르겠다. 어렴풋이 느껴질 뿐... 그래도 그 느낌을 정리한다.)
1. Blending은 GPU에서 작업해준다.
- 픽셀 쉐이더는 화면(Viewport)에 점이 무슨 색으로 찍힐지 결정하는 친구이다. Blend를 만약에 하기로 했다면, 이미 픽셀로 찍혀있는 (Rasterized) 색과 App이 정해준 계산으로 새로운 색을 찍는 것이라고 한다.
- App에서 PSO의 D3D12_RENDER_TARGET_BLEND_DESC 으로 로직을 정해준다.
(Pixel Shader 바디에서 로직을 정해주는 것이 아니다. Pixel Shader의 로직이 끝나고 나온 값과 원래 찍힌 화면 픽셀이 계산에 쓰이는 것이다.)
- D3D12는 Alpha와 RGB blend를 따로 진행 할 수 있다.
- 그리고 픽셀 형식이 DXGI_FORMAT_R8G8B8A8_UNORM 라면 비트 연산으로도 블랜딩을 할 수 있다고 한다.
- 예제에서는 RGB blend만 해줬다. 새로 그려지는 픽셀(Src)의 알파값을 중심으로 원래 픽셀(Dest)과 섞어서 새로운 색을 그리는 것이다.
- Vertex Shader에서 Homogeneous 좌표로 즉, 렌더링 좌표로 변환이 되어서 넘어오기 때문에, 그냥 화면에 찍힌 색깔이 무엇인지 + 정해진 Blend 공식은 무엇인지만 신경쓰면 되는것이다.
2. App에서 해줘야 하는 것
- 이미 찍혀있는, 픽셀과 계산을 하는 것이기 때문에 alpha가 (0, 1) 값을 가지고 blend를 하기로 한 친구라면 opaque(불투명)한 친구가 다 화면에 찍힌 다음에 다음에 Draw 요청을 걸어야 한다.
- 그리고 만약에 transparent 한 친구가 여럿이 있고, 그것들이 카메라 사이에 여러개 존재한다면, 정확한 색이 화면에 찍히게 하기 위해서는 Homogeneous Coords에서 Z - order를 맞춰야 한다.
(바로 위 내용은 예제에서는 아직 다루지 않았다.)
- 그리고 blend를 해주기로 한 PSO로 랜더링을 한다면, 추가적인 작업을 한다는 뜻이기 때문에 작업이 느려지게 된다. 그래서 opaque 한 친구들을 렌더링 할때는 blend 옵션을 꺼주어야 한다.
3. 언급할 만한 예제에서 사용한 방법(구조)
- 철망이나 울타리 같은 것을 표현할 때, Alpha 값을 가진 텍스쳐로 표현하였다. 복잡한 Vertex 구조가 필요 없이, Pixel Shader에서 Alpha 값을 기준으로 clip을 걸어서 중간중간 구멍이난 망 형태를 쉽게 표현할 수 있었다.
- Vertex Shader 에서 World 변환을 통해서 얻은 값을 Pixel Shader로 넘겨서, 해당 surface(표면)가 카메라와 얼마나 거리가 먼지 구할 수 있게 된다.
(목표는 카메라와 픽셀을 찍을 surface가 멀다면 안개의 농도를 짙게하는 것이다.)
- 안개의 색으로 전부 가려버릴 거리를 정하고, 카메라와 표면 간의 거리로 안개의 농도를 구하는 식을 새운다.
(필요하다면 안개가 시작되는 거리를 정해서 식에 넣어도된다.)
- 그리고 쉐이더 함수인 lerp의 알파 값으로 사용해서, 계산된 픽셀 색과 안개 색을 적절히 섞어서 안개를 표현하게 된다.
4. 연습 문제
(클릭하면 커집니다.)
연습 문제 1
연습 문제 2
- Blending을 하기로 하고 + Alpha가 (0, 1)인 픽셀을 먼저 화면에 찍으면
- 다음처럼 Back Buffer에 초기로 넣었던 배경 값과 blending이 일어난다.
- m_MainPassCB.FogColor를 바꿔서 시도해보면, 알 수 있다.
연습 문제 3
- 원래 픽셀 값이 뭔지 모른다. 그러니 그냥 lerp에 들어가는 alpha값 (안개 농도) 을 계산하겠다.
fogStart = 10 / fogRange = 200
(a) (160 - fogStart) / fogRange = (160 - 10) / 200 = 0.75
(b) (110 - fogStart) / fogRange = (110 - 10) / 200 = 0.5
(c) (60 - fogStart) / fogRange = (60 - 10) / 200 = 0.25
(d) (30 - fogStart) / fogRange = (30 - 10) / 200 = 0.1
연습 문제 4
- fxc으로 컴파일 해서 asm을 확인한다.
- 일단 여기 방법이 있고 Syntax - Win32 apps | Microsoft Learn
- 매크로를 넣어서 컴파일 하는 방법은
fxc "<경로>\Shaders\07_Blend.hlsl" /Od /D "ALPHA_TEST"="1"/Zi /T ps_5_1 /E "PS" /Fo "<경로>\Shaders\07_Blending_PS_Alpha.cso" /Fc "<경로>\Shaders\07_Blending_PS_Alpha.asm"
- fxc는 이미 환경변수로 추가가 되어있는 상태이다. 혹은 fxc.exe가 있는 곳으로 작업 폴더를 옮겼던가.
(나는 쉐이더 어셈블리를 볼 줄 모른다... 그니까 차이점만 대충 보자.)
(일단 위에 구조체 선언과 시그니처 선언을 넘기고 PS(main) 시작지점 부터 캡쳐 했다.)
- 오른쪽 asm을 보면 96줄 부터 r1.x 에다가 -1 값을 넣더니
(l 은 무슨 뜻일까... lvalue라는 뜻인가?)
- r1.w과 r1.x을 더한 값을 r1.x 에 넣는다.
- lt 명령어를 이용해서 r1.x 가 0.0 보다 작은지 결과를 r1.x에 저장한다.
- 그리고 r1.x와 -1를 and 비트 건 것을 다시 r1.x에 저장한다. (32비트)
- r1.x의 결과를 가지고 discard_nz를 건다.
- 아래 링크 내용을 요약하면, r1.x의 값에 따라 현재 픽셀을 버릴지 말지 결정하는 것이다.
(discard 에 관한 설명은 여기 있다. discard(sm4 - asm) - Win32 apps | Microsoft Learn )
연습 문제 5
- 이렇게 되면 더 밝아지긴 하는데, 그래도 어떤 느낌인지는 알 수 있다.
책 : DirectX 12를 이용한 3D 게임 프로그래밍 입문
'Programming > D3D12' 카테고리의 다른 글
[책공부] Geometry Shader + chap 12 연습 문제 (0) | 2024.01.30 |
---|---|
[책공부] Stencil 예제 + chap 11 연습 문제 (0) | 2024.01.23 |
[책공부] Texturing 예제 + chap 9 연습 문제 (0) | 2024.01.13 |
[책공부] Lighting 예제 + chap 8 연습 문제 (0) | 2024.01.11 |
[책공부] FrameResource 예제 ( + Root Constant) (0) | 2024.01.08 |