1. 개요[편집]
| 프러스텀 컬링 Frustum Culling | |
|---|---|
| 분류 | 가시성 판정(visibility determination) |
| 대상 | 카메라 절두체 밖 객체 |
| 대표 자료구조 | 경계 볼륨 계층, 옥트리, 공간 분할 자료구조 |
| 복잡도 | 공간 자료구조 사용 시 대략 O(log N) |
| 관련 컬링 | 오클루전 컬링, 백페이스 컬링 |
프러스텀 컬링(frustum culling)은 카메라의 시야 절두체(view frustum) 바깥에 있어 어차피 화면에 나오지 않을 객체를 렌더링 파이프라인에 넘기기 전에 걸러내는, 실시간 렌더링의 가장 기본적인 가시성 최적화 기법이다. 한 마디로 “안 보일 걸 그리느라 GPU를 갈아 넣지 말자”는 지극히 상식적인 이야기다.1
절두체(frustum)는 원근 투영 카메라의 가시 영역으로, 피라미드의 꼭대기를 잘라낸 모양이다. 근평면(near plane)과 원평면(far plane), 그리고 좌·우·상·하 4개의 측면, 총 6개의 평면으로 둘러싸인 볼록 다면체다. 어떤 객체가 이 6개 평면이 만드는 공간 바깥에 완전히 놓여 있으면 화면에 단 한 픽셀도 기여하지 못하므로, 드로우 콜(draw call) 자체를 생략한다.
2. 절두체의 6평면 표현[편집]
컬링을 하려면 먼저 절두체를 6개의 평면으로 뽑아내야 한다. 각 평면은
꼴로, 법선 이 절두체 안쪽을 향하도록 잡는다. 실무에서는 뷰-투영 행렬(view-projection matrix) 의 행들을 더하고 빼서 6평면을 한 방에 추출하는 Gribb–Hartmann 방법을 쓴다.2 예컨대 좌측 평면은 의 4번째 행과 1번째 행의 합으로 얻어진다. 이 트릭 덕분에 카메라가 움직일 때마다 평면을 재계산하는 비용이 사실상 공짜다.
점 가 어떤 평면의 안쪽에 있는지는 부호 있는 거리(signed distance)로 판정한다.
이 값이 음수면 그 평면 바깥이다.
3. 경계 볼륨과 판정[편집]
객체마다 복잡한 메시를 직접 6평면과 대조하는 것은 낭비다. 대신 객체를 감싸는 단순한 경계 볼륨(bounding volume) — 구(sphere) 또는 축 정렬 경계 상자(AABB) — 를 대신 판정한다. 이는 충돌 감지에서 쓰는 발상과 똑같다. 싸고 러프하게 먼저 거른다.
경계 구를 쓰면 판정이 가장 싸다. 구 중심 와 반지름 에 대해, 6개 평면 각각에서
가 하나라도 성립하면 그 객체는 절두체 완전 바깥이므로 버린다(reject). 6평면 모두에서 안쪽이면 채택하되, 여기엔 유명한 함정이 있다. 6평면 반공간의 교집합 판정은 절두체 모서리 근처 구석에서 실제로는 바깥인데 안쪽으로 오판(false positive)하는 경우가 있다.3 다행히 이 오판은 안전한 방향(안 보일 것을 그림)이라 렌더 결과는 정확하고, 약간의 낭비만 생긴다. AABB는 판정이 조금 더 비싸지만(평면마다 최근접/최원거리 꼭짓점 선택), 길쭉한 객체에서 경계 구보다 타이트해 컬링 효율이 좋다.
4. 계층적 컬링과 자료구조[편집]
객체가 수만 개면 매 프레임 전부를 순회하는 것 자체가 부담이다. 그래서 씬을 공간 분할 자료구조로 조직한다. 경계 볼륨 계층(BVH), 옥트리(octree), kd-트리 등이 대표적이다.
핵심 아이디어는 계층적 조기 종료다. 트리의 어떤 노드(=부분 공간)의 경계 볼륨이 절두체 완전 바깥이면, 그 아래 모든 자식을 통째로 버린다. 반대로 노드가 절두체에 완전히 포함되면 자식들을 더 검사할 필요 없이 전부 채택한다. 이렇게 하면 개별 객체 수 에 대해 매 프레임 순회 비용이 선형 에서 대략 수준으로 떨어진다. 넓은 오픈월드가 수십만 오브젝트를 굴리면서도 프레임을 유지하는 비결의 상당 부분이 여기 있다.
5. 다른 컬링과의 관계[편집]
프러스텀 컬링은 여러 컬링 기법 중 첫 관문일 뿐, 이것만으로 끝나지 않는다.
- 백페이스 컬링(backface culling): 삼각형 단위로, 카메라를 등진 면을 GPU가 자동으로 버린다. 프러스텀 컬링이 객체 단위라면 이건 폴리곤 단위.
- 오클루전 컬링(occlusion culling): 절두체 안에 있지만 앞의 다른 물체에 가려 보이지 않는 객체를 버린다. 벽 뒤 방 전체를 안 그리는 것. 프러스텀 컬링보다 비싸고 정교하며, hierarchical Z-buffer나 하드웨어 오클루전 쿼리를 쓴다.
- 레벨 오브 디테일: 컬링이 “그릴까 말까”라면 LOD는 “얼마나 정밀하게 그릴까”. 살아남은 객체에 대해 거리별로 저폴리 메시를 골라 준다. 텍스처 쪽 대응물이 밉맵이다.
파이프라인 순서로 보면 대개 프러스텀 컬링 → 오클루전 컬링 → LOD 선택 → 드로우로 이어진다. 값싼 필터를 앞에, 비싼 필터를 뒤에 두는 것이 국룰. 디퍼드 셰이딩 같은 후단 파이프라인의 부하를 줄이려면 이 전단 컬링이 얼마나 촘촘한지가 관건이다.4
6. 관련 문서[편집]
7. Footnotes[편집]
-
그런데 이 상식을 안 지킨 채 “왜 우리 게임 프레임이 안 나오죠?” 하는 사례가 생각보다 흔하다. 프로파일러를 켜 보면 화면 뒤편 도시 전체를 매 프레임 GPU로 밀어 넣고 있더라는 전설. ↩
-
Gribb, G. & Hartmann, K. (2001). “Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix.” 투영 행렬의 대수적 구조를 이용한 클래식 트릭으로, 지금도 거의 모든 엔진이 이걸 쓴다. ↩
-
이른바 “구석(corner) 문제”. 절두체를 6개 무한 평면의 반공간 교집합으로 근사하면, 절두체 밖이지만 6평면 모두에는 안쪽인 얇은 영역이 모서리 바깥에 생긴다. 정확히 잡으려면 절두체 8꼭짓점 vs AABB의 SAT(분리축 정리) 검사가 필요한데, 대부분은 그 정확도가 아까워서 그냥 조금 넘겨 그린다. ↩
-
컬링을 너무 빡세게 하려다 컬링 비용이 렌더 절감분을 넘어서는 배보다 배꼽 사태도 있다. 컬링도 결국 트레이드오프다. “일단 다 그려” vs “일단 다 걸러”의 균형점은 프로파일러가 정해 준다. ↩