unity3d 성능 최적화 방법론

원본 : http://3dmpengines.tistory.com/1516

참고 영상 https://www.youtube.com/watch?v=l4EX_RDVg2Q


[프로그램]

- update 보다는 코루틴을 활용하여 상태를 변경한다, 코루틴이 update 보다 더 빠르다
-FindObject 계열 함수는 상당히 느림으로 캐싱 작업으로 사용하는 것이 좋다
-Instanitate 와 Destory 함수를 이용한 프리팹의 생성/해제는 비용이 크다 -> 오브젝트 풀링으로 해결
-박싱 & 언박싱은 부하가 큰 작업
-문자열은 readOnly혹은 const 키워드를 사용하여 가비지 컬렉션으로부터 벗어나도록 한다

[메모리]
GC
메모리를 알아서 자동 해제, 문제점 : GC 에 메모리 해제의 명령어를 주기는 할 수 있지만 삭제되는건 GC 내부의 처리에 의해서 제거되는 것이기 때문에 해제 명령어를 준 시점에서 메모리가 해제 되지 않을 수 있다

가비지 컬렉터(GC)에 메모리를 많이 넘기지 않기

-오브젝트 풀링 시스템을 사용하기

-String 이 아닌 StringBuilder 사용하기, string 에서 두 문자열을 합칠때 + 연산 에서 임시 객체가 발생되어 GC 에 추가된다
 StringBuilder 를 사용할 경우 StringBuilder.Append() 문자열을 붙이는  함수는 임시 객체를 생성하지 않음

-Array 에 대해서 foreach가 아닌 for문을 사용 하는것이 좋다 배열에 대해 foreach를 사용할때 임시 객체가 생성된다 (: list , dictionary 의 경우는 괜찮음)
 foreach 한번 돌때 24byte 의 쓰레기 메모리 생성, 10번만 돌아도 240 byte 가 GC 에  수거 메모리를 넘김

- 태그 비교에는    if( go.tag == "enemy")  가 아닌 go.compareTag("enemy")  를 사용하여 비교한다, 그냥 문자열 비교에서 임시 객체 발생

- 값만 저장하는 데이터 타입에는 class 보다는 구조체를 사용한다  struct 는 stack 에 생성 되기 때문에 GC에 들어가지 않는다

- 즉시 해제할 때는 Dispose() 를 수동으로 호출해 즉시 해제 될 수도 있지만 Dispose()한다고 메모리가 바로 해제 되지 않을 수 있다 , 왜냐하면 GC에서 해제가 가능하다면 해제를 하지만 그렇지 않다면 그냥 지나가기 때문
 하지만 습관적으로 써 놓으면 해제 되는 경우들이 있기 때문에 메모리의 절감효과를 가져올 수 있다


- 임시 객체들을 만들어 내는 API를 조심하라
 : GetComponents<T>,   Mesh.Vertices,   Camera.allCameras, etc....    => 객체를 캐싱해두고 사용한다 
  GetComponents 의 경우는 느리기도 함


- 빈 콜백 함수는 제거 
   Start(), Update() 같은 콜렉함수는 비어있어도 성능에 영향을 끼친다 , 안쓴다면 제거함

- Unity는 c++ 기반으로 만들어 졌고 단지 위에 C# 스크립트로 덮어져 있는 상태임으로
이 둘을 왔다갔다 할때는 오버헤드가 발생한다  이런 왔다갔다 하는 종류는 Move() 가 있는데
이동 하는 수치 값을 C# 에 작성하지만 실질적으로 이 값은 Unity3d 내부로 전달됨(c++) 즉 이런 함수는 모든 처리가 된 후 한번만 호출 하도로고 설계를 하는 것이 좋음

- draw call 을 줄일 수 있도록 한다

-실제 게임에 올라오는 메모리가(텍스쳐포함) 어느정도 되는지 확인한다


[리소스]
-텍스처는 압축하여 사용
아이폰 : PVRCT,   (POWERVR)
안드로이드 DXT (TEGRA) , ATC  (Adreno) , ETC1 (공통)

-넥스처 사이즈는 무조건 2의 제곱이어야 한다
로드시 900 x 900 은 실제로 2의 배수로 변환됨 1024x1024로 변환됨


