본문 바로가기

유니티

유니티 최적화 - Engine

스크립팅 최적화

  • sendMessege 와 broadcastMessage 함수 사용 자제 (문자열을 통해 함수를 살펴보면서 무거운 연산을 동반함)
  •  find 관련 함수 사용 자제 (씬 내 오브젝트를 검색해서 반환하면서 씬내 모든 오브젝트를 검사하기 때문에 성능 이슈 동반)
  • 자식이 많은 오브젝트 transtorm 변경 시 많은 비용 발생
  • update, lateUpdate 등 unity : Monobehaviour 에 있는 비어있는 내부 함수 제거하기
  • 비용이 큰 수학 연산 줄이기 (sin, pow, 나눗셈, 제곱근, 루트 등의 연산이 곱셈보다 100배 가량 느리다고 한다.)

 

가비지 컬렉터(힙 메모리) 최적화

  • 캐싱 사용
    (우리 코드가 힙 할당으로 이어지는 함수를 반복적으로 호출하고 결과를 폐기하면 불필요한 쓰레기가 생성된다.
    대신, 우리는 이러한 객체에 대한 참조를 저장하고 재사용하는 기술을 캐싱이라고 한다.)
  • 자주 호출되는 함수에는 힙메모리 할당을 하지 않는다.
  • 오브젝트 풀링 사용
  • 문자열 관련
    1) 필요한 문자열 생성을 줄여야한다. 동일한 문자열 값을 두 번 이상 사용하는 경우 문자열을 한 번 만들고 값을 캐시해야합니다.
    2) 우리는 불필요한 문자열 조작을 줄여야합니다. 
    3) 런타임에 문자열을 작성해야 한다면 StringBuilder 클래스를 사용해야 합니다 .
    4) 디버깅을 위해 더 이상 필요하지 않게 되면 Debug.Log ()에 대한 호출을 제거해야 합니다.
  • 함수 관련
    1) GameObject.tag 대신 GameObject.CompareTag 사용하기
    2) Input.GetTouch 와 Input.touchCount 대신 Input.touches 사용하기
    3) Physics.SphereCastNonAlloc 대신 Physics.SphereCastAll 사용하기
  • 박싱으로 이어지는 함수 호출 제거
  • 코루틴 함수 관련
    1) StartCoroutine 을 사용할때 약간의 가비지가 발생한다.
    2) yield new return 에서 new 를 할때마다 가비지가 생성 된다.
  • 수동으로 가비지컬렉터 실행 자제

 

그래픽 최적화

  • CPU 의 작업량을 줄이는 방법
    1) 가까이에 있는 오브젝트를 수동이나 Unity 의 드로우 콜 배칭을 활용해 결합합니다.
    2) 큰 텍스처 아틀라스에 개별적 텍스처를 넣는 등의 방법으로 오브젝트의 머티리얼 수를 줄입니다.
    3) 오브젝트가 여러 번 렌더링되는 요소(반사, 그림자, 픽셀 별 광원 등)를 덜 사용합니다.
  • GPU 모델 지오메트리 최적화
    1) 필요 이상으로 삼각형을 사용하지 않습니다.
    2) UV 매핑의 경계 부분과 하드 에지(버텍스가 두 배)의 수를 가능한 적게 유지합니다.
  • 조명(Lighting) 퍼포먼스
    1) 전역 조명을 베이크하고 라이트 매퍼를 사용
  • GPU: 텍스처(Texture) 압축과 밉맵
    1) 3D 씬에서 사용되는 텍스처에 항상 밉맵 생성을 활성화 (2D 에서는 잘 활용하지 않는다.)
  • 실시간 섀도우
    1) 실시간 섀도우는 많은 비용이 발생한다.

