📒Deferred Rendering
: 지연 렌더링
📌Foward Rendering
Straight Forward Shading.
렌더링 파이프라인을 1번만 거쳐서 GPU Back Buffer(GBuffer)에 바로 렌더링
- Mesh 하나를 그릴 때마다 모든 계산을 시행
- 라이팅 계산: Mesh의 수에 비례
- 불필요한 연산 발생: 빛의 영향을 받지 않은 Mesh에 대해서도 연산
📌Deferred Rendering
: 렌더링 파이프라인을 크게 2번 거쳐 렌더링 (Two Pass Algorithm)
[장점]
- 특정 정보만 따로 분리해 다룰 수 있으므로
- 특정 영역에 관한 추가적인 연산, 효과 적용 가능
- 광원을 많이 사용하는 경우 Forward보다 빠를 수 있음
- 겹친 픽셀을 포함해 모든 픽셀마다 Light 연산을 하는 대신 Light마다 한 번의 연산만 진행
[단점]
- 광원을 적게 사용하는 경우 Forward보다 느림
- 더 많은 렌더링 횟수
- 더 많은 메모리 사용 (Texture)
- 반투명한 물체 처리가 어려움
- PASS1에서 한 오브젝트의 값으로 모든 데이터를 결정하므로 겹쳐있는 오브젝트 처리가 어려움
- Anti-Aliasing 성능 하락
- MSAA같은 anti-aliasing은 하드웨어 Rasterization 단계에서 수행됨
- Deferred Shading에서는 Frist Pass에서만 Rasterization 수행
- Second Pass는 GBuffer결과물을 사용하기만 하므로 Rasterization 수행되지 않으므로 AA 적용 불가능
- 이러한 이유로 Deferred Shading은 Light계산이 이루어지기 전에 AA을 적용하므로 최종 결과물이 예상한 값과 다르게 나올 수 있음
📒Deferred에서의 Lighting
: Deferred rendering을 적용하면 광원에 대한 연산만을 따로 다룰 수 있음
- 라이트가 미치는 영향을 따로 기록
- 빛 번짐, Bloom 등과 같은 기능을 사용하기 쉬워짐
📌Forward Lighting과의 연산흐름 차이
: (Deferred) 화면 결정 후 -> 라이팅 연산
-
Forward Shading:
한 pixel위치에 존재하는 여러개의 pixel값들에 모두 Lighting 연산 후 depth값 비교해 하나의 pixel만 그림
-
Deferred Shading:
First Pass를 통해 한 pixel 위치에서 'Light 계산하게될 pixel값'을 선정, Second Pass에서 해당 pixel값만 Light연산 후 그림
- 즉, 한 픽셀에 여러개의 Object가 겹쳐있을수록 Deferred Shading의 성능이득 증가
📌Light MRT
: 전용 Texture에 빛의 영향 기록
📌Setting
[Texture]
: 2개의 CBuffer 사용
- Diffuse: 세기
- Specular: 반사광
[Setting]
- DepthStencil Type: NO_TEST_NO_WRITE
- Blend State Type: ONE_ONE
- Culling: CULL-FRONT
- CULL-NONE: Light rendering이 두 번 호출됨
- CULL-BACK: Light 범위 안으로 카메라가 들어가면 Light 연산하지 않음
📌Volume Mesh Check
: Directional Lihgt가 아닌 경우 빛이 영향을 주는 범위를 알기 위해 Volume Mesh check가 필요함
- VolumeMesh: 광원이 영향을 주는 범위
- VolumeMesh만큼 호출된 전체 픽셀에 빛을 적용시키면 안 됨
- VolumeMesh만큼 호출된 곳에서도 빛이 영향을 주는 부분만 적용시켜야 함
📒Volume Mesh Check
[빛의 영향 범위를 확인하는 여러 방법들]
- 방법1: Position Texture 사용
- 방법2: Stencil 사용
📌방법1: Position Texture 사용
: Position Texture를 사용해 Pixel shader에서 한 번에 빛의 영향 범위 판단
- VolumeMesh 안에 들어오는지 판단
- 호출된 픽셀 위치를 UV로 환산
- 추출한 UV로 Position Texture 샘플링
- 얻은 좌표정보로 VolumeMesh와의 거리 측정
- 역으로 연산 (Screen➡️World➡️LocalSpace of VolumeMesh)
- 좌표계 역연산: 변환행렬(View Inv * World Inv)을 바인딩해 사용
- 거리 측정 결과로 내외부 판단
- 장단
- 장: 빠름 (PS에서 바로 연산 가능)
- 단: VolumeMesh의 기하학적인 특징이 있어야 함 - 내외부 판단 위해
📌방법2: Stencil 사용
: VolumeMesh의 BackFace, FrontFace, Stencil에 대해 총 3번 렌더링 결과로 빛의 영향 범위 판단
-
VolumeMesh 안에 들어오는지 판단
-
Volume Mesh용 DepthStencil State 제작
- BACKFACE용
- FRONTFACE용
- STENCIL용
-
BACKFACE 렌더링
: Light의 뒷부분 관점에서 VolumeMesh의 내부판단
- DepthFunc: BackFaceCheck
- DepthStencilType: Greater
- 더 뒤에 있으면 통과
- 먼저 그려진 물체들이(Deffered) VolumeMesh의 뒷면보다 앞에 존재한다면
- 즉, light의 영향 범위 안쪽이라면
-
FRONTFACE 렌더링
: Light의 앞부분 관점에서 VolumeMesh의 내부판단
- DepthFunc: FrontFaceCheck
- DepthStencilType: Less
- FrontFace.StencilFailOp: DECR
-
STENCILCHECK
: 예상하는 Stencil 값인지 확인
- DepthFunc: NEVER
- DepthStencilType: Equal
- OMSetDepthStencilState: 2번째(idx 1) pram으로 예상하는 Stencil 값 전달
- StencilEnable = true
- RenderTarget없이 DepthStencil Texture만 세팅
- 즉, RenderTarget에 색을 내보내는 Pixel Shader 단계 수행 X
- StencilPassOp: INCR
-
장단
- 장: VolumeMesh의 기하학적인 특징이 없어도 가능 - 내외부 판단 위해
- 단: 느림 (렌더링이 3번 발생)
[Stencil 단계 3~4를 한 단계로 합치기]
: 2~3 단계는 한 단계로 수행할 수 있음
- DepthStencilType: CULL_NONE
- 각 구조체마다 세팅
📒Stencil Buffer
: 렌더링해야 할 곳에 특정 값을 설정해, back buffer의 일정 부분만 rendering되도록 함
- off-screen buffer
- 해상도: Backbuffer, depth buffer와 동일함
- ex) 거울, 그림자, 아웃라인

References
[1] Deffered Rendering: https://learnopengl.com/Advanced-Lighting/Deferred-Shading
[2] Stencil Buffer: https://dis.dankook.ac.kr/lectures/game09/wp-content/uploads/sites/16/1/1171436988.pdf