2014년 5월 15일 목요일

unity3d script : 스크립트 최적화


감소된 고정 델타 타임

15-25fps(0.04 ~ 0.067)의 고정 델타 타임을 사용하세요. 사용자는 Edit->Project Settings->Time에서 이것을 바꿀수 있습니다. 이것은 FixedUpdate가 불리고 물리 엔진이 충돌감지(collision detection)와 rigidbody 엡데이트하는 빈도수를 줄여줍니다. 주요 캐릭터에 rigidbody를 사용한다면 Rigidbody컴포넌트에서 낮은 고정 델타 타임 스텝을 부드럽게하기 위해 interpolation을 활성화 할 수 있습니다.
Interpolate렌더링 프레임의 현재 시점에서 이전 물리 프레임과 다음 물리 프레임(예측)의 사이 값을 찾아서 선형보간을 수행합니다.  이를 위해 이전 물리 프레임의 값을 계속해서 어딘가에 저장해두어야 합니다. 엔진은 선형 보간된 위치와 회전 값으로 Transform정보를 강제로 설정합니다. Extrapolate 렌더링 프레임의 현재 시간과 이전 물리 프레임시간을 뺀 델타시간을 구한뒤에 현재 리지드바디가 가지고 있는 속력에 이를 곱하여 최종 위치를 예측합니다. ( 회전은 각속도를 사용합니다. ) 마찬가지로 엔진은 예측된 위치와 회전 값으로 Transform정보를 강제로 설정합니다. 

GetComponent콜수 줄이기

GetComponent나 BuiltIn 컴포넌트를 액세서를 사용하는 것은 주목할만한 오버헤드를 생기가 할 수 있습니다. 이것은 컴포넌트의 직접적인 참조를 캐슁하여 줄일수 있습니다.
예를 들어:
function Update () {
    transform.Translate(0, 1, 0);
}

> 위 코드는 실제 아래와 같이 처리됩니다.
GetComponent<Transform>().Translate(0, 1, 0);

대신 아래와 같이 최적화 할수 있습니다:
myTransform : Transform;
function Awake () {
   myTransform = transform;
}
function Update () {
    myTransform.Translate(0, 1, 0);
}

 

메모리 할당을 피하세요

  • 스크립트에서 할당을 최소화하세요.
  • Structs를 사용하세요. Structs는 메모리를 할당하지 않습니다. 대신 스택에 놓이게되며 값으로 전달을하며 이것이 더 빠릅니다.

struct로 생성가능한 걸 class를 생성하면 힙에 할당될 시점에서의 메모리 할당, 제거할떄의 GC처리는 성능 비용이 비싼편입니다.

   

GUI 를 줄이세요

  • GUILayout대신 GUI functions을 사용하고 화면에서 GUI의 양을 최소화 하세요
  • GUI 오버헤드를 줄이기 위해MonoBehaviour.useGUILayout = false를 사용하세요
function Awake () {
    useGUILayout = false;
}

GUI는 NGUI나 앞으로 유니티에 포함될 UGUI를 사용하는것이 좋겠음.

iOS 스크립트 콜 최적화를 사용하세요

UnityEngine 내임스페이스에 있는 대부분의 함수는 C/C++로 구현되어 있습니다. 그런 함수를 스크립트에서 부르는 것은 성능에 추가적인 오버헤드가 있습니다. 프레임당 추가의 몇 밀리세컨드를 얻기 위해서는 Edit->Project Settings->Player 에 있는 iOS스크립트 콜 최적화를 사용하세요:
  • Slow and Safe - 기본적인 단일의 내부 콜 핸들링 (익셉션 지원함) .
  • Fast and Exceptions Unsupported - 빠른 단일 내부 콜 구현, 그러나 익셉션이 지원되지 않으므로 조심히 사용하세요. 이것이 유용한 전형적인 경우:프로그램이 유니티엔진을 많이 사용하면서 익셉션이 생기지 않을때 입니다. 이 옵션은 1-4ms/frame을 줄일 수 있습니다.

Garbage Collection 최적화

  • 위에 서 말한 것처럼 어떤 할당도 피하도록 하세요
  • 만약 피할수 없다면 두가지 할당/수집 방법이 있습니다:
    • 작은 힙 빠르고 자주 일어나는 가비지 콜렉션 전략
      이 방법은 아주 긴 액션 게임플레이가 있고 부드러움 framerate가 필요한 게임에서 잘 작동합니다.
      짧은 시간동안 작은 블락을 할당하는 유니티 iOS게임에서 힙은 보통 ~5ms(iPhone 3G에서)걸립니다. 1MB힙에서는 가비지 컬력션은 ~7ms정도 더 걸립니다.
      가끔은 매 N번 프레임마다 강제 가비지 콜렉션을 하는것도 유용합니다:
      if (Time.frameCount % 30 == 0)
      {
         System.GC.Collect();
      }
      
      그러나 유의해서 사용하세요. 내부 프로파일러 통계를 보고 그것을 바탕으로 결정을 내리세요.
    • 큰 힙 느리고 빈도수가 낮은 가비지 콜렉션
      이 방법은 게임이 요구하는 부드러운 프레임 속도가 짧은 것과 중간 사이의 길이일 때 사용을 합니다. 아이디어는 게임이 실행될때는 가비지 컬렉션을 피하고 게임이 중단 되었을 때하는 것입니다. 게임 시작에 힙에 어느 정도의 공간을 미리 할당하는 것도 좋은 생각인데 그 공간은 게임 플레이 세션이 잘 돌아갈수 있을 만큼 크고 OS의 낮은 메모리 시스템으로 인해 프로그램이 멈추지 않을 만큼의 작은 공간을 말합니다. 모노는 필요할 때문 힙을 늘리기 때문에 가끔 시작시에 강제적으로 확장하는 것도 좋은 생각입니다:
      function Start() {
       var tmp = new System.Object[1024];
       // 할당은 작은 블락에해서 큰 블락은 위하 특별한 처리 방법을 피하도록 합니다
              for (var i : int = 0; i < 1024; i++)
        tmp[i] = new byte[1024];
       // 참조를 풀어 줍니다
              tmp = null;
      }
      
      나중에 게임 플레이가 중단 되었을때 강제적으로 가비지 콜렉션을 할 수 있습니다:
      System.GC.Collect();
      
      주의해서 사용하셔야 합니다. 내주 프로파일러 통계에 주목하시고 실제 숫자를 바탕으로 결정을 내리세요.

string '+' operator는 많은 가비지를 생성합니다. 가급적 StringBuilder()를 사용하는 것이 좋겠음.
StringBuilder sb = new StringBuilder();
sb.AppendFormat("[{0}] {1}", index, name.ToString());

.Net의 gerneric collections 을 사용하여 타입의 boxing, unboxing 부하를 없앱니다.

의심가는 코드 블럭에 Profiler.BeginSample, Profiler.EndSample를 사용하여 프로파일러 하이라키에서 확인하자.

using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour {
    void Example() {
        Profiler.BeginSample("MyPieceOfCode");
        Profiler.EndSample();
    }
}





댓글 없음:

댓글 쓰기