반응형
Notice
Recent Posts
Recent Comments
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

Do Something IT

유니티3D 게임 리소스 최적화? 3가지만 기억해라 본문

Unity3D/Optimization

유니티3D 게임 리소스 최적화? 3가지만 기억해라

아낙시만더 2014. 12. 11. 15:23
반응형

출처: 바로가기

unity5_140320_1

유니티3D(Unity3D)로 게임을 개발하다가 개발사가 완성 단계에서 가장 어려워하면서도 꼭 한번은 거쳐야 하는 과정이 바로 리소스 및 메모리 최적화모바일기기 특성상 리소스가 넉넉하지 않은 탓에 단 몇 메가라도 메모리를 아끼려는 노력이 필요할 수밖에 없다.

메모리와 리소스 최적화를 해야 하는 이유는 이렇다첫째용량이 50M를 넘게 되면 다운로드 받는 유저 수가 절반으로 줄어든다는 것통계적으로 50MB가 넘는 게임을 내려받는 유저 수가 절반 이상 꺾인다고 한다개발사와 퍼블리셔 모두 게임 클라이언트 용량을 가능하면 적게 낮추려고 하는 이유도 여기에 있다.

둘째 메모리를 많이 쓰면 게임 유저 수에 제약이 생긴다는 점메모리를 많이 쓰게 되면 저사양 스마트폰의 경우에는 게임상 이미지 자체를 불러올 수 없게 된다그 탓에 화면이 깨지거나 아예 작동을 멈추게 된다고객의 엄청난 항의와 불만을 몰고 오게 되는 원인 제공자가 되는 것.

마지막은 게임 콘텐츠 자체의 특성상 이미지와 사운드 리소스 양이 방대하다는 것이다.보통 앱이나 서비스보다 게임은 이미지 리소스를 상당량 보유하고 있다따라서 리소스가 최적화되지 않았을 때 발생하는 오버헤드는 일반 앱과는 비교가 안 된다그렇다면 이제 구체적으로 리소스 최적화 가이드라인을 알아본다.

