티스토리 뷰

728x90

youtu.be/tT9LS53HRx4

ScriptCode 작성팁

ObjectPooling

  • 다수 동일한 객체를 자주 생성/삭제가 발생하면 GC의 동작이 많아지게되고 이는 곧 전체 CPU사용량에 부정적인 영향을 주게된다.
  • Object Pool을 통해 게임내에서 사용할 객체를 미리 충분한 개수만큼 생성하였다 필요한 순간 꺼내서 사용하고 끝나면 Pool에 반납하는 시스템.
  • Pool의 크기결정이 중요하며, Pool의 크기를 넘는 개수를 사용해야되는 상황에 대한 보조적인 조치가 필요하다.

Sciprtable Object

  • 게임에서 변하지 않는 데이터를 위한 클래스를 작성하는 경우 Monobehaviour보다 Scriptable Object를 상송하여 객체를 작성하는것을 추천함.
  • Mono에 비해 메모리 사용량도 적고 불필요한 프로세스콜(Start(), Update()..)을 줄인다.
  • Mono와 같이 Inspector사용가능하고 별도의 asset으로 저장하여 관리가 가능하다.
  • static객체처럼 사용가능하다. 레퍼런스만 들고있으면.

Variables/Properties

#if DEV_BUILD
private int _health;
public int Health => _health;
#else
public int health;
#endif

 

 

프로퍼티도 함수콜을 사용하기에 스택프레임에서 오버헤드가 발생한다. start때와 같이 1회면 상관없지만 update문에서 사용하게되면 불필요한 오버헤드가 생긴다.

 

Resources폴더

  • Resources폴더에 있는 모든 리소스가 사용여부와 상관없이 패키징됨. (최종빌드의 용량낭비)
  • Resources폴더에 있는 리소스의 개수는 앱의 구동시간에 영행을 준다.
    앱구동시에 리소스폴더내의 모든 리소스를 탑색하여 Lookup테이블을 작성하는데 이로인해 개수가 많아지면 기동이느려지고 lookup테이블의 용량도 증가한다.
  • 가능하면 Addressable Assets패키지를 활용하여 Assetbundle을 활용하는것을 추천

빈 Unity 이벤트 함수 삭제

  • void Start() {} void Update() {}.. 같은것.
  • 비어있어도 선언만 되있어도 내부의 각 이벤트 컨테이너에 추가되어 매번호출되기에 오버헤드 발생.

Awake() / Start() 함수는 최대한 가볍게

  • 무거운 Awake() / Start()는 개체의 초기화를 지연시키게 되고, 결국 Scene 초기동작을 지연시킴
  • Unity의 처음 렌더링 결과물이 스크린에 표시되는 시점이 Scene의 모든 Object의 Start()호출이 완료된 이후이기에 초기화의 지연은 결국 Scene을 처음띄우는 시간의 지연으로 이어짐.
  • 무거운 초기화로직은 가능하면 update내의 별도의 FSM등을 통해 초기화구간을 구성해서 진행하는것을 권장

Hierarchy복잡성을 줄이기

  • Hierarchy의 계층구조에서 Root GameObject는 모든 하위오브젝트의 Transform데이터를 배열로 들고있음.
    • 작은 Transform변화에도 하위의 모든계층에 대한 Transform계산을 다시하기에 가급적 Transform변화가 있는 오브젝트를 변도의 트리로 관리해야함.
    • Hierarchy 구조가 변경되면 내부적으로 Root 오브젝트의 transform배열의 메모리 재할당이 일어나며 모든 배열값을 다시 설정한다. 이로인한 GC가 발생하기에 가급적 hierarchy구조는 변경하지 않는것이 좋다.
  • 계층적인 구조가 필요한 경우가 아니라면 Root에 GameObject를 배치하는 것이 성능면에서 가장 좋다.