[텍스쳐 최적화]
-텍스처 atlas (아틀라스)를 활용하라
- 큰 텍스처에 여러 이미지를 우겨 넣는다
- UI 만 아니라 같은 재질의 오브젝트들을 묶음
한 화면에 나오는 텍스쳐 끼리,  알파가 있는 텍스쳐 끼리, 알파가 업슨 텍스처끼리 묶는다
- 찹축된 텍스처와 밉맵을 사용하자(대역폭 최적화) ,  툴 주에서 256 카라로 이미지를 쓸 수 있는 거의 아트적으로 손상 없이 쓸수 있는 툴 들이 있기도 하다-
텍스처 용량이 앱 다운 로드 용량에 영향을 많이 미친다
-보통 이미지 사이즈보다 좀 더 크게 메모리가 잡히게 된다



[메쉬]
-Import  할때 항상 Optimize Mesh 옵션을 사용하면 버텍스 캐쉬를 최적화 해준다 , 변환 전 / 변환 후 버텍스  캐쉬를 최적화 해준다

-항상  Optimize Mesh Data 옵션을 사용한다
 : Player setting > Other SEttings
   사용하지 않는 버텍스 정보를 줄여준다(Tangents, Normal, color, etc...)


[오디오]
- 모바일에서 스테레오는 의미 없다
 모두 92kb, 모노로 인코딩 , 모노로 설정하여 사운드 용량을 절반으로 줄인다

- 모바일 상에선 3D 사운드는 큰 의미가 없기때문에 2D사운드로 변경한다
-압축 -> mp3. ogg   압축시 음질 손상이 있기때문에 긴 음악 , 배경 음악의 파일 포멧으로 활용한다
-비압축 사운드 (wav) - 순간적인 효과음, 이펙트 등등..


[폰트 최적화]
한글, 영어, 일본어, 중국어 등,, 글로벌화 할때 글자에 의한 텍스처 용량이 증가한다
: => 
글자를 1024 * 1024 에 한픽셀당 넣을때 RGBA 채널을 활용하여 각 채널당 한 글자씩 넣도록 함  : Packed Font 라는 기법
그리하여 이미지 4 장을 한장의  용량으로 줄임



[리소스 기타]

ResourceLoadAsync() 함수는 엄청 수십배 느리다 (비동기 함수) -> ResourceLoad
- 게임 레벨 로드시에 사용했을 경우, 일반 함수에 비해 수십배나 느림


[그래픽 최적화]
Draw Call (DP Call)

"적절한 DP Call" 은 얼마 정도 인가?
: 일반적으로 100 이하를 추천, 보통 70~80 정도가 일반적적

!! PC에서는 DP call 차이가 많이 나지 않는다, 모바일에서 테스트를 해볼 것  : 차이가 50% 이상 차이가 날 수 있음
하지만  DC Call 은 게임마다 틀리긴 한데 DP Call 이 200 이라도 프레임이 60 정도 나오는 샤오미 Mi4 의 게임 등도 있음

!! 프레임을 먼저 확인 할것!!!

[Culling]
 : 가장 빨리 그리는 방법은 아무것도 그리지 않는 것
- 유니티의 각 Layer 별로 컬링 거리를 설정하는 것이 가능하다 !!!!!!!
- 멀리 보이는 오브젝트 성, 사냄ㄱ은 거리를 멀게 설정하고, 중요도가 낮은 풀이나 나무는 컬링 거리를 짧게 설정한다
- 오쿨루젼 컬링(보이지 않는 오브젝트르르 그리지 않는 것 ) , Window -> Occulusion Culling 메뉴에서 설정 가능   http://docs.unity3d.com/kr/current/Manual/OcclusionCulling.html


[오브젝트]
: 오브젝트 통합
! DP Call 은 오브젝트에 설정된 재질의 셰이더 패스당 하나씩 이러난다
! 렌더러에 사용된 재질의 수만큼 드로우 콜이 발생된다
DP Call 을 줄이기 위해서 각각 오브젝트를 따로 그리는 것이 아닌 붙일 수있는 오브젝트를 붙여서 DP Call 을 한번의 호출로 오브젝트를 그리도록 한다

: 오브젝트 통합 ( Combine )
 유니티에서 CombineChildren 컴포넌트를 제공하는데 이것은 하위 오브젝트를 모두 하나로 통합하는 컴포넌트이다 즉 Draw Call 한번으로 그릴 수 있게 된다
 -> 통합할 경우 텍스처는 하나로 합쳐저서 Texture Atlas를 사용해야 된다!!


[ Batch ] http://docs.unity3d.com/kr/current/Manual/DrawCallBatching.html

Static Batch
 Edit > Project Setting > Player 에서 설정
 움직이지 않는 오브젝트들은 Static 으로 설정해서 배칭함
 Static 으로 설정된 게임 오브젝트에서 동일한 재질을 사용 할 경우 자동으로 통합됨
 통합되는 오브트를 모두 하나의 커다란 메쉬로 만들어서 따로 저장(메모리 사용량 증가)
 스테틱 오브젝트의 경우 움직이면 안됨, 움직이는 즉시 유니티 내부에서 움직 일 수잇또록  물리 체계를 다시 만들어 버림