UI 최적화

  • 캔버스를 구성하는 지오메트리(UI메쉬)가 리배치가 필요하다고 표시되면 해당 캔버스는 dirty 상태로 간주된다.
    1) 캔버스에 의해서 화면에 그려지는 지오메트리는 모두 큐(Queue)에서 그려진다.
    2) 폴리곤으로부터 레스터화 된 각 픽셀은 다른 폴리곤에 의해서 완전히 가려져 있더라도 샘플링 된다.
  • Layout 보다 RectTransform 시스템이 상대적으로 좋지만 UI를 구조화 하고 싶으면 Layout 사용하는 것이 좋다.
  • Fill-rate 문제를 해결하는 2가지 방법 (GPU의 프래그먼트 파이프라인에 가해지는 부하를 줄이는 2가지 방법)
    1) 프래그먼트 쉐이드의 복잡도 줄이기
    2) 샘플링해야하는 픽셀의 수 줄이기
  • 게임 오브젝트를 활성화 비활성화 하는 것보다 Canvas Renderer 컴포넌트를 활성화 비활성화 하는게 비용이 더 적다.
    = 이렇게 하면 스크립트는 살아있기 때문에 Update 같은 콜백메소드를 호출하는데 콜백관라자를 만들어서 스크립트들을 관리해야한다.
  • World Space 또는 Screen Space로 설정된 캔버스를 함께 사용하는 경우
    모든 World Space 및 Camera Space 캔버스 마다 Camera 속성을 할당해야 성능이 향상된다.
    = 할당하지 않으면 카메라를 찾는데 그 연산때문에 성능이 저하 된다.
  • 화면 전체를 가리는 UI가 열리는 경우 UI에 의해서 가려지는 월드 공간의 카메라를 모두 비활성시키는 것이 좋다.
    = 캔버스가 Screen Space = Overlay 로 설정된 경우에는 활성화 된 카메라의 수에 관계없이, 캔버스가 그려진다.
  • 화면 일부분을 가리는 UI가 열리는 경우 월드 공간에서 렌더 텍스쳐에 실제로 보이는 부분만 캡쳐하는 것이 더 효율적이다.
    = 캐싱 되었을 떄 실제 월드 공간 카메라를 비활성화 시키는 방법
  • 일반적으로 캔버스를 하위 혹은 동등한 캔버스로 분할하는 것이 좋다.
    1) 동등한 캔버스
    = 나머지 UI요소들과는 별도로 드로우 깊로 제어되는 경우 (가장위 혹은 가장 아래)
    2) 하위 캔버스
    = 편리하지만 서로 분리되어 있는 다른 캔버스와들은 배치 처리하지 않는다. 재량껏 사용
  • 포인터 이벤트가 처리되어야하는 UI컴포넌트에서만 'Raycast Target' 설정을 활성화 하는 것이 좋다. (이미지 같은거 빼기)
    = Taycast Target 목록이 작을수록, 확인해야하는 계층이 얕을 수록 Raycast를 테스트하는 속도가 빠르다.
  • UI Text는 폰트마다 아틀라스를 제작하는데(새로운 글자시 추가) 계속 변화해야하는 텍스트라면 미리 만들어 놓고 사용하는게 좋다.
  • UI Text를 사용하여 점수를 표시하고 싶을떄는 스프라이트를 위한 커스텀 컴포넌트를 작성하는 것이 좋다.
  • 많은 수의 폰트를 사용하려는 경우 폰트마다 메모리을 잡고 있다. 특히 일본한자 or 중국어 같이 그림 문자폰트는 더 심하다.
  • 일반적으로 UI Text 컴포넌트의 Best Fit 설정은 사용하지 않는 것이 좋다.
    = 아틀라스 제작문제는 버전이 올라가면서 해결됐지만 속도면에서 상당히 느리다.
    = 폰트 아틀라스가 너무 빈번하게 리빌드 되면 런타임 성능을 급격하게 저하시키고 메모리 파편화를 유벌할 수 있다.
  • 스크롤 뷰는 런타임 성능문제를 일으키는 원인 중 하나이다. 스크롤 뷰를 채우는 다음의 2가지 방식때문이다.
    1) 스크롤 뷰의 콘텐츠를 표시하기위해 필요한 모든 UI요소를 스크롤 뷰의 채웁니다.
    = 콘텐츠 수가 적으면 사용하기 좋지만 콘텐츠의 수가 증가하면 증가할수록 리빌드 하는데 드는 시간이 늘어난다.
    2) UI요소를 화면에 표시하기 위해서 필요에 따라 위치를 변경합니다.
    = 해결하기 위한 몇가지 방법이 있지만 위치기반 스크롤 뷰 풀링이 가장 좋다.
    3) LayoutGroup을 사용하여 스크롤 뷰의 포함되는 UI의 RectTransform 을 이동시키는 풀링시스템사용하는 방법이다.
  • UI에서 PVRTC (고정 비율 텍스처 압축 형식) 를 사용한다면 무조건 2의 제곱승으로 제작해야한다.
  • PNG 포멧을 사용하는 것이 APK등 빌드배포 패키지 용량에 있어서 조금더 유리하다.
  • Atlas - 모든 UI를 합쳐서 한장의 Atlas로 묶을 수 있으면 한장으로 묶고 메모리에 상주시키는 방법이 좋다.
  • 디자인 - UI의 디자인이 너무 다채롭고 어렵다면, 완성된 UI이미지를 씬 별로 나누어서 제작하는 편이 좋을 때도 있다.
  • Batch - 여러 Atlas를 사용하는 디자인은 60 Batch이하라면 사용할만하다.
    = 드로우콜이 60을 넘어가면 저사양 모바일에서 프레임드랍과 발열 문제가 발생한다.
  • Draw Call과 Canvas
    1) 한번에 그리는 경우 하나의 캔버스 안에 넣어주면 드로우 콜을 줄일 수 있습니다.
    2) 폰트의 종류를 줄이면 드로우 콜이 줄어듭니다.
    3) 화면에 가려져 있거나 안보이는 부분은 아예 그리지 않도록 제작합니다.
    4) Canvas를 여러개 써야한다면 각각 역할에 나누어 캔버스를 할당하고 Atlas를 따로 관리하는 것도 좋은 방법입니다. (중요 - 스프라이트 패커)
  • UI캔버스에서 한두가지 요소가 변경되면 캔버스 전체를 다시 드로우콜을 하는데 캔버스를 분할 혹은 중첩 하는게 좋습니다. (중요)
  • 정적요소나 비인터랙티브 요소에 대한 레이케스트 타겟을 비활성화 합니다. (클릭이벤트가 필요없는 UI)
  • 연산을 많이 하는 Camera.Main 을 사용하지 않는다.
  • 가능한한 레이아웃그룹 사용하지 않고 앵커 변경을 사용한다.
  • UI 오브잭트를 풀링할 때 활성화상태 -> 부모수준 변경 -> 비활성화 말고, 비활성화 -> 부모수준 변경을 사용한다.
  • 캔버스 컴포넌트를 비활성화한다. 추가로 스크립트들을 같이 비활성화 해주어야 한다. (오브젝트 x)
  • 애니메이션 값이 변경되지 않더라도 모든 프레임요소를 변경하기 때문에 UI에서 애니메이터 사용을 자제한다.
    = 변화 비용이 낮거나 이벤트의 반응으로 단기간동안만 바뀌는 경우 Tween 시스템을 구축하는 것이 좋다.
  • Sprites - 투명 영역을 최소화 한다. 텍스쳐와 마찬가지로 Generate mip maps는 필수.
  • Material이 비어있는 이미지나 텍스트가 성능저하를 가져온다고 한다.
    = 새 Material을 만들고, 만들어진 매터리얼의 shader 설정을 UI/Default로 한다. 그리고 이 걸 모든 텍스트와 이미지에 추가하면 된다.

게임 성능 최적화

  • 프로파일링을 사용 (과부화가 어디서 걸리는지 확인)
  • 움직이지 않는 오브젝트에는 Static 체크 해야 정적 배칭과 같은 내부 최적화가 가능해진다.
  • 동적 조명 보다는 조명은 베이크해서 사용!!!
  • 프래그먼트 별 텍스처 사용을 줄여야한다.
728x90

'유니티' 카테고리의 다른 글