
렌더링 성능의 핵심, "안 그리기"
게임이나 3D 앱을 만들 때 가장 큰 성능 병목 중 하나는 "화면에 보이지도 않는 것까지 GPU가 그리느라 시간을 낭비하는 것"이에요. 카메라 뒤쪽이나 벽 너머, 아니면 너무 작아서 1픽셀도 안 되는 오브젝트까지 충실하게 그려주면 프레임이 쭉쭉 떨어지거든요. 그래서 렌더링 엔진들은 컬링(culling), 즉 "이건 안 그려도 돼"라고 미리 걸러내는 기술을 오래전부터 발전시켜 왔어요. Yaroslav Krupitskas라는 그래픽스 엔지니어가 최신 기법들을 정리한 글을 올렸는데, 요즘 AAA 게임이나 Unreal Engine 5 같은 엔진에서 실제로 쓰는 방식들을 짚어줘요.
컬링의 기본 세 가지
먼저 가장 고전적인 세 가지를 볼게요. 프러스텀 컬링(frustum culling)은 카메라의 시야각(절두체) 바깥에 있는 오브젝트를 제외하는 거예요. 바운딩 박스랑 절두체의 평면 6개를 비교해서 교차 여부를 보는 방식이죠. 이건 CPU에서 수십 년째 해오던 기본기예요. 백페이스 컬링(backface culling)은 삼각형 중에서 카메라 반대 방향을 보고 있는 면을 안 그리는 거고, 이건 GPU 래스터라이저가 기본으로 해주는 일이에요. 오클루전 컬링(occlusion culling)은 좀 어려운데, 다른 오브젝트에 완전히 가려져서 어차피 안 보이는 걸 빼는 거예요. 이게 제일 효과가 크지만 계산도 제일 복잡해요.
전통적으로 오클루전 컬링은 CPU에서 소프트웨어 래스터라이저를 돌려서 "깊이 버퍼 근사치"를 만들고, 거기에 바운딩 박스를 테스트하는 식으로 구현했어요. Intel의 Masked Software Occlusion Culling이 유명하죠. 근데 이게 씬이 복잡해지면 CPU 부담이 커져서 최근에는 GPU 쪽으로 다 넘어가고 있어요.
GPU 드리븐 렌더링의 시대
요즘 트렌드는 GPU 드리븐 렌더링(GPU-Driven Rendering)이에요. 예전엔 CPU가 "이거 그려, 저거 그려" 하고 Draw Call을 하나씩 날렸다면, 이제는 CPU가 "전체 씬 버퍼 던져줄 테니까 네가 알아서 골라서 그려"라고 GPU에게 맡기는 방식이에요. 여기서 핵심이 컴퓨트 셰이더 기반 컬링인데요, 수십만 개의 오브젝트나 메시렛(meshlet, 작게 쪼갠 메시 단위)을 병렬로 한꺼번에 검사해서 그릴 것만 인다이렉트 드로우 버퍼에 채워넣어요.
이 방식의 대표 주자가 Unreal Engine 5의 Nanite예요. Nanite는 메시를 "클러스터"라는 작은 삼각형 덩어리로 쪼개고, 각 클러스터를 계층 구조(LOD bound tree)로 관리해요. 렌더링할 때는 컴퓨트 셰이더가 카메라와의 거리, 화면에서 차지하는 크기, 가려짐 여부를 동시에 판정해서 적절한 LOD 레벨의 클러스터만 골라 그립니다. 그래서 수십억 폴리곤짜리 씬도 실시간으로 돌릴 수 있는 거예요.
또 중요한 게 HZB(Hierarchical Z-Buffer) 기반 오클루전이에요. 이게 뭐냐면, 지난 프레임의 깊이 버퍼를 밉맵처럼 여러 해상도로 다운샘플링해서 계층 구조로 만들어요. 그리고 이번 프레임에서 오브젝트를 테스트할 때, 그 오브젝트의 화면 크기에 맞는 적절한 밉 레벨을 골라서 "이 바운딩 박스가 그 깊이보다 뒤에 있나?"를 한 번에 확인하는 거죠. 한 픽셀 샘플링으로 수천 픽셀 영역을 커버할 수 있어서 엄청 빨라요. 두 패스(two-pass) 구조로 구성해서 오클루더(가리는 오브젝트)를 먼저 그리고, 그 결과로 다시 컬링하는 테크닉도 표준이 됐고요.
메시 셰이더와 메시렛
최근 하드웨어 흐름에서 빼놓을 수 없는 게 메시 셰이더(Mesh Shader)예요. DirectX 12 Ultimate와 Vulkan에서 지원하는데, 전통적인 정점 셰이더 파이프라인을 갈아엎고 아예 컴퓨트 셰이더처럼 동작하는 스테이지를 새로 만든 거예요. 여기서는 태스크 셰이더(task shader)가 먼저 돌면서 메시렛 단위로 컬링을 수행하고, 통과한 것만 메시 셰이더로 넘겨서 삼각형을 생성해요. 이렇게 하면 컬링, LOD 선택, 지오메트리 생성이 전부 GPU 안에서 끝나서 CPU-GPU 동기화 오버헤드가 거의 사라집니다.
NVIDIA Turing 이후, AMD RDNA2 이후 GPU부터 지원하고, Apple Silicon도 Metal 3에서 지원해요. 다만 모바일이나 구형 GPU 대응이 필요한 프로젝트라면 아직 채택하기엔 이르다는 단점이 있어요.
업계 흐름과 비교
Id Tech 엔진의 Doom Eternal은 전통적인 CPU 프러스텀 컬링에 GPU HZB를 조합하는 클래식한 방식으로도 120fps를 뽑아냈고, 반대로 UE5 Nanite는 완전히 GPU로 밀어붙인 극단 사례예요. Unity의 HDRP도 SRP Batcher랑 GPU Resident Drawer로 이 방향으로 가고 있고, Godot 4의 Vulkan 렌더러도 비슷한 개선을 진행 중이에요.
한국 개발자에게 주는 시사점
게임 개발 하시는 분들이라면 지금 쓰는 엔진에서 어떤 레벨의 컬링까지 쓰고 있는지 확인해볼 만해요. 모바일 게임에서 드로우 콜이 1000개 넘어가면 거의 대부분 컬링이나 배칭이 원인이거든요. 웹 3D(Three.js, Babylon.js)에서도 프러스텀 컬링은 기본으로 켜져있지만 오클루전 컬링은 직접 구현해야 하는 경우가 많고요. 실시간 시각화나 디지털 트윈 분야에서도 씬 규모가 커지면 이 기법들을 직접 응용해볼 여지가 많습니다.
마무리
한 줄로 정리하면, 현대 렌더링 최적화의 본질은 "그리지 않을 것을 얼마나 똑똑하게 골라내느냐"에 있어요. 셰이더 하나 최적화하는 것보다 컬링 아키텍처를 잘 짜는 게 훨씬 임팩트가 큰 경우가 많죠.
여러분은 실시간 렌더링 프로젝트에서 어떤 컬링 기법까지 적용해보셨어요? 메시 셰이더 도입을 실무에서 고려하신 분들 이야기도 궁금합니다.
🔗 출처: Hacker News
TTJ 코딩클래스 정규반
월급 외 수입,
코딩으로 만들 수 있습니다
17가지 수익 모델을 직접 실습하고, 1,300만원 상당의 자동화 도구와 소스코드를 받아가세요.
"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"
실제 수강생 후기- 비전공자도 6개월이면 첫 수익
- 20년 경력 개발자 직강
- 자동화 프로그램 + 소스코드 제공