7. 렌더링 최적화
1. 래스터라이저의 평면 처리
래스터라이저가 수행하는 작업 중 뒷면 제거(Back-face Culling)작업은 정점을 특정 방향으로 읽은 후, 사전 설정에 따라 해당 구역 내 픽셀을 렌더링할 지 결정하는 일을 수행한다.
기본적으로 삼각형 프리미티브를 이루는 세 정점을 Index 버퍼에 따라 읽었을 때, 카메라가 바라보는 방향에서 시계방향이면 렌더링을 수행하고 반시계방향이면 렌더링에서 제외(Culling)된다.
RSSetState()
함수로 렌더링 파이프라인의 래스터라이저 상태를 설정할 수 있고, CreateRasterizerState()
함수에 D3D11_RASTERIZER_DESC
구조체를 이용해 ID3D11RasterizerState
객체로 래스터라이저 상태값을 관리할 수 있다.
이 중 D3D11_RASTERIZER_DESC
의 CullMode
로 컬링 옵션을 따로 사용자가 설정할 수 있다.
2. 렌더링 최적화 기법
#1. 오클루전 컬링 (Occlusion Culling)
-
카메라 시점에서 다른 객체에 의해 완전히 가려져 화면에 보이지 않는 객체는 렌더링에서 제외시켜 렌더 부하를 줄인다.
-
불필요한 드로우 콜을 요청하지 않아 GPU 작업량을 줄인다.
-
예시: 주벽, 빌딩 등에 가려진 물체를 렌더링에서 제외.
#2. 절두체 컬링 (Frustum Culling)
-
카메라의 뷰 프러스텀(시야 영역) 밖에 있는 객체를 렌더링에서 제외시키는 방법. 뷰 프러스텀과 객체의 충돌 여부 등을 이용해 판단한다.
-
불필요한 드로우 콜을 요청하지 않아 GPU 작업량을 줄인다.
-
예시: 플레이어 축면, 후면 등 시야각 바깥의 물체를 렌더링에서 제외.
#3. 인스턴싱 (instancing)
-
동일한 메쉬를 여러번 렌더링할 때, 위치, 회전, 색상 등 일부 데이터만 변경하여 한 번의 드로우 콜로 여러 객체를 한번에 처리한다.
-
드로우 콜 횟수를 줄여 CPU-GPU 간 통신 비용을 크게 절약할 수 있다.
-
예시: 파티클 시스템 등 단순 반복 렌더링이 필요한 경우.
#4. LOD (Level of Detail)
-
객체와 카메라 거리에 따라 단계적인 해상도 모델링을 적용한다.
-
화면에 잘 보이지 않는 물체는 저해상도 모델링을 사용하므로 렌더링 비용을 줄인다.
-
예시: 오픈 월드 게임에서 원거리에 있는 건물, 캐릭터 등.
#5. 배칭 (Batching)
-
같은 재질(material)이나 셰이더를 사용하는 여러 객체를 하나의 드로우 콜로 묶어 렌더링한다.
-
드로우 콜 횟수를 줄여 CPU-GPU 간 통신 비용을 크게 절약할 수 있다.
-
예시: 동일한 텍스처를 사용하는 UI 요소나 대량의 작은 객체.
배칭 vs 인스턴싱
둘 다 드로우 콜을 줄여 오버헤드로 인한 퍼포먼스 감소를 막는 데 효율적이다.
하지만, 배칭은 CPU에서 여러 객체의 정점을 하나로 묶어서 한번에 렌더링하는 것이고, 인스턴싱은 같은 메쉬를 공유하는 객체들의 위치, 회전, 색상 등의 추가 정보를 버퍼에 담아 같이 전달해서 GPU에서 버퍼에 담긴 정보에 따라 각 객체의 렌더링을 처리하는 것이다.
따라서, 정점 수가 많은 복잡한 모델의 경우 웬만하면 인스턴싱이 유리하다. 상황에 따라 적합한 최적화 방법을 사용하도록 하자.
#6. Texture Atlasing
-
여러 텍스처를 하나의 큰 텍스처(아틀라스 텍스처)로 합쳐 사용한다.
-
렌더링 시 텍스처 교체를 줄일 수 있고, 리소스 관리에도 유용하다.
-
예시: 2D 게임의 스프라이트 시트 또는 타일 텍스처 등.
#7. Deferred Shading/Rendering
-
모든 객체의 기하학적 데이터를 먼저 렌더링하고, 이후 조명을 계산하는 방식.
-
화면에 보이는 픽셀만 조명을 계산하므로, 복잡한 씬에서 성능 개선.
-
예시: 조명이 많은 3D 게임(예: FPS 게임).
#8. Precomputed Lighting
-
정적인 환경에서 조명을 미리 계산하고 텍스처에 저장(Baked Lighting).
-
실시간 조명 계산을 줄여 성능 향상.
-
예시: 실시간 조명이 필요 없는 실내 장면.
#9. Distance Culling
-
카메라로부터 특정 거리 이상에 있는 객체를 렌더링하지 않음.
-
먼 거리에 있는 불필요한 객체를 제외하여 성능 개선.
-
예시: 먼 배경에 있는 객체, 게임 맵의 경계 영역.
#10. Adaptive Tessellation
-
객체의 화면 크기에 따라 테셀레이션(폴리곤 세분화)을 동적으로 조정.
-
화면 가까이 있는 객체의 디테일을 높이면서도, 멀리 있는 객체는 단순화.
-
예시: 캐릭터의 얼굴 세부 표현, 지형 렌더링.
#11. GPU Culling (Compute Shader를 활용한 컬링)
-
GPU에서 Compute Shader를 사용하여 컬링 작업을 수행.
-
컬링 연산을 GPU에서 수행하여 CPU 부하를 줄임.
-
예시: 복잡한 씬의 대규모 객체 컬링.
#12. Z-Prepass (Depth Pre-pass)
-
첫 번째 패스에서 깊이만 렌더링하고, 두 번째 패스에서 깊이 테스트를 사용해 화면에 보이는 픽셀만 셰이더를 적용.
-
픽셀 셰이더를 최소화하여 성능 향상.
-
예시: 복잡한 픽셀 셰이더가 많은 게임.
#13. 비동기 연산 (Async Compute)
-
그래픽스와 별도로 비동기 작업(예: 물리 연산, 후처리 효과 등)을 GPU의 Compute Queue에서 처리.
-
GPU 자원 활용도 증가.
-
예시: 물리 연산, 파티클 시스템, 화면 후처리.
#14. Virtual Texturing
-
필요한 텍스처 데이터만 메모리에 로드하여 렌더링.
-
메모리 사용량 절약, 고해상도 텍스처의 효율적 관리.
-
예시: 대규모 오픈월드 게임의 지형 텍스처.
#15. Shader LOD
-
화면 크기나 카메라 거리 등에 따라 셰이더의 복잡도를 조정.
-
중요한 객체에만 고품질 셰이더 적용.
-
예시: 디테일한 표면 효과나 후처리.
#16. Occlusion Queries
-
GPU가 특정 객체가 화면에 보이는지 여부를 검사(쿼리)하여 결과를 활용.
-
화면에 보이지 않는 객체의 렌더링을 줄임.
-
예시: 화면 뒤에 숨겨진 대형 구조물.
Occlusion Culling 과 차이점
둘 다 가려진 물체에 대한 렌더링 제외 최적화라는 공통점이 있지만, 최적화 시점에 차이가 있다.
오클루전 컬링의 경우, CPU 또는 GPU에서 객체가 가려질 것을 미리 연산해 해당 객체를 제외시키는 방법이고, 오클루전 쿼리의 경우 렌더링 후 해당 객체가 화면에 실제 보이는지 여부를 GPU에 쿼리로 요청한다. 이후 해당 쿼리 결과를 이용해 최적화를 하는 것이 오클루전 쿼리이다.
#17. DRS (Dynamic Resolution Scaling)
-
프레임 속도를 유지하기 위해 해상도를 동적으로 조정.
-
안정적인 프레임 속도 유지.
-
예시: 콘솔 게임, 하드웨어 리소스 제한이 있는 환경.
#18. Multi-Resolution Rendering
-
화면 중심부는 고해상도로, 가장자리 부분은 저해상도로 렌더링.
-
렌더링 비용 절감.
-
예시: VR 렌더링.