고사양 레벨 애셋 사용을 위한 언리얼의 다양한 랜더링 프로파일링 기능 총정리 및 최적화 적용사례 기록
요약
- 주요 문제 : 고사양을 요구하는 배경 애셋 적용 시 심각한 프레임드랍으로 작업진행 어려움
- 해결 방안 :
LOD와HLOD를 활용해 드로우콜 수 절감 및 그려지는 폴리곤 수 절감,Texture LOD bias로 텍스처 해상도 조율하여 Rendering Resolution 비용 절감Lighting과Shadow비용 확인 및 최적화를 위한 액터 재배치
- 그 외 방법들 :
- 에디터 그래픽 설정 변경
- Mesh Merge로 드로우콜 감소
Cull Distance Volume활용 카메라 거리에 따른 소형애셋 드로우 조정
- 이루어낸 성과 :
- 작업환경에 제한받지 않는 최적화 기법으로 작업 완료
- 추후 레벨 애셋 적용시 필요한 최적화 방법을 탐색할 수 있는 plugin 제작
-
작업환경 주요 SPEC
CPU GPU intel i7 4코어 6스레드 내장 Intel iris Xe -
사용한 애셋 정보
기술 세부사항
- 500 ~ 5000 tri수를 가진 매쉬가 대부분이며 최대 350,000까지 있음
- 텍스처 해상도 4096 x 4096
고사양 컴퓨터에서 사용을 권장한다는 문구가 그제서야 눈에 들어온다..
This pack is almost 10GB in size
and with all features enabled is recommended for higher-end PC’s.
All features are recommended for highest quality results -
레벨 애셋 적용 후 랜더링 상태
프로젝트 크기 Draw Call Mesh Triangles Drawn FPS 12.5GB (+8GB) 1,698.98 27,147,798 80.1ms (약 12.5 fps) 프로젝트 자체 볼륨도 커져 파일 실행에 몇십분이 걸리는 상황이라 진행이 어려워졌다.
도대체 어느정도여야 할까? 기준 수치가 있을까?
사실 에디터 프레임드랍으로 체감하기 전까진 Tri의 수나 각 텍스처의 무게 등이 얼마나 무거운지 알 수 없었다.
상용화되는 게임이 어디까지 최적화 되어있는지 직접 해부해보고 싶은 마음에 에픽게임즈의 교육용 컨텐츠를 찾았고 그제서야
나의 프로젝트가 얼마나 처참한 수준인지 알 수 있었다.프로젝트 크기 Draw Call Mesh Triangles Drawn FPS 7.2GB 3,344 12,541,438 22.8ms (약 43 fps) 이렇게 엄청난 디테일과 고퀄의 레벨을 멀쩡히 돌릴 수 있게 해주다니..!
에디터 그래픽 설정으로 응급치료를 해두고, 가벼운 레벨에서 최적화 방법을 찾아 하나씩 적용해보았다.
랜더링 비용 확인방법
언리얼엔진 문서 1 를 통해 개념을 이해하고, 각종 유튜브 2 3 4 로 실제 적용사례를 공부했습니다.
| 구분 | 이름 | 내용 | 참고할 정보 |
|---|---|---|---|
| cmd | stat unit & unitgraph | 밀리초단위 프레임 수와 영향을 주는 요소 | CPU 게임 스레드, CPU 렌더 스레드, GPU |
| cmd | stat scenerendering | 뷰포트의 랜더링정보 통계자료 조회 | Mesh draw calls : 드로우콜 수 |
| cmd | stat RHI | RHI 메모리 및 퍼포먼스 통계 | Triangles drawn : 폴리곤 수 |
| 창 | 통계 | 프리미티브 관련 데이터 통계 확인 | 상위 Tri오브젝트 조회 |
| 시각화 툴 | GPU Visualizer | GPU작업 과정을 시각화 | 최적화필요 과정 확인 |
| 콘텐츠브라우저 | 사이즈맵 | 각 파일의 용량 정보 확인 | 상위 크기의 애셋 확인 가능 |
| 뷰포트 | 라이트복잡도 | 오버드로우 픽셀 복잡도 표시 | 중첩되어 낭비되는 픽셀에셋 확인 |
-
CPU, GPU사용량 확인 런타임, 에디터에서 확인 가능하며 에디터에선 STAT표시
Shift+L로 토글 가능
`cmd 호출 >stat unitstat unitgraph
FrameRate에 직접적인 영향을 주는 3개의 멀티스레드 :
구분 스레드명 내용 DX프레임워크에서의 유사과정 CPU Game C++, 블루프린트, 충돌, 물리등 게임로직 실행 Scene의 Update 단계 CPU Draw 오브젝트들의 정점정보와 Shader, Culling 등
계산을 마친 뒤 GPU에 전달 및 DrawCallScene의 Render단계
랜더링 파이프라인, Device와 DC가 하는 일들GPU GPU Draw스레드에서 전달받은 정보로 픽셀 표현 Draw 단계 한 프레임에 소요되는 시간은 각 스레드에서 소요된 시간의 합이며,
각 스레드의 작업이 끝나면 곧바로 다음 프레임에 대한 작업을 진행한다.
현재 내 프로젝트는 Draw스레드로부터 받은 정보를 처리하는 GPU스레드에서 심각하게 많은 시간이 소요되고 있음을 알 수 있다.
-
뷰포트에서의 DrawCall / Triangles Drawn 확인
`cmd 호출 >stat scenerendering
소모되는 시간이 많은 순서의 주요 랜더링 단계 및 랜더링 통계 확인
랜더링 과정에서 병목현상이 일어나는 주요 원인을 찾을 수 있고, Count 통계를 통해 드로우콜 수 등을 확인할 수 있다.
`cmd 호출 >stat RHI
RHI : Render Hardware Interface : 지원하는 플랫폼의 각기다른 그래픽 API에 대한 크로스플랫폼 인터페이스
랜더링에 사용되는 메모리크기를 확인할 수 있고 Count 통계를 통해 폴리곤(tri)수 등을 확인할 수 있다. -
프리미티브 통계정보 확인
창 > 통계
레벨에 배치된 액터들의 프리미티브 통계 확인 텍스처 크기가 큰 액터 또는 tri수가 많은 액터를 확인할 수 있다.
랜더링 비용 3대장
Oskar Świerad님 의 블로그 5 를 통해 언리얼의 랜더링 파이프라인 구조와 과정을 이해했습니다.
- Base Pass
- Shadow Depth
- Lights
✨LOD & HLOD
언리얼엔진 문서 6 7 를 참고해 개념을 이해하고 적용했습니다.
Level of Detail : 거리에 따른 메시 표현 복잡도를 단계적으로 적용해주는 방식으로 성능을 최적화해주는 기술
Hierarchical Level of Detail (계층형 LOD) : 다수의 스태틱 메시 액터를 아틀라스 처리된 텍스처를 사용해 단일 프록시 메시 및 머터리얼로 결합하는 방식으로, 드로우 콜을 프록시 메시 당 1개로 줄이며 거리에 따라 표현 복잡도를 차등적용해 주며 성능을 최적화해주는 기술
두 기능의 장단점을 확인하여 아래 기준으로 적용해주는게 가장 효율적이라 판단했다 :
- 메시 LOD 적용 : 사물, 나무와 같은 Prop 단위로 배치된 레벨에셋 중
- 갯수가 많음 (프리미티브 통계 상위 10위내)
- 폴리곤수가 많음 (프리미티브 통계 상위 10위내)
- HLOD 적용 :
- 건물과 같이 다수의 액터가 겹쳐져 있는 레벨에셋
- 상호작용이 불필요한 근거리 배경용 에셋
Mesh LOD 설정
우선 가장 시급해보이는 폴리곤수를 줄이기 위해 Mesh의 LOD를 아래와 같이 설정했다.
🚀 LOD 적용 장단점 분석
- 장점 : 디테일한 표현이 불필요한 거리의 에셋에 대한 랜더링비용을 절감할 수 있다.
ex) Triangles drawn: 27,147,798 → 14,627,936 (약 46% 감소)
- 단점 : LOD 추가당 감소된 폴리곤의 퍼센트만큼 메모리 증가한다.
ex) 41,348KB → LOD 1개 트라이 수 5% 추가: 42,677KB (약 3% 증가)
눈에 띌 정도로 메시가 급격히 바뀌는 설정은 시각적으로 보기 불편할 수 있기 때문에
메모리 부하를 주지 않을 만큼의 LOD수와 적절한 거리에 따른 감소세팅이 필요했다.
HLOD 설정
건물과 같은 다수의 엑터들이 겹쳐진 배경에셋 또한 불필요한 비용부담을 줄이도록 아래와 같이 HLOD를 설정해주었다.
🚀 HLOD 적용 장단점 분석
- 장점 : 멀리있는 다수의 배경에셋들을 결합해 한번의 드로우콜과 단일화된 머터리얼, 텍스처 사용으로 랜더링비용을 절감할 수 있다.
| 구분 | Draw call mesh | Tirangles Drawn | Texture Memory 2D | Draw | Frame |
|---|---|---|---|---|---|
| 기존 | 1,698.98 | 14,627,936 | 1033.36 MB | 76.26 ms | 80.1ms (약 12.5 fps) |
| 적용 후 | 1,447.42 | 13,522,253 | 696.23 MB | 0.08 ms | 63.6 ms (약 15.7 fps) |
- 단점 : 너무 많은 액터들로 HLOD 클러스터 프록시 액터를 생성할 경우 메모리에 부담을 줄 수 있다.
ex) 8개의 프록시 액터 생성으로 프로젝트의 디스크메모리는 약 100MB 추가됐다.
Texture 해상도 조율
그 외 방법들
에디터 그래픽 설정
Cull Distance Volume
Light Draw Distance
Directional Light Cascaded Shadow Map
Dynamic Shadow Distance Movalble Lights
Mesh Merge
생각정리
엔진 5로 버전업을 하면 하지 않아도 될 고생..
좀 더 가벼운 레벨애셋으로 작업하는게 어떨까요?
(사무용 노트북으론 너무 과한 작업이니) PC를 새로 구매하는게 어떨까요..?
이미 애니메이션 때문에 한땀한땀 과정을 옆에서 지켜본 동기들이 해준 말이었다.
작업속도도 느려지고 의미없는 고생을 사서하는건가 싶었지만, 성능최적화를 제대로 배워보는 시간을 가져보자는 마음에 관련기능 공부를 깊게 파고들었다.
거시적 관점에서 문제요소를 파악한 뒤 디테일을 찾아 필요한 기술을 적용하는 재미
이런 기능도 있었네! 어떻게 적용되는 거지?
꼬리에 꼬리를 물며 기능들을 살피다 보니 생각보다 너무 많은 정보에 뒤죽박죽 프로파일링이 되기도 했다.
언리얼 엔진에서의 랜더링 구조를 이해하고 나선 큰 범위에서 부터 점점 범위를 좁혀가며 적절한 최적화 방법을 적용하는 과정을 파악할 수 있었다.
이 후에 어떤 무거운 레벨을 적용해도 필요한 최적화 방법을 빠르게 적용할 수 있겠다는 자신감도 생겼다.
Reference
Unreal Engine Documentation. Cull Distance Volume Unreal Engine. Unreal Engine Documentation. Mesh Drawing Pipeline