[ 병목현상 원인 ]
[ CPU ]
너무 많은 Draw Call
복잡한 Scripts
복잡한 Physics
[ Vertex Processing ]
너무 많은 Vertex
버텍스당 너무 많은 연산 (복잡한 Shader)
[ Fragment Processing ]
너무 많은 OverDraw
너무 많은 Fragment 연산 (Fragment 셰이더 /픽셀 셰이더)
[ Band Width ]
크고, 압축되지 않은 텍스쳐
고해상도 프레임 버퍼
[ 프로 파일러 ]
병목 현상을 체크
Window >> 프로파일러 - 최권희
[ 스크립트 최적화 / GC ]
FindObject 계열의 함수는 느리다 (미리 찾아서 캐싱)
나눗셈보다는 곱셈이 몇 십배 빠르다.
magnitude 보다는 sqrMagnitude를 사용해서 비교한다.
magnitude : 벡터의 길이를 float로 얻음
sqrMagnitude : 벡터의 길이 제곱을 float로 얻음(sqrt 안함)
삼각함수의 값은 상수로 저장하고, 사용하는 것이 좋다.
빈 가상 함수는 제거
비어있는 Start(), Update() 같은 함수는 성능에 영향을 미친다.
ResourceLoadAsync() 함수는 엄청 느리다
게임 레벨 로드시에 사용했을 경우, 일반 함수에 비해 수십배나 느렸다.
Update()에서의 처리보다는 Coroutine 처리를 한다.
8. 충돌체의 이동
- 리지드 바디가 없는 고정 충돌체를 움직이면 CPU에 부하가 발생된다.
- 이 경우, 리지드 바디를 추가하고 IsKinematics 옵션을 준 후 움직이는 것이 좋다.
10. Solver Iteration Count 조절
- 물리 관련 계산을 얼마나 정교하게 할 것인지 지정. ( 높을수록 정교해진다. )
- Edit > Project Settings > Physics 메뉴에서 설정.
11. Sleep 조절
- 리지드 바디의 속력이 지정된 수치보다 작을 경우, 자동으로 휴면 상태에 들어간다.
- Edit > Project Settings > Physics 메뉴에서 설정.
- Physics.Sleep() 함수를 이용해서 강제 휴면 상태를 만들 수도 있다.
(Awake()함수에서 사용하면 레벨이 로딩되기 전까지 물리 엔진 사용을 자제시킬 수 있다.)
[ Garbage Collector (GC) 관련 ]
[ 기본 지식 사항 ]
가비지 컬렉션(Garbage Collection)
더 이상 사용되지 않는 메모리는 알아서 해제해 줌
Reference Type과 Value Type
복사되는 메모리와 주소를 참조하는 객체를 명확히 구분
Reference Type
참조 타입, 인스턴스의 주소 값만 참조
Heap 영역에 메모리 할당
예> class 등으로 생성된 Instance
Value Type
값 타입, 데이터 크기만큼 실제 메모리 복사
Stack 영역에 메모리 할당
예> int, float 등의 기본 타입과 구조체
가비지 컬렉션
GC.Collect()
항당된 메모리들 중에 가비지를 골라서 메모리를 해제
CPU 장시간 점유, GC는 큰 비용이 드는 작업
가비지 컬렉션 시점
메모리를 더 이상 할당 할 수 없을 때
가비지가 어느 정도 쌓이면 스스로 수행
System.GC.Collect() 호출시
데이터 타입에는 class 대신 구조체 사용
구조체는 GC에 들어가지 않는다. Stack 영역에 할당되기 때문
Value와 Reference의 차이
Vector3 자료형은 지역 변수(Stack 영역)
Transform은 Reference (Heap 영역)
Instantiate/Destroy 함수를 이용한 프리팹 생성/해제는 비용이 큼
오브젝트 풀링으로 사용 권장
에셋스토어에 이미 만들어진 오브젝트 풀링 소스가 있다.
예제> 오브젝트 풀 스크립트 작성할 것 - 임수동
적절한 시기에 메모리 정리
GC.collect() / Resources.UnloadUnusedAsset() 호출해서 텍스쳐등 실제 메모리에서 제거
그렇다고 원하는 시점에 처리되지 않는다.
Dispose 수동 호출
오브젝트의 dispose를 수동으로 호출하여, 즉시 cleanup
예제> 해볼 것
WeakReference
System.WeakReference 클래스
GC에 의한 객체 회수를 허용하면서 객체 참조
WeakReference 객체로 참조 중인 인트턴스가 삭제되면 null로 자동 셋팅
Dispose와 같이 사용하면 훌륭할 수 있다는
참조 : http://mirwebma.tistory.com/142 / http://ehdrn.tistory.com/335
임시 객체들을 만들어내는 API들을 조심
GetCoponents<T>, Mesh.Vertices, Camera.allCameras, etc
한번만 호출하여, 객체를 캐싱해두고 사용하자
문자열의 병합은 StringBuilder
StringBuilder.Append()함수를 사용하여 병합
예제> 해볼 것 - 최윤서, 조호용
foreach 대신에 for문 사용
foreach는 한번 돌 때마다 24byte의 쓰레기 메모리를 생성 ( 데이터 타입을 일치하기 위해 임시 메모리를 사용)
태그 비교에는 compareTag() 사용
if(go.tag == "enemy") 대신에 go.compareTag("enemy") 사용 (tag 프로퍼티를 호출하는 것은 추가적인 메모리를 할당하고 복사함)
박싱(Boxing)과 언박싱(Unboxing) 줄이기 - 최윤서, 조호용
Boxing : 값(Value) 타입을 참조(Reference)타입으로 변경하는 것
Boxing은 스택에 있는 값을 힙에 새로운 공간을 생성한 후 복사 한다. 이 공간을 Box 라고 부른다.
Unboxing : 참조 타입을 값 타입으로 변경하는 것
Unboxig은 Boxing 된 참조타입을 이전 값 타입으로 다시 변경하는 것으로 , 해당 참조가 대상으로 지정한 값 타입을 Boxing 한 값인지 확인 한 후 , 힙에 존재하는 객체의 값을 스택에 있는 값으로 복사한다.
결과 적으로 Boxing 과 Unboxing 을 거치면 메모리상에 2개의 메모리가 생성되는데, 주로 Collection에서 boxing이 빈번하게 발생
자료구조(Collection)
Array : 아이템들의 크기가 일정하고, 순서가 변할 일이 없다면 일반 배열을 사용하는 것이 가장 빠르게 동작한다.
ArrayList : 아이템들의 크기가 자주 변하고 순서도 자주 바뀌는데다, 모든 아이템이 레퍼런스형일 경우 사용한다.
List<T> : ArrayList인데 저장하는 데이터가 밸류 타입이면 제네릭 List를 사용해야 박싱이 일어나지 않는다.
Hashtable : 키와 값으로 구성된 사전류의 데이터를 관리할 때 해시 테이블을 사용하면 편리하다.
Dictionary<K, V> : 해시 테이블과 동일한 기능을 수행하나, 데이터의 형식이 밸류 타입이면 제네릭 Dictionary를 사용해야 박싱이 일어나지 않는다.
예제> 해볼 것
[ Resource 최적화 ]
[ Texture ]
Import시 "Optimize Mesh" 옵션 사용
변환 전/후 버텍스 캐쉬를 최적화 해준다.
Player Setting > Other Settings
예제> 해볼 것
텍스쳐 사이즈는 2의 제곱근 (POT : Power of Two)
POT가 아닌경우 POT가 되도록 유니티가 자동 변환한다.
텍스쳐 아틀라스를 활용하라.
UI만이 아니라, 같은 재질의 오브젝트들을 묶음
예> UI만 해볼 것
압축된 텍스쳐와 밉맵을 사용하자. (대역폭 최적화)
32bit가 아닌 16bit 텍스쳐 사용도 상황에 맞게 고려.
흰색 그림에 색깔을 입히는 형태로 다양한 UI 연출
폰트 이미지 - 최우성
Packed Font 활용
Packed Font는 언제 사용할까??
위의 이미지 처럼 3개의 언어를 지원하는 경우에 각 언어에 해당하는 폰트를 써야한다.
그렇다면 폰트는 어떻게 저장이 될까?
한국어와 영어가 합쳐서 2048*2048을 꽉 채우지 못하는데 일본어는 혼자서 2048*2048!!
만약 중국어를 지원해야 한다면??
위에서 무엇이 문제인지 모르겠다면 아래 이미지를 보면 더 확실하다.
위의 문제를 해결하기 위해 Packed Font를 사용한다.
그렇다면 Packed Font의 원리는 무엇인지 알아보자.
- 원리 : R, G, B, A 채널에 문자를 저장하는 방법이다. (아래 그림 참초)
Packed Font의 장점
- 4개의 채널에 각각 저장하기 때문에 메모리 사용량을 1/4를 줄일 수 있다.
장점이 있으면 단점이 있는법.
Packed Font의 단점들!(무려 단점들 이다.)
- 각각의 RGBA 채널에 저장하므로 그림자 같은 고퀄리티 효과를 사용할 수 없다.
- 알파블랜딩이 불가능 해진다.
- NGUI 아틀라스 사용이 불가능해진다.
실습 및 더 자세한 설명은 아래 동영상 및 이미지를 참고하면 된다.
- 동영상
- 이미지를 이용한 설명(위 동영상과 다름)
위의 RGBA채널에 저장하는 Packed Font된 이미지파일을 만들자.
Unity 3D와는 상관없으므로 자세한 설명은 하지 않겠다.
BM Font 라는 프로그램을 설치해서 만들면 된다고 함.
1. 유니티로 파일을 넣는다.
2. Texture Type 을 Advanced로 바꾼다.
3. NGUI Font Maker를 열어서 폰트를 만든다.
4. 폰트파일이 생성되었다.
5. NotoFont의 메터리얼의 인스펙터에 들어가면
default로 Shader가 "Unlit/Transparent Colored"로 되어 있다.
이걸 "Unlit/Transparent Packed"로 변경해야 한다.
[ Material 관련 ] - Draw Call 확인
Batches
Object Combine - 전수라, 차수빈
Script 패키지 - CombineChildren 컴포넌트 제공
하위 오브젝트를 모두 하나로 통합
통합하는 경우 텍스쳐는 하나로 합쳐서, Texture Atalas를 사용해야 함
-CombineChildren 컴포넌트를 사용할 경우, 하위 오브젝트가 모두 하나가 되어서 빛의 계산을 모두 수행하는 등 불필요한 계산이 발생하는 단점도 있다.
예제> CombineChildren해볼 것
예제>
하나의 모델링에 여러 메터리얼(모델링당 다른 머터리얼) & 하나의 모델링에 하나로 합친 머터리얼(다른 메터리얼들을 하나로 합친 머티리얼)
여러 개의 모델링에 하나의 메터리얼 생성하는 결과물 예제 만들기
Static Batching & Dynamic Batching
Static Batch
움직이지 않는 오브젝트들은 static으로 설정
static으로 설정된 게임 오브젝트에서 동일한 재질을 사용할 경우 자동으로 통합
통합되는 오브젝트를 모두 묶어 커다란 메쉬로 만들어서 따로 저장(메모리 사용량 증가)
Dynamic Batch
움직이는 물체를 대상으로 동일한 재질을 사용할 경우, 자동으로 통합
동적 배칭은 계산량이 많으므로, 정점이 900개 미만인 오브젝트만 대상이 됨
예제> 옵션 키고 끄는 걸로 보일 수 있도록 - 차수빈, 전수라
Cast Shadows & Receive Shadows -
예제 실습
Cast Shadows 실습
Receive Shadows 실습
Shader(Particles/Alpha Blended)를 이용한 Shadow 처리 실습
[ Sound ]
모바일에서 스테레오는 의미 없음 >> 모노로 인코딩
2D 사운드로 변경 (사운드 import시 자동 3D 사운드)
압축 사운드(mp3, ogg), 비압축 사운드(wav) 구별
압축 사운드 : 배경 음악 / 비압축 사운드 : 효과음
[ Graphics PipeLine 최적화 ]
[ CULL ]
프러스텀(Frustum) 컬링
Layer 별로 컬링 거리를 설정하는 것이 가능하다.
멀리 보이는 중요한 오브젝트는 거리를 멀리 설정하고 중요도가 작은 풀이나 나무등은 컬링 거리를 짧게 설정한다.
참고 : http://docs.unity3d.com/kr/current/Manual/class-Camera.html
예제> 해볼것
오클루젼(Occlusion) 컬링
http://www.inven.co.kr/webzine/news/?news=48504
예제> 해볼 것
예제> 해볼 것
[ Shader ]
Shader의 Mult-pass
예제 실습
Pass에 따른 Batches 확인
기본 셰이더는 모바일용 셰이더 사용
Mobile > VertexLit은 가장 빠른 셰이더
복잡한 수학 연산 자제
pow, exp, log, cos, sin 같은 수학 함수들은 고비용
텍스쳐 룩업테이블을 만들어서 사용하는 방법이 좋다.
예제> 해볼 것
알파 테스트 연산(discard)은 느리다.
기본적인 연산보다는 최적화 시키고 간략화시킨 공식들을 찾아서 사용한다.
실수 연산
float : 32bit - 버텍스 변환에 사용. 아주 느린 성능(픽셀 셰이더에서 사용은 피함)
half : 16bit - 텍스쳐 uv에 적합. 대략 2배 빠름
fixed : 10bit - 컬러, 라이트 계산과 같은 고성능 연산에 적합. 대략 4배 빠름
[ Light ]
라이트 맵 사용
고정된 라이트와 오브젝트의 경우(맵) 라이트 맵을 최대한 활용
아주 빠르게 실행된다.(Per-Pixel Light보다 2~3배)
더 좋은 결과를 얻을 수 있는 GI와 Light Mapper를 사용할 수 있음
(Pixel) Light 개수 처리
예제>
(Pixel) Light 개수에 따른 Draw Call 확인
Light의 Render Mode : Not Import에 따른 Draw Call 확인
[ Overdraw ]
화면의 한 픽셀에 두번 이상 그리게 되는 경우(Fill rate)
특히 2D 게임에서는 Draw Call 보다 더욱 큰 문제가 된다.
Depth testing으로 인해서 오버드로우를 방지한다.
하지만 알파 블랜딩이 있는 오브젝트의 경우에는 알파 소팅 문제가 발생
반투명 오브젝트는 뒤에서부터 앞으로 그려야 한다. -> Overdraw 증가
[ 스크립트 최적화 / GC ]
[ Fixed Update 주기 조절 ]
FixedUpdate()는 Update와 별도로 주기적으로 불림
디폴트는 0.02초, 즉 1초에 50번이나 호출
TimeMangaer에서 수정 가능
게임에 따라, 0.2초 정도(혹은 그 이상)로 수정해도 문제 없음
예제> 해볼 것
[ 물리엔진 설정 및 물리 엔진 스크립트]
Static Object : 움직이지 않는 배경 물체는 static으로 설정
Maximum Allowed timestep 조정
시스템에 부하가 걸려, 지정된 시간보다 오래 걸릴 경우, 물리 계산을 건너뛰는 설정
PhysicsManager : Solver Iteration Count 설정
물리 관련 계산을 얼마나 정교하게 할지를 지정(높을 수록 정교)
Sleep 조절
리지드 바디의 속력이 설정된 값보다 작을 경우, 휴면상태에 들어감
Physics.Sleep()함수를 이용하면, 강제 휴면 상태를 만들 수 있음( 각 GameObject 당)
ControllerColliderHit 콜백에 의존하지 않게 코드를 수정
이들의 콜백은 빠르게 작동하지 않음
천 물리 설정은 스킨드 메쉬로 교체
미학적인 부분과 성능적인 균형을 고려해야 함
래그돌 사용 최소화
래그돌은 또 다른 물리 시뮬레이션이기 때문에 꼭 필요한 경우에만 활성화
태그 대신 레이어
물리 처리(충돌처리)에서 태그로 처리하는 것보다 레이어가 훨씬 유리, 성능과 메모리에서 장점을 가진다.
메쉬 콜라이더는 사용하지 않는다.
레이케스트와 Sphere Check 같은 충돌 감지 요소를 최소화
Tilemap Collision Mesh
2D 게임에서 타일맵의 Collision Mesh를 최적화
연결된 Tilemap을 하나의 Collision Mesh로 물리 연산을 최적화하라.
[ 기타 ]
권장 텍스처 사용하기.
아이폰 (PowerVR) : PVRTC
안드로이드 (Tegra) : DXT
안드로이드 (Adreno) : ATC
안드로이드 (공통) : ETC1
[ 참고 사이트 ]
http://www.slideshare.net/hnam7/unite-2013-optimizing-unity-games-for-mobile-platforms-37933478
http://www.slideshare.net/AlexanderDolbilov/google-i-o-2014?next_slideshow=1
http://www.slideshare.net/hnam7/unite-2013-optimizing-unity-games-for-mobile-platforms-37933478
http://lonpeach.com/2017/02/19/unity3d-optimizing-performance/
http://blog.naver.com/PostView.nhn?blogId=whitejopd&logNo=70166651512
https://docs.unity3d.com/kr/2018.4/Manual/MobileOptimisation.html
https://devbobos.github.io/2018/03/06/Unity-%EC%B5%9C%EC%A0%81%ED%99%94-Tips.html