◇ 이미지 가로세로 사이즈는 무조건 2의 제곱=게임에서 사용하는 이미지 가로세로 사이즈는 무조건 2의 제곱으로 되어야 한다(Power Of Two). 컴퓨터에서 이미지를 사용할 때에는 개념적으로 “[1디스크에서 이미지 불러오기→[2이미지 압축 포맷 압축 해제→[3] 1024×1024×32비트 메모리 블록에 해당 이미지 할당” 과정을 거친다.

1024×1024×32비트 RGBA 기준으로 이미지를 압축한 png 용량은 313KB에 불과하다.하지만 압축을 해제하면 메모리상 이미지 사이즈는 4MB나 된다. 2048×2048이라면16MB에 이른다.

이렇게 가로세로 사이즈가 2의 제곱으로 된 이미지가 아닌 경우에는 상당한 메모리 낭비가 일어나게 된다예를 들어 900×900 사이즈 이미지가 있다고 하자메모리상에서900×900 사이즈 이미지를 도르할 때 해당 이미지를 똑같이 1024×1024로 변환해 다시 메모리에 저장하게 된다다시 말해 거의 배에 가까운 이미지 메모리가 낭비되는 것이다.

이런 이유 때문에 유니티3D를 비롯한 여러 게임 개발 엔진에서 아틀라스(Atlas)라는 리소스 단위를 사용하게 된다이미지를 POT(2의 제곱방식으로 바꿔서 항상 활용하기를 권한다.

◇ 메모리 사용량 프로파일링 직접 해보면=이번에는 게임 리소스를 최적화할 때 직접 간단한 프로파일러를 돌려보겠다현재 씬(Scene)에 있는 모든 이미지 리소스를 모두 조사해 개별 객체가 얼마나 메모리를 차지하고 있는지 체크해 큰 순서대로 나열한다.

var sortedAll = FindObjectsOfTypeIncludingAssets(typeof(Texture2D)).OrderBy(go=>

Profiler.GetRuntimeMemorySize(go)).ToList();

이 명령으로 현재 모든 텍스처2D(Texture2D) 오브젝트를 구할 수 있다또 메모리 크기 순서대로 정렬한 상태로 리스트가 나오게 된다그렇다면 모든 텍스처2D 리스트를 출력해보도록 하겠다.

var sortedAll = FindObjectsOfTypeIncludingAssets(type).OrderBy(go=>

Profiler.GetRuntimeMemorySize(go)).ToList();

StringBuilder sb = new StringBuilder(“”);
int memTexture = 0;
for(int i = sortedAll.Count-1;i>=0;i–){
if(!sortedAll[i].name.StartsWith(“d_”)){
memTexture += Profiler.GetRuntimeMemorySize(sortedAll[i]);
sb.Append(type.ToString());
sb.Append(” Size#”);
sb.Append(sortedAll.Count – i);
sb.Append(” : “);
sb.Append(sortedAll[i].name);
sb.Append(” / Instance ID : “);
sb.Append(sortedAll[i].GetInstanceID());
sb.Append(” / Mem : “);
sb.Append(Profiler.GetRuntimeMemorySize(sortedAll[i]).ToString());
sb.Append(“B / Total : “);
sb.Append(memTexture/1024);
sb.Append(“KB “);
sb.Append(“\n”);

}
}
Debug.Log(“Texture2D Inspect: “+sb.ToString());

※ 여기에서 string의 연산 대신 StringBuilder를 사용한 이유는 연산 성능이 더 효율적이기 때문이다.

이렇게 간단한 C# 코드로 된 프로파일러를 돌려보면 현재 씬에서 어떤 텍스처2D가 괴물같이 많은 메모리를 먹고 있는지 눈으로 확인할 수 있다안드로이드(Android) 빌드라면 안드로이드 DDMS의 로그캣(LogCat)으로 로그를 확인할 수 있다여러 테스트 기기에서 해당 로그를 직접 확인해보고 싶다면 서버에 로그를 남기는 방식도 가능하다필자는 QA 테스트를 할 때 해당 로그를 서버에 직접 보내보면서 테스트를 해봤다성능 최적화에 상당한 도움이 된다.

◇ 텍스처 하나하나 최적화로 마무리=마지막은 가장 많은 메모리를 먹고 있는 텍스처부터 작은 것까지 하나하나 최적화를 해나간다먼저 쓸데없이 큰 공간을 차지하는 아틀라스의 경우는 몇 개를 묶어 하나로 만들어 남는 여백을 줄인다다음으로 필요 없는 이미지는 삭제한다.

눈에 크게 보이지 않는 이미지가 너무 고해상도인 경우 화질을 낮춰서 다시 임포트(Import)하는 것도 잊지 말아야 한다. png의 경우 포토샵 플러그인을 통해서 이미지를 압축해 다시 임포트한다.

오디오 파일은 모바일에서 스테레오 모드가 의미가 없으니 모두 92kb, 모노로 인코딩하도록 설정한다이 설정은 유니티 엔진에서 가능하다또 이미지가 여러 번 로딩되지 않게 Singleton 패턴을 활용한다.

물론 위와 같은 리소스와 메모리 최적화 방법은 단편적인 솔루션이다하지만 게임에서 가장 많은 용량과 메모리를 차지하는 이미지 리소스 최적화에선 아주 기본적인 단계이기도 하다

반응형

'Unity3D > Optimization' 카테고리의 다른 글

아낙's Unity팁 모음  (0) 2015.09.02
Memory profiling in Unity  (0) 2014.07.22
String.Format() and StringBuilder  (0) 2014.07.01
효과적인 C# 메모리 관리 기법  (0) 2014.05.07
[Unity] 유니티의 메모리 관리  (0) 2014.03.26
Comments