유니티 엔진 (Unity Engine)

유니티 그래픽스 최적화 - 3.병목

원소랑 2019. 8. 26. 19:41
728x90

.

.

유니티 리드 에반젤리스트 오지현님의

"유니티 그래픽스 최적화 스타트업" 오랜만에 다시 읽기 시작해서 정리를 해봤습니다. 왜 3챕터부터냐... 는 정리 하고싶은 챕터 먼저 다시 읽어서요. 다른 챕터도 다시 읽고 정리해보겠습니다.

제가 다시 볼 목적으로 간략하게 정리한 포스트입니다. 자세한 설명은 책 본문에서 확인해주세요.

 


 

3. 병목 ( Bottleneck )

 

최적화의 가장 중요, 병목 제거

 

3-1 병목의 이해, 측정, GUI 병목 탐지

 

보통의 최적화 목록

- 매시 버텍스 줄이기

- 텍스쳐 크기 줄이기

- 가벼운 쉐이더

- 드로우콜 줄이기

- 게임 로직 최적화

- 물리 연산 줄이기

- 기타 등등...

 

프로파일링을 잘 해야한다.

 

최적화의 처음은 게임의 타깃 기기를 결정하는 것.

주 타깃 기기와, 시장에서 주로 쓰이는 대표적인 디바이스 확인

 

성능에 따라 병목 지점이 달라질 수도 있다.

ex) 아이패드 해상도가 올라가면서 픽셀 수가 많아져서 병목이 됨.

 

03) FPS 와Frame Time

 

FPS 보다는 한 프레임 처리에 걸리는 Frame Time 기준으로 처리하는 게 좋다.

 

에디터의 Game 뷰 좌측 상단의 Stats 를 누르면 FPS와 Frame Time MS 를 확인 가능.

But, 에디터에서의 성능 측정은 큰 의미가없고 실제 디바이스에서 측정해야 함.

 

Time.unscaledDeltaTime

은 한 프레임 처리를 위한 시간.

 

04) 구간 측정

FPS 로 측정해서 최적화 하기 보다는, 모듈마다 실제로 몇 MS가 걸렸는가를 두고 최적화 해야 함.

 

05) 선형적인 측정

FPS 로만 측정하면, 실제로 어떤 모듈이 얼마나 느려졌는지 알 수 없음.

오브제1개 = 90FPS = 1000 / 90.0 = 11.1 ms

오브제2개 = 45FPS = 1000 / 45.0 = 22.2 ms

오브제3개 = 30FPS = 1000 / 30.0 = 33.3 ms

 

오브젝트 하나당 11.1ms 이지만 FPS를 선형적으로 감소하지 않음.

 

06) 측정 시나리오

측정할 땐 여러번 측정하고 편균을 내야 한다. 오브젝트가 몇 개 없는 간단한 씬이라고 해서 무조건 FPS 가 높지 않을 수도 있다. 가령, Deferred 인 경우에는 영향이 큼. 디퍼드 렌더링 패스는 기본적으로 대역폭 요구 성능이 큼.

 

후처리도 비용이 큼. DOF, Bloom 활성화 여부.

 

07) Target Frame Rate

모바일 디바이스가 과부하 돼서 쓰로틀링 상태가되지 않도록 하는 것도 방법. 강제로 최대 FPS 를 설정할 수도 있다.

Application.targetFrameRate = 40; // 40 FPS 로 강제 설정

 

60FPS 가 충분히 나오는지 보기 위해 60 으로 설정해서 맞추는 것이 좋음. 60까지 나오는데 쓰로틀링 방지를 위해 40으로 강제하는 방향으로.

 

내장 프로파일러의Wait For Target FPS 항목에서 한 프레임 마치고 얼마나 쉬는지 확인.

 

08) VSync (수직동기화)

targetFrameRate를 높게 설정해도 안 넘는 경우, VSync 도 의심해 봐야 함.