참조 변수 캐싱

  • GameObject.Find(), GameObject.GetComponent()..와 같은함수
    • 생성되어 있는 모든 GameObject를 순회하며 조건검사를 진행하기에 오버헤드가 크다. 가능하면 직접 참조하거나 초기화시점에 검색하여 검색결과를 캐싱하여 사용
  • 검사대상도 많고 비교검사자체가 문자열조건비교이기에 비교식에 대한 오버헤드가 높은편, 그렇기에 자주사용하는것은 전체성능에 부정적인 영향을 줌.

 

Asset Import

Texture Import Settings

  • Generate Mipmaps
    • 밉맵이 필요하지 않는 텍스쳐의 경우 이 옵션을 해제하면 리소스용량을 약 24% 줄일수 있다.
  • Format
    • 디바이스 하드웨어에서 지원하는 압축포맷을 선택
    • OpenGLES3 이상일 경우 ETC2/ASTC 포맷이 표준규격으로 지정되어 있음.
    • ETC2는 ES3.0, ASTC는 ES3.1
  • Compression
    • 옵션에 따라 용량과 퀄리티차이가 발생하고 동일설정이라도 플랫폼별로 확인 필요.
  • POT 지정 또는 Altas 사용
    • iOS의 PVRTC 포멧의 경우 강제로 POT상태로 텍스쳐가 변경되면서 의도치 않은 낭비가 발생할 수 있음. 명시적으로 POT값을 지정하여 잘못된 변경이 발생하지 않도록 한다.
    • 일부 플랫폼의 경우 POT옵션이 지정되어 있지 않은 상태에서 mipmap을 설정하면 압축포멧이 유지가 되지 않는 경우가 있다. 이는 에디터에서 경고로 표시하고 있음.
  • 불필요한 알파채널 삭제
    • 압축포맷을 사용할때 알파채널/유무는 용량보다 이미지 퀄리티에 영향을 줌.
  • Read/Write Enable 해체
    • Read/Write Enable을 선택하면 비디오 메모리에서 읽기버퍼외 쓰기버퍼를 추가로 할당하기에 메모리사용량이 2배가 됨.

Mesh Import Settings

  • Mesh Compression
    • Mesh의 Shape에 영향을 줄수 있기에 output을 확인하여 원본과 비교해서 적용
    • 패키지용량은 줄지면 runtime메모리에는 영향이 없다.
  • Read/Write Enable옵션은 텍스쳐의 그것과 동일
  • Blendshapes, Normals and Tangents
    • 불필요한 경우 해제하면 사용하지 않는 데이터가 제거되어 mesh데이터의 크기를 줄임.
  • Rig
    • 애니메이션을 사용하지 않는경우 animation type을 none으로 설정

Audio Import Settings

  • 가능하면 Force to Mono를 사용
  • 가능한 Compression bitrate를 낮추가
    • 퀄리티 손상을 체크하면서 가능한 bitrate를 낮추면 그만큼 오디오 파일의 크기가 작아져 패키지 용량과 메모리 용량을 아낄 수 있다.
  • 추천포멧
    • iOS : ADPCM (단순효과음), MP3(BGM)
    • Android : Vorbis (ogg)
    • 리소스 임포트는 wav로 무손실로 하고 관리해야.
      • 패키징단계에서 압축하기에 mp3로 넣으면 두번압축이라 손실발생
  • Audio Clip크기 별 LoadType 추천
    • 200kb 미만 : Decompress On Load
    • 200kb 이상 : Compressed In Memory
    • 1mb이상의 큰파일 : Streaming
    • 압축해제를 위한 버퍼가 200kb 할당되기에 200kb미만은 그냥 압축을 풀어서 load하는편이 사용량을 절약함.
  • Mute (볼륨0) 상태에서는 오디오재생을 중지시키기.
    • 볼륨이 0 이여도 내부적으로 오디오 재생프로세스가 돌고있으므로 cpu와 메모리할당을 절약
    • mute옵션이 되면 기존 load되어 있는 audio clip도 unload하는것이 좋다.

그래픽스