Dynamic Batch
- 동일한 메테리얼을 공유하고 다른 조건을 만족하면, Unity는 자동으로 움직이고 있는 오브젝트를 배칭합니다. 동적 배칭이 자동으로 처리되므로 어떤 노력이 필요하다는 것은 아닙니다.
 - 움직이는 물체를 대상으로 동일한 재질을 사용하느 경우 자동으로통합됨
  동적 배치는 계산량이 많음으로 정점이 900개 미만인 오브젝트만 대상이 된다
 움직이는 개체이지만 정점개수가 적으면 자동배치로 배치될 수 있음 > 옵션  껐다 킬 수 있음



[라이팅]
라이트맵을 사용하자! 필수    Per-Pixel Light 보다 2~3개 빠름
고정된 라이트와 오브젝트의 경우(배경) 라이트맵을 최대한 활용한다
아주 빠르게 실행됨 필셀 라이트보다 2~3배 빠름
GI 와 Light Mapper 를 사용하여 더 좋은 결과물을 얻을 수도 있다

-라이트 렌더 모드
 라이팅 별로 Render Mode : Important(픽셀)  /Not Important(정점) 셰이더  설정 기능
게임에서 중요한 동적 라이팅만 Important 로 설정
그렇지 않은 라이트들은 Not Important 로 설정한다



[Overdraw]  : 화면에 중첩해서 그릴때 퍼포먼스가 떨어진다 EX : 버튼
특히 2D 게임에서 DP Call 보다 더욱 큰 문제가 됨

기본적으로 앞에서 뒤의 순으로 그림, 깊이 테스트로 오버드로우를 방지한다, 하지만 알파 블렌딩이 있는 경우 알파 소팅 문제가 발생하게 됨

반투명 오브젝트의 개수에 재한을 건다
반투명 오브젝트이 지나친 사용에 주의 필요



[유니티 셰이더]
기본 셰이더는 모바일용 셰이더를 사용 할것
Mobile > VertexLit 은 가장 빠른 셰이더이다


!!!! 셰이더 실수 연산지 float 를 사용하지 않음 , 아주 느림 
-텍스쳐 UV 에는 Half 16bit 를 사용 float 보다 2배 빠름
-float 대신 fixed (10 bit ) 타입으로 사용  - 컬러, 라이트 계산과 같은 고성능 연산에 적합, 대략 4배 빠름



[물리 엔진]
Fixed Update 주기 조절
FixedUpdate() 는 Update와 별로도 주기적으로 불리며 주로 물리 엔진 처리에사용되는 함수
Default 로 0.01 초 -> 즉 1초에 50번 이 호출됨
TimeManager 에서 수정 가능!!!!
게임에 따라 0.2초(혹은 이상) 으로 수정해도 문제 없음

충돌체의 이동
 리지드 바디가 없는 고정 충돌체를 움직이면 CPU 부하 발생,  - 물리 월드 재구성이됨
이럴 경우 리지드 바디를 추가하고 IsKinematic 옵션을 사용해서 부하를 줄인다

Maximum Allowed timestep 조정
-시스템에 부하가 걸려, 지정된 사간보다 오래 걸릴 경우, 물리 계산을 건너뛰는 설정도 있다

-움직이지 않는 오브젝트 들은 휴면 상태로 들어감 이때 물리 업데이트를 하지 않음
이것은 기본적으로  리지드 바디의 속력이 설정된 값보다 작을 경우 발생하게 됨
-Physics.Sleep() 함수를 이요하면, 강제 휴면 상태로 만들 수 있다

-2D 게임은 2D 물리로, 3D 는 3D물리를 사용한다

-렉돌은 꼭 필요할때만 활성화 한다, 그 이후엔 비활성화

- 물리 처리엔 태그보다는 레이어로 처리할때 더 유리하다, 성능과 메모리측면에서 장점을 가짐

- 메쉬 콜라이더는 절대 사용하지 않는다

- 레이캐스트와 Sphere Check 같은 충돌 감지 요소를 최소화 한다 ( 탐색하면서 성능 저하됨 )



Tilemap Collision Mesh
2D 게임에서 타일맵의 Collision Mesh 를 최적화하라
타일맵을 디폴트롤 사용해서 각 타일별로 충돌 메쉬가 있는경우, 물리 부하가 커진다
연결된 타일맵을 하나의 Collision Mesh로 물리연산을 최적화 하라

댓글

가장 많이 본 글