모니터 화면 갱신 주파수의 한계, 신호를 넘겨서 랜더링하는 경우 화면이 물결치거나 찢어져 보이게 됨.

백버퍼와 프론트 버퍼를 전환할 때 섞여보이게 됨. 티어링 현상(Tearing)

 

방지하기 위해 VSync 설정. 단, 퍼포먼스도 같이 조절되기 때문에 targetFrameRate 설정과 같은 효과. 성능 병목 측정할 땐 꺼주는 것이 좋다.

 

Edit > Project Settings > Quality 에서 설정. Don’t Sync 로 비활성화.

Edit > Project Settings > Quality 선택, 플랫폼별 기본 설정 레벨은 녹색 체크박스로 표시됨.

퀄리티 세싱 항목들, 세부 설명은 메뉴얼에서 확인

https://docs.unity3d.com/kr/current/Manual/class-QualitySettings.html

 

09) 쓰로틀링(throttling)을 고려한 측정

모바일 디바이스, 쓰로틀링 염두해두고 성능 프로파일링 해야.

- 타깃 디바이스가 얼마나 빠르게 쓰로틀링 상태로 진입하고, 얼마나 성능 떨어지는지

- 열기 영향받지 않도록 떨어트린다

- 배터리는 항상 100%, 단 충전중 온도가 올라갈 수도 있다.

- 측정 후, 다음 측정까지 5분 정도 대기

- 아이스팩이나 쿨링팬으로 쿨링

- 최신 기종일 수록 성능이 좋아서, 쓰로틀링 상태에 빨리 진입할 수 있다

- 기기마다 쓰로틀링 단계가 다름. 여러단계로 하락하기도.

 

10) CPU 바운드(bounds) VS GPU 바운드

병목이 CPU 인지 GPU 인지 확인해야 함.

CPU/GPU 는 직렬로 작동하는 것으로 오인하는데, 병렬처리 방식이다.CPU 는 명령을 던지고 계속 자기 일을 처리함. 한 프레임에서 CPU 는 일처리를 모두 마쳤지만, GPU 가 받은 작업을 순서대로 처리하는데 안 끝났다면 CPU 는 기다리게 됨. GPU 바운드 상태라고 하고, GPU 작업을 줄여줘야 함.

반대의 경우 GPU 최적화 해봤자 무의미하고 CPU 작업을 줄여줘야 함.

 

3-2 병목 측정

 

01) 유니티 내장 프로파일러 측정

프로파일러 연결은 개발빌드로 연결해야하는데, 측저 부하가 포함되므로, 릴리즈 빌드와는 차이가 있다. 플랫폼 디바이스에서 직접 측정 해봐야 함. 에디터 측정은 큰 의미가 없다.

 

테스트용 프로젝트

Survival Shooter Tutorial 샘플 튜토리얼 프로젝트 다운로드 해서 측정.

비디오 강좌

https://unity3d.com/kt/learn/tutorials/projects/projects/survival-shooter-tutorial

 

안드로이드 빌드 환경설정

https://docs.unity3d.com/kr/current/Manual/android-sdksetup.html

 

Asserts/PostProcessing 폴더 통째로 삭제. 퀄리티 셋팅에서 레벨을 높여준다. Android 아이콘 Default 드랍박스 선택해서 Fantastic 으로 변경. 녹색으로 변하면 설정된 것.

 

Project Settings > Player 를 선택, Other Settings 의 Rendering / Color Space 를 Linear 에서 Gamma 로 병경. OpenGL ES 버전 호환성 때문. Linear 로 설정하면 OpenGL ES 2.0 을 지원하지 못함.

 

Build Settings 에서 Development Build 와 Autoconnect Profiler 를 체크.

 

구형 디바이스일 수록 PlayerLoop > ... > Graphics.PresentAndSync > Device.Present 가 상위권. CPU 가 GUI의 일처리가 끝날 때까지 기다리고 있는 시간. 이 숫자가 크면 GPU 병목이라는 의미.

 

3-3 GPU 병목 탐지

 

