지형과 환경 요소 최적화
랜드스케이프 LOD·재질·폴리지와 조명·안개·클라우드 비용을 점검해 넓은 레벨의 렌더링 부담을 줄입니다.
지형과 조명, 환경 효과를 쌓아 올렸다면 이제 성능을 점검할 차례입니다. 레벨이 풍부해질수록 렌더링 비용과 메모리 사용량도 빠르게 늘어나서, 고사양 개발 컴퓨터에서는 부드럽던 장면이 목표 기기에서는 끊기기 쉽습니다. 그래서 최적화는 마지막에 하는 선택 작업이 아니라, 여러 사양에서 플레이 품질을 지키기 위한 기본 작업입니다.
이 글에서는 랜드스케이프의 구성과 재질, 조명의 이동성과 그림자, 안개와 구름, 후처리, 컬링과 LOD, 폴리지를 차례로 살펴보며 각각에서 비용을 줄이는 기준을 정리합니다. 마지막으로 측정한 결과를 어떻게 읽고 비교할지 계산 예와 함께 익힙니다. 넓은 장면을 유지하면서 렌더링 부담을 줄이는 균형을 찾는 것이 목표입니다.
랜드스케이프 최적화
랜드스케이프는 넓은 영역을 차지하고 많은 버텍스와 텍스처를 쓰기 때문에, 그 자체로 성능에 큰 영향을 줍니다. 비용이 생기는 곳은 크게 두 군데입니다. 지형을 어떤 단위로 나눠 그릴지 정하는 컴포넌트와 섹션 구성은 처리할 버텍스 수와 CPU 부담을 정하고, 여러 레이어를 섞는 랜드스케이프 재질은 화면의 픽셀마다 드는 셰이더 계산과 텍스처 샘플 수를 정합니다. 그래서 아래 두 항목은 따로 확인하며, 한쪽을 줄였다고 다른 쪽 비용까지 줄었다고 보지 않습니다.
컴포넌트와 섹션 구성
지형 (랜드스케이프) 생성 및 조정에서 봤듯이 랜드스케이프는 컴포넌트와 섹션으로 나뉩니다. 같은 해상도라도 섹션과 컴포넌트를 어떻게 나누느냐는 여러 가지일 수 있으므로, 컴포넌트마다의 CPU 처리 비용과 섹션마다의 그리기 비용, 그리고 컬링과 LOD가 얼마나 정밀하게 동작하는지를 함께 비교합니다.
먼저 해상도는 필요한 만큼만 고릅니다. Manage 탭에서 랜드스케이프를 만들 때 필요 이상으로 넓거나 촘촘한 랜드스케이프를 만들면 쓸데없이 성능이 떨어집니다. 플레이어가 직접 밟지 않는 아주 먼 배경 지형이라면 해상도가 더 낮은 랜드스케이프를 쓰거나, 스태틱 메시로 만든 배경 산을 놓는 편이 효율적입니다.
컴포넌트의 크기도 균형을 맞춥니다. 컴포넌트는 렌더링과 가시성을 관리하는 단위이고, 그 안의 섹션 단위로 LOD가 정해집니다. 컴포넌트가 너무 많으면 컴포넌트마다 처리하는 CPU 부담이 늘어나므로, 전체 크기 안에서 컴포넌트 수를 알맞게 조절합니다. 레벨에서 전혀 쓰지 않는 부분은 Manage 탭의 삭제(Delete) 도구로 그 컴포넌트를 지워 렌더링 범위 자체를 줄입니다.
랜드스케이프 재질
랜드스케이프 재질은 잔디, 흙, 바위 같은 여러 레이어를 섞기 때문에 일반 오브젝트의 재질보다 복잡하고 비용이 큽니다. 그래서 먼저 레이어 수를 제한합니다. 필요한 레이어만 쓰고 한 랜드스케이프에서 너무 많은 레이어를 섞지 않으며, 실제로 각 컴포넌트에 쓰인 레이어와 출력까지 이어진 계산과 텍스처 샘플의 비용을 확인합니다. 랜드스케이프 재질에 쓰는 텍스처에도 에셋 최적화 및 압축에서 본 것처럼 알맞은 해상도와 압축 설정을 적용합니다.
색이나 강도처럼 자주 바꾸는 값은 마스터 랜드스케이프 재질을 하나 만들고, 재질 인스턴스에서 파라미터만 바꾸게 합니다. 일반 파라미터는 다시 컴파일하지 않고 바꿀 수 있지만, 정적 스위치는 별도의 셰이더 변형을 만들 수 있고, 인스턴스를 쓴다고 렌더링 비용이 저절로 줄지는 않습니다.
디테일 텍스처를 지형 표면에 반복해서 입힐 때는 UV 대신 World Aligned Texture 노드를 쓰면, 월드 좌표를 기준으로 투영해 지형의 크기와 상관없이 텍스처의 크기를 맞출 수 있습니다. 다만 투영하는 방향과 이음새, 추가로 드는 텍스처 샘플 비용을 확인해야 하며, 이 노드를 성능을 자동으로 높여 주는 기법으로 보지는 않습니다.
조명과 그림자 최적화
레벨의 분위기를 정하는 조명은 시각적 품질만큼 성능에도 민감합니다. 광원 하나가 늘면 그 빛이 닿는 범위의 지오메트리를 다시 계산해야 하고, 그림자를 드리우면 그 범위를 한 번 더 그려야 하기 때문입니다. 아래에서는 먼저 이동성과 프로젝트의 조명 방식에 따라 비용이 어떻게 달라지는지 보고, 이어서 비용이 가장 큰 그림자를 줄이는 방법을 살펴봅니다.
이동성과 조명 방식
조명 액터의 이동성은 성능에 바로 영향을 줍니다. 다만 그 영향은 프로젝트의 조명 방식에 따라 다릅니다. 미리 굽는 조명 방식에서는 Static이 고정된 조명이고, Stationary는 위치를 고정한 채 실행 중의 일부 변화를 허용합니다. 이때는 라이트맵과 빌드 시간, 메모리, 그리고 실시간 그림자의 비용을 함께 봅니다. 동적 조명에서 Movable은 위치와 속성을 바꿀 수 있고, 광원의 영향 범위와 그림자 방식, 빛을 받는 지오메트리의 양이 비용을 좌우합니다.
루멘 글로벌 일루미네이션을 쓰는 프로젝트는 미리 계산한 라이트맵을 쓰지 않으므로, 무조건 Static으로 낮추라는 규칙이 맞지 않습니다. 이동성마다 실행 중에 바꿀 수 있는 범위는 기본 조명 설정과 환경 조정의 이동성 비교를 참고하고, 지금의 렌더링 방식에서 비용이 큰 광원부터 측정합니다.
그림자
그림자는 렌더링에서 비용이 가장 큰 부분 가운데 하나입니다. 그림자의 품질과 거리는 쓰고 있는 그림자 방식에 맞는 설정으로 조절합니다. 기존 섀도 맵과 가상 섀도 맵(Virtual Shadow Maps)은 서로 다른 설정으로 품질을 정하므로, 모든 방식이 같은 해상도 옵션으로 제어된다고 생각하지 않습니다. 중요하지 않은 작은 조명이라면 그림자 품질을 낮추거나 그림자를 아예 끄는 것을 검토합니다.
그림자가 거의 눈에 띄지 않는 작은 오브젝트는 그림자를 드리우지 않게 할 수 있습니다. 액터의 디테일 패널에서 Rendering 항목의 Cast Shadows를 끄면, 그림자를 그리는 단계에서 그 오브젝트를 그리지 않으므로 그만큼 그리기 호출(draw call)이 줄어듭니다.
컬 디스턴스 볼륨(Cull Distance Volume)도 쓸 수 있습니다. 볼륨 안의 액터가 카메라에서 일정 거리보다 멀어지면 그리지 않도록 크기별로 거리를 정하는 볼륨입니다. 멀리 있는 작은 소품은 화면에서 거의 보이지 않으면서도 그림자까지 그리는 비용을 만들기 때문에, 그림자를 드리우는 오브젝트에 특히 효과가 있습니다.
안개와 구름 최적화
볼류메트릭 안개는 보기에는 뛰어나지만 비용이 큽니다. 목표 플랫폼의 사양이 충분하지 않다면 볼류메트릭 안개를 끄고 기본 지수형 높이 안개만 쓰는 편이 좋습니다.
볼류메트릭 클라우드는 디테일 패널의 Tracing Max Distance와 샘플 배율, 스케일러빌리티 설정으로 비용을 조절합니다. 구름은 멀리 갈수록 화면에서 작게 보이므로, 아주 먼 거리까지 고품질로 계산할 필요는 없습니다.
후처리, 컬링, LOD
후처리 볼륨
후처리 볼륨은 화면 전체에 적용되므로, 설정이 과하면 모든 프레임이 그만큼 비싸집니다. 필요한 효과만 켜고 쓰지 않는 효과는 끕니다. 블룸, 앰비언트 오클루전, 화면 공간 반사(Screen Space Reflections)처럼 비용이 큰 효과는 품질을 알맞게 조절하는데, 효과의 강도(Intensity)를 줄이는 것과 계산 품질이나 그 단계의 비용을 줄이는 것은 다르다는 점에 주의합니다. 강도를 0에 가깝게 낮춰도 계산은 그대로 할 수 있으므로, 바꾼 뒤 GPU 시간을 비교해 실제로 줄었는지 확인합니다.
컬링
컬링(culling)은 화면에 보이지 않는 것을 그리지 않는 기능으로, 여러 종류가 있습니다. 카메라 시야 밖의 것을 빼는 시야 절두체 컬링(frustum culling), 정해진 거리보다 먼 것을 빼는 거리 컬링, 다른 지오메트리에 가려진 것을 빼는 오클루전 컬링(occlusion culling)입니다. 이 셋을 구분하고, 실제로 무엇이 그려지는지 결과를 확인합니다. 오클루전 컬링의 가림은 실제로 그려지는 지오메트리로 판단하므로, 충돌만 담당하는 블로킹 볼륨(Blocking Volume)을 놓는다고 그것이 뒤의 물체를 가리지는 않습니다.
LOD
일반 스태틱 메시에는 화면에서 차지하는 크기에 맞는 LOD를 설정합니다. 특히 나무, 바위, 풀처럼 여러 번 반복해서 쓰는 오브젝트는 줄인 비용이 배치한 수만큼 곱해지므로 LOD 설정이 중요합니다. 나나이트 메시는 다른 방식으로 상세도를 정하므로, 그 방식과 지원 범위는 따로 확인합니다. LOD 설정 방법은 에셋 최적화 및 압축에서 다뤘습니다.
폴리지 최적화
풀이나 잔디 같은 폴리지(foliage)는 레벨을 풍성하게 하지만, 폴리곤과 그리기 호출을 많이 만듭니다. 먼저 폴리지 도구에서 밀도를 지나치게 높이지 않습니다. 다음으로 폴리지 유형마다 디테일 패널의 Cull Distance를 정해, 어느 거리까지 그릴지를 정합니다. 일반 폴리지와 나나이트 메시는 이 설정이 적용되는 범위가 같지 않을 수 있습니다.
폴리지가 갑자기 나타나거나 사라지면 눈에 거슬리므로 전환도 다듬습니다. 일반 폴리지의 LOD와 컬링이 끝나는 거리(End Cull Distance)를 맞추고, 지원하는 재질에서는 PerInstanceFadeAmount 노드로 거리에 따라 서서히 사라지게 해 전환을 부드럽게 합니다. 낮은 LOD로 바뀐다고 메시가 저절로 꺼지는 것은 아니므로, 꺼지는 거리는 컬링 거리로 따로 정합니다.
측정한 결과를 읽고 비교하기
최적화는 증상을 보고 바로 원인을 정하는 일이 아니라, 측정한 수치로 다음에 비교할 대상을 고르는 일입니다. 증상별로 다음에 무엇을 볼지는 다음과 같습니다.
| 측정한 증상 | 다음에 비교할 대상 |
|---|---|
| GPU 시간이 김 | stat GPU와 ProfileGPU로 그림자, 볼류메트릭, 기본 패스(Base Pass)의 비용을 나눠 봅니다. |
| 카메라를 돌릴 때 끊김 | 폴리지 밀도와 그리기 호출 수뿐 아니라, 스트리밍과 셰이더 준비도 확인합니다. |
| 특정 구역에서만 느림 | 그 구역 지형 재질의 사용 레이어, 텍스처 메모리, 보이는 컴포넌트 수를 비교합니다. |
이 표도 원인을 확정해 주지는 않습니다. 같은 기기와 해상도, 카메라 경로에서 한 항목만 바꾸고, 프레임 시간과 시각적으로 잃은 것을 다시 비교합니다. 성능 측정 도구는 환경 요소의 성능 분석에서 자세히 다룹니다.
계산으로 확인해 봅니다. 목표가 60 FPS라면 한 프레임의 예산은 1000 / 60, 약 16.67 ms입니다. 가상의 측정에서 프레임이 22 ms였고 구름 설정 하나를 낮춘 뒤 20 ms가 되었다면, 개선은 있었지만 아직 목표에는 못 미칩니다. 이때 GPU 시간이 줄어도 게임 스레드나 다른 대기 시간이 남아 있다면 전체 프레임 시간이 같은 비율로 줄지 않을 수 있습니다. 여러 단계가 동시에 진행되기 때문에, 항목별 시간을 단순히 더해 전체 프레임 시간을 짐작하지 않습니다.
다음 비교에서도 기기와 해상도, 카메라 경로를 고정하고, 바꾼 값과 프레임 시간, 시야에서 잃은 것을 함께 적습니다. 바꾼 결과가 15 ms라면 수치로는 60 FPS 예산 안에 들어갑니다. 하지만 목표 지점이 보이지 않을 만큼 안개나 폴리지를 없앴다면, 성능 조건만 맞췄을 뿐 플레이 조건은 깨진 것이므로 그것도 다시 확인해야 합니다.
정리
- 랜드스케이프는 필요한 만큼의 해상도와 알맞은 컴포넌트 수로 만들고, 먼 배경은 낮은 해상도나 스태틱 메시로, 쓰지 않는 컴포넌트는 지웁니다.
- 랜드스케이프 재질은 레이어 수와 출력에 이어진 계산을 줄이고, 인스턴스나 World Aligned Texture가 비용을 저절로 줄인다고 보지 않습니다.
- 조명의 이동성이 주는 영향은 조명 방식에 따라 다르며, 루멘 프로젝트에서는 무조건 Static으로 낮추는 규칙이 맞지 않습니다.
- 그림자는 쓰는 방식에 맞는 설정으로 품질을 정하고, 작은 오브젝트의
Cast Shadows를 끄거나 컬 디스턴스 볼륨으로 먼 오브젝트를 빼서 줄입니다. - 볼류메트릭 안개와 구름은 비용이 크므로 사양에 맞춰 끄거나 추적 거리와 샘플을 줄이고, 후처리는 강도와 계산 비용이 다르다는 점을 기억합니다.
- 시야 절두체, 거리, 오클루전 컬링을 구분하고, 반복되는 오브젝트에는 LOD를, 폴리지에는 밀도와 컬링 거리, 전환을 정합니다.
- 같은 조건에서 한 항목씩 바꾸고, 프레임 시간과 시야 손실을 함께 비교하며, 60 FPS의 예산은 약 16.67 ms입니다.
연습 문제
1. 개선했지만 아직 부족할 때
60 FPS가 목표인 장면에서 프레임이 22 ms였고, 구름의 Tracing Max Distance를 줄인 뒤 20 ms가 되었습니다. 목표까지 몇 ms를 더 줄여야 할까요? 이번 개선으로 GPU 시간이 2 ms 줄었으니, 그림자에서 GPU 시간을 4 ms 더 줄이면 반드시 16 ms가 될까요?
해설 보기
60 FPS의 예산은 약 16.67 ms이므로, 20 ms에서 약 3.33 ms를 더 줄여야 합니다.
그림자의 GPU 시간을 4 ms 줄여도 전체 프레임이 반드시 16 ms가 되지는 않습니다. GPU 말고도 게임 스레드나 렌더 스레드의 시간이 프레임을 정할 수 있고, 여러 단계가 동시에 진행되므로 항목별 시간을 단순히 빼서 전체를 짐작할 수 없습니다. 바꾼 뒤 같은 조건에서 다시 측정해 확인합니다.
2. 블룸 강도를 0으로 했는데
GPU 비용을 줄이려고 후처리 볼륨의 Bloom 강도를 0에 가깝게 낮췄습니다. 화면에서 블룸은 거의 보이지 않는데, GPU 시간은 거의 그대로입니다. 왜 그럴까요?
해설 보기
효과의 강도를 낮추는 것은 결과를 화면에 얼마나 섞을지를 바꾸는 것일 뿐, 그 효과를 계산하는 비용을 반드시 줄이지는 않습니다. 강도를 낮춰도 블룸을 계산하는 단계가 그대로 실행될 수 있습니다.
비용을 줄이려면 그 효과를 실제로 끄거나 계산 품질을 낮추는 설정을 찾고, 바꾼 뒤 GPU 시간을 다시 비교해 실제로 줄었는지 확인합니다.
3. 벽 뒤에 있는 마을
높은 벽 뒤에 마을이 있어 플레이어에게는 보이지 않는데, 마을이 여전히 그려지는 것 같습니다. 그 벽은 보이지 않는 블로킹 볼륨으로 만들어져 있고, 겉모습은 그림이 그려진 얇은 판입니다. 무엇이 문제일까요?
해설 보기
오클루전 컬링은 실제로 그려지는 지오메트리를 기준으로 가림을 판단합니다. 충돌만 담당하는 블로킹 볼륨은 그려지지 않으므로 뒤의 마을을 가리는 물체로 취급되지 않습니다. 그림이 그려진 판이 얇거나 작으면 가림 판정에 충분하지 않을 수도 있습니다.
벽을 실제 지오메트리로 만들었을 때 뒤의 마을이 그려지지 않는지 확인하고, 그래도 그려진다면 거리 컬링이나 레벨 스트리밍처럼 다른 방법도 함께 검토합니다.
이것으로 4장을 마칩니다. 4장에서는 새 레벨을 만들어 기본 구조를 잡고, 랜드스케이프로 지형을 조각하고 칠한 뒤, 광원과 하늘, 후처리로 기본 조명을 설정하고, 안개와 대기, 구름으로 환경 효과를 더하고, 마지막으로 지형과 환경 요소의 비용을 측정하며 줄이는 방법까지 레벨 디자인의 흐름을 살펴봤습니다. 다음 장의 기본 조명 설정부터는 광원의 종류와 방향을 더 깊이 다루는 데서 시작해, 그림자 옵션과 성능, 글로벌 일루미네이션과 반사, 조명과 그림자의 디버깅, 실시간 조명과 사전 계산 조명까지 조명과 그림자를 본격적으로 다룹니다.