절두체 컬링(Frustum Culling)
절두체 컬링(Frustum Culling)
카메라의 시야 볼륨(Frustum) 밖 오브젝트를 드로우 제출(렌더링) 이전에 제외하여, 불필요한 렌더링 비용을 줄이는 최적화 기법
- 정의
- 카메라의 시야를 나타내는 절두체(Frustum) 내부에 있는 오브젝트만 렌더링
- 절두체 밖 오브젝트는 렌더링 단계(드로우콜 제출) 이전에 제외
- 렌더링 파이프라인 단게에서 수행되는 다른 컬링 개념과는 다소 다른 편
- 클리핑(Cliping) : 제출된 도형이 화면 밖으로 나갔을때, 화면 경계에 맞게 ‘잘라냄’(RS)
-
- 오클루젼(Occlusion)
- 절두체 내부에 존재하여도 ‘다른 물체’에 가려져 카메라에 안보이는 오브젝트를 제외
-> 다만 이는 실제로 모든 물체를 ‘그려봐야’ 알기에 매우 무거움!
(OM)
- 오클루젼(Occlusion)
- 클리핑(Cliping) : 제출된 도형이 화면 밖으로 나갔을때, 화면 경계에 맞게 ‘잘라냄’(RS)
- 렌더링 파이프라인 단게에서 수행되는 다른 컬링 개념과는 다소 다른 편
- 카메라의 시야를 나타내는 절두체(Frustum) 내부에 있는 오브젝트만 렌더링
- 왜 필요한가?
- 화면에 보이지 않는 오브젝트를 렌더 파이프라인에 태우면 비용이 발생함
- CPU: DrawCall 기록/상태 변경/커맨드 버퍼 생성 등 제출 오버헤드
- GPU: Vertex/Primitive 처리, Rasterization, Pixel shading, 메모리 대역폭 사용
- CPU: DrawCall 기록/상태 변경/커맨드 버퍼 생성 등 제출 오버헤드
- 따라서 “가벼운 컬링 계산”으로 “무거운 렌더링 작업”을 처리!
- 화면에 보이지 않는 오브젝트를 렌더 파이프라인에 태우면 비용이 발생함
절두체(Frustum)란?
- 형태
- 원근(Perspective) 투영: 가까운 면(Near)이 작고 먼 면(Far)이 큰 절두체(Truncated pyramid)
- 직교(Orthographic) 투영: 상자(Box) 형태
- 원근(Perspective) 투영: 가까운 면(Near)이 작고 먼 면(Far)이 큰 절두체(Truncated pyramid)
- 구성
- 절두체는 다음 6개의 평면으로 정의
Left / Right / Top / Bottom / Near / Far
- 절두체는 다음 6개의 평면으로 정의
절두체를 구하는 방법
1) 기하학적 구성: 8개 코너 → 6개 평면
- 입력
- 카메라 위치
C - 카메라 축
R( right ), U( up ), F( forward ) - 투영 파라미터
FOV,Aspect,Near,Far
- 카메라 위치
- 아이디어
- Near/Far 평면의 중심을 구한 뒤,
R,U방향으로 너비/높이만큼 이동해 Near 4개 + Far 4개 = 8개 코너를 만듦
- Near/Far 평면의 중심을 구한 뒤,
- 평면의 법선(외적)
- 코너 3점
A, B, C가 있을 때 평면 법선은 다음처럼 표현 가능
n = normalize((B - A) × (C - A))
- 법선 방향은 절두체 내부를 향하도록 점 순서(와인딩) 또는 부호를 맞춤
- 코너 3점
2) 행렬 기반: View-Projection(VP)에서 6개 평면 추출
- View 행렬
- 월드 좌표를 카메라 좌표로 변환
- “카메라를 움직이는 대신, 월드를 카메라 반대로 이동”시키는 역변환 개념
- 월드 좌표를 카메라 좌표로 변환
- Projection 행렬
FOV / Aspect / Near / Far를 이용해 원근(또는 직교) 투영을 수행- 클립 공간(Clip Space)으로 사상하기 위한 변환
- ViewProjection
VP = Projection * View- 클립 공간 경계 조건(예:
-w ≤ x ≤ w,-w ≤ y ≤ w, z 범위)을
clip = VP * world에 대입하면 월드 공간의 6개 평면(Frustum planes) 을 얻을 수 있음
평면 방정식과 내적 판정
- 평면 방정식
- 평면은 보통 아래 형태로 표현
n · p + d >= 0→ 내부(inside)
n: 평면의 법선(normal)d: 상수항p: 검사할 점(위치)
- 평면은 보통 아래 형태로 표현
- 왜 내적으로 판정할 수 있나?
n · p + d의 결과(+/0/-)가 점p가 평면 기준으로 안/밖에 있는지를 판단
- 양수: 평면 안쪽
- 0: 평면 위
- 음수: 평면 바깥쪽
- 양수: 평면 안쪽
- 절두체는 6개 평면의 교집합이므로, 모든 평면에 대해 조건을 만족하면 내부이다.
- 중요한 규약
-
n · p + d >= 0를 내부 조건으로 쓰려면,
평면의 법선n이 절두체 내부를 향하도록 맞춰져 있어야 한다. -
또한 거리 기반 판정을 정확히 하려면,
평면을||n|| = 1이 되도록 정규화해두는 것이 안전하다.
-
실제 컬링은 바운딩 볼륨으로 수행한다
메시의 모든 정점을 검사하는 대신, 오브젝트의 바운딩 볼륨(Bounding Volume)을 검사해 비용을 줄인다.
1) Bounding Sphere
- 아이디어
- 구의 중심과 반지름만으로 빠르게 판정 가능.
- 구의 중심과 반지름만으로 빠르게 판정 가능.
- 판정
dist = n · center + ddist < -radius이면 구 전체가 평면 바깥 → 컬링 가능- 그 외에는 내부 또는 교차(완전 컬링 불가)
- 특징
- 매우 빠르지만, 형태에 비해 느슨할 수 있다.
- 매우 빠르지만, 형태에 비해 느슨할 수 있다.
2) Bounding Box (AABB/OBB)
- 아이디어
- 박스로 오브젝트를 감싸고 평면과의 관계를 검사한다.
- AABB는 축 정렬이라 계산이 비교적 쉽고,
- OBB는 회전까지 포함해 더 타이트하지만 계산이 더 무겁다.
- 박스로 오브젝트를 감싸고 평면과의 관계를 검사한다.
- 개념
- 평면 법선 방향으로 “가장 불리한 점(지원점)”을 이용하면
모든 코너를 검사하지 않고도 “완전 외부” 판정이 가능하다.
- 평면 법선 방향으로 “가장 불리한 점(지원점)”을 이용하면
TMI - CPU 절두체 컬링의 한계와 GPU-driven 컬링
- CPU 절두체 컬링이 비효율적일 수 있는 경우
- 컬링 검사 자체가 너무 많을 때
- 오브젝트 수가 매우 많으면(AABB/Sphere 테스트가 가볍더라도) 전체 검사 비용이 CPU에서 누적될 수 있음
- 오브젝트 수가 매우 많으면(AABB/Sphere 테스트가 가볍더라도) 전체 검사 비용이 CPU에서 누적될 수 있음
- 컬링 후에도 살아남는 오브젝트가 너무 많을 때
- 최종적으로 제출해야 할 렌더링 후보가 많으면 그만큼 DrawCall 기록/상태 변경/커맨드 생성 비용이 증가
- 즉, 병목이 “GPU 셰이딩”이 아니라 “CPU 제출” 쪽에서 생길 수 있음
- 최종적으로 제출해야 할 렌더링 후보가 많으면 그만큼 DrawCall 기록/상태 변경/커맨드 생성 비용이 증가
- 컬링 검사 자체가 너무 많을 때
- 그래서 등장한 흐름: GPU-driven 컬링
- CPU는 “엄청 많은 개별 DrawCall” 대신, 비교적 적은 수의 큰 작업을 제출하고
- GPU가 내부에서 가시성(컬링) + LOD + 렌더링 단위 선택을 수행하는 방식
- 대표적인 형태
- Indirect Draw / ExecuteIndirect
- GPU가 “그릴 목록(인자 버퍼)”을 만들고, 그 버퍼를 기반으로 그리기
- GPU가 “그릴 목록(인자 버퍼)”을 만들고, 그 버퍼를 기반으로 그리기
- Mesh Shader / Task Shader 기반
- 기존 VS/GS 중심 파이프라인보다 “GPU 쪽에서 프리미티브 생성/컬링/증폭”을 유연하게 수행 가능
- 기존 VS/GS 중심 파이프라인보다 “GPU 쪽에서 프리미티브 생성/컬링/증폭”을 유연하게 수행 가능
- UE5 Nanite 개념
- 렌더링 단위를 더 잘게(클러스터) 쪼개고,
- GPU가 화면 기여도에 따라 클러스터 단위 가시성/LOD를 결정해
- CPU의 개별 메시/폴리곤 단위 제출 부담을 줄이는 방향(“그릴 단위의 가상화/자동 선택”)
- 렌더링 단위를 더 잘게(클러스터) 쪼개고,
- Indirect Draw / ExecuteIndirect
- CPU는 “엄청 많은 개별 DrawCall” 대신, 비교적 적은 수의 큰 작업을 제출하고
댓글남기기