GPU 병목은 내장 프로파일러로는 디테일하게 파악이 힘듬. 렌더링 파이프라인의 어느 부분이 문제인지 찾아야 함. 안드로이드는 그래픽스 API 가 Vulkan 일 경우 지원이 가능. Open GL ES 는 NVIDAI 와 Intel GPU 디바이스만 지원 가능.

 

Snapdragon 칩셋을 사용하는 디바이스는 Qualcomm 에서 제공하는 전용툴로 GPU 프로파일링.

 

아이폰, 아이패드는 XCode 에서 제공하는 GPU FrameDebugger 를 이용하는 GPU 프로파일링

 

스냅드래곤 프로파일러, 엑스코드

 

01) 필레이드 (Fillrate)

Fillrate 는 그래픽카드가 1초에 스크린에 렌더링할 수 있는 픽셀의 수.

 

게임에선 더 많은 뜻을 내포. 픽셀 처리에 대한 부담을 의미.

필레이트 = 픽셀(Pixel) 수, 프래그먼트 쉐이더 복잡도(Fragment Shader Complexity), 오버드로우(Overdraw)들을 포함한 개념.

 

필레이트 = 화면 픽셀 수 x 프래그먼트 쉐이더 복잡도 x 오버드로우

 

래스터라이저 스테이지에서 병목이 발생.

간단하게 확인 = 디스플레이 해상도를 변경해보면 됨. 픽셀 수가 변하기 때문에.

 

해상도 변경 = Edit > Project Settings > Player 에서

Resolution Scaling 항목을 수정.

Resolution Scaling Mode 는 기본 Disabled. Fixed DPI 로 변경해서 DPU 에 맞게 자동 조정되도록 할 수 있다. DPI 가 낮을 수록 해상도가 낮게 조절됨.

 

특정 해상도 강제 = Screen.SetResolution() 메소드로 조절

https://docs.unity3d.com/ScriptReference/Screen.SetResolution.html

 

02) 오버드로우(Overdraw)

화면에 렌더링 되는 픽셀이 여러 번 덧그려지는 현상. 채워진 픽셀을 또 다른 오브젝트 렌더링 하면서 다시 그리면 오버드로우.

렌더링 파이프라인의 Z버퍼(Z Buffer, Depth Buffer)는 오버드로우 방지를 도와줌. 오브젝트를 렌더링할 때 Z버퍼의 내용도 같이 채워짐. 카메라 기준 뒤에 있는 오브젝트가 렌더링 되면 Z버퍼에 의해 픽셀이 걸러져 오버드로우가 방지됨. 카메라와의 거리를 기준으로 정렬한 뒤 순서대로 렌더링.

 

불투명(Opaque) 오브젝트는 앞에서 뒤로 정렬(Front to Back Sorting) 카메라 앞에서 뒤로 정렬. 뒤에 있는 오브젝트의 가려지는 픽셀은 렌더링을 건너 뜀.

 

투명(Transparent) 오브젝트는 반대로 뒤에서 앞으로 정렬 (Back to Front Sorting). 뒤가 비춰져야 하기 때문. 즉, 투명 오브젝트는 모든 픽셀에서 오버드로우가 발생.

 

투명 오브젝트는 오버드로우 + 프레임 버퍼 일겅올 때 병목 발생. 블렌딩 연산을 위해 픽셀의 컬러를 혼합.

 

최종 픽셀 컬러 = 현재 픽셀 컬러 x 알파 + 프레임버퍼의 픽셀 컬러 x (1-알파)

 

투명 오브젝트는 최소한 필요한 곳에서만 사용하는 것이 좋다. 파티클은 오버드로우가 과도하게 발생하기 쉬움. Scene View 좌상단 Draw 모드를 Overdraw로 두면 오버드로우를 확인할 수 있다. 픽셀이 밝을 수록 오버드로우가 많이 일어나는 픽셀.

 

03) 포스트 프로세싱 (Post Processing)