Batching

  • Dynamic Batching은 900개 이하의 Vertex를 가진 오브젝트를 대상으로 positon, normal, uv0, uv1, tangent등을 계산하며, 한프레임당 한번씩 평가된다. batching 결과를 프로파일링하여 batching 성공률이 낮다면 배칭평가에 대한 cpu 비용을 줄이기위해 옵션을 비활성화하는 것도 좋다.
  • Static Batching은 static flag가 활성화된 정적오브젝트를 대상으로 build타임에 batching 평가가 수행됨. 만약 runtime에 동적으로 mesh를 추가하려면 StaticBatchingUnility.Combine Api를 참고하여 직접구현해야함.

Shadow Casting 비활성화

  • 오브젝트가 중첩되어 있어 실제로 그림자를 그릴필요가 없는 오브젝트는 명시적으로 off해야함.
  • Shadow Rendering은 unity에서 제공하는 Framedebugger를 통해 그림자 계산결과를 각 오브젝트마다 확인가능

Light용 Culling Mask

  • Light의 계산비용은 상당히 높은편. 특히 Spot Light의 경우 일반 Direction Light에 비해 계산양이 높음 가능하면 Light효과를 받는 대상을 별도의 Layer로 구성하여 Culling Mask를 통해 계산비용을 최소한으로 지정하는것을 권장함. 해당 Layer만 계산하기에 불필요한 Layer에 대한 계산을 줄이기위해

모바일기기 해상도보다 낮은 해상도사용

  • 최근 해상도가 매우 높기에 가능하면 게임해당도를 지정하여 GPU사용량과 GPU메모리도 절약가능
  • Screen.SetResolution(width, height, false);를 통해 조절.

UI

보이지 않는 UI는 Hide시키기

  • 카메라 밖으로 벗어나거나 다른 UI에 가려져 실제로 보이지 않는 UI도 실제로는 매프레임마다 렌더링 되고 있다. 명시적으로 Active를 끄거나 Hide옵션을 설정하면 불필요한 렌더링 비용을 줄일 수 있다.
  • 일반적인 object는 컬링을 하지만 ui는 아님.

UI Batching

  • Sub-Canvas의 UI를 분리하기
    • 정적인 UI와 동적인 UI를 분리시키면 UI가 변경되면서 발생하는 UI Mesh 재생성을 최소화 할 수 있음.
  • 하나의 Canvas에 있는 UI의 z값을 동일하게 설정하기
    • 같은 Canvas라도 z값이 다르면 Batching이 꺼진다.
  • 같은 텍스쳐와 마테리얼의 사용
    • atlas를 적극적으로 활용하여 같은 텍스쳐와 마테리얼을 사용하여 draw call을 줄이도록
  • 동일한 clipping rect를 사용하기
    • clipping rect 활성상태나 값이 다르면 batching이 이뤄지지않고 drawcall이 분리됨.
  • Graphic Raycaster
    • 마우스나 터치등의 입력이벤트처리가 필요한 Canvas만 Graphic Raycaster를 활성화하자.
    • 입력 이벤트가 발생하면 Graphic Raycaster가 활성화된 canvas 밑에 raycast가 선택된 모든 ui요소를 대상으로 입력처리를 시도함. 해당 옵션을 비활성화하면 canvas 단위로 입력처리대상의 숫자를 줄일수 있다.

풀스크린UI

  • Pause나 메인Menu를 띄울때 전체화면 UI사용을 권장.
  • 전체화면을 가려서 게임화면 Camera를 비활성화하여 렌더링 비용을 줄이자.
  • 가려지는 ui는 hide시켜야함
  • frame rate는 낮추기
  • 메인게임 camera를 끄고 frame rate를 낮추면 cpu와 gpu부하를 대폭줄일 수 있고, 메뉴를 열고 있는 시간만큼 cpu와 gpu가 쉬게되어 스로틀링을 예방하는데 도움이됨.

최적화의 경우 마일스톤별로 어디를 최적화할지 프로파일링을 하고 다음 마일스톤에 해당부분을 보완하는것이 합리적이다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31