프래그먼트 쉐이더가 무거워지는 흔한 요인 중 하나는 이미지 효과. 해상도를 줄이면 해결. 픽셀 단위로 처리하기 때문에 종류별 성능 코스트가 다름. Color Grading 은 모바일 괜찮. Bloom 도 디바이스 성능이 좋아져서 해결. 하지만, DOF는 성능 부담이 큼(모바일). 인게임보다는 컷씬이나 로비 등에서 권장. DOF는 프래그먼트 쉐이더의 부담 뿐 아니라 드로우콜이 늘어나는 요인.

 

전체적 룩앤필을 고품질로 유지하려면 해상도를 줄이는 것이 가장 간단. 일부 스마트폰은 게임 실행시 강제로 해상도를 줄이는 기능을 제공하기도. (삼성 게임센터)

 

* 유니티 제공 포스트 프로세싱 스택 (Post Processing Stack)

- Antialiasing (FXAA, Temporal AA)

- Motion Blur

- Chromatic Aberration

- Ambient OCclusion

- Eye Adaptation

- Grain

- Screen Space Reflections

- Bloom

- Vignette

- Fog

- Color Grading

- Dithering

- Depth of Field

- User Lut

에셋스토어

https://www.assetstore.unity3d.com/en/#!/content/83912

 

패키지 매니저 Window > Package Manager 의 All 탭에서 설치

Post Processing 선택 후 Install 버튼을 눌러 설치.

 

04) 업스케일링 샘플링 (Upscale Sampling)

해상도를 줄이면 픽셀이 도드라지니, UI는 원래 해상도로, 3D 씬만 낮은 해상도로. 이 트릭을 흔히 업스케일링 샘플링(Upscale Sampling) 이라고 부릅니다. 오래 전부터 사용되오던 트릭.

 

룩앤필은 고품질로 유지하면서 해상도를 줄이는 트릭.

구현 스텝

- 저해상도 렌더 텍스처(RenderTexture)를 생성

- 3D 씬을 렌더 텍스처에 렌더링

- 렌더 텍스처를 업스케일링(Upscaling)해서 현재의 백 버퍼에 렌더링

- 오버레이(Overlay) UI를 렌더링

 

전체 해상도는 줄이지 않고, 저해상도의 렌더 타깃으로 렌더 텍스처를 생성하여 렌더링.

샘플 링크

https://github.com/ozlael/UpsamplingRenderingDemo

 

05) 폴리곤 (Polygon)

렌더링 할 폴리곤이 많으면 지오메트리 스테이지 병목. 버텍스 쉐이더를 그만큼 많이 수행해야 한다는 의미. 버텍스를 줄여서 성능체크를 해보면 됨.

LOD 적용으로 버텍스를 줄여서 병목 해결. 맥스같은 DCC(Digital Content Creation) 툴에서 모델을 수정해야겠지만, 자동 생성.

에셋 스토어의 LOD, Mantis LOD Editor - Professional Edition, Mesh Implify

퀄리티 셋팅 윈도우에서 LOD Bias 를 조절. LOD 그룹 컴포넌트로 LOD 레벨.

 

06) 텍스처 (Texture)

텍스처 메모리 대역폭이 작은 모바일 디바이스에서 크기가 큰 텍스처는 병목이 될 수 있음.

Edit>Project Settings>Quality 에서 Rendering 섹션에서 텍스처 해상도 조정 가능.

 

텍스처 성능 관련 자세한 내용은 Part 08 에서.

정리

1. 병목의 이해

FPS와 Frame Time, 구간 측정, 선형적 측정, 측정 시나리오, Target Frame Rate, VSync, 모바일 기기 쓰로틀링, CPU 바운드와 GPU 바운드 구분

 

2. 프로파일러 활용

 

3. GPU 병목 탐지

Fill Rate, 오버드로우, 포스트 프로세싱, 업스케일 샘플링, 폴리곤, 텍스처

.

.

728x90
반응형