반응형

유니티에서 제공하는 안드로이드용 알파 채널 텍스쳐중 디바이스 호환성이 뛰어난 것은 3가지 밖에 없습니다.

RGBA32 BIT / RGBA 16BIT / ETC2 8BIT

 

ETC 2 8Bit는 아직 디바이스 점유율이 안좋아 사용이 불가한 상황입니다.. 현재 시장에 배포된 디바이스중 50프로는 사용 불가..

(점유율 현황 - https://developer.android.com/about/dashboards/index.html --- Open GL Version 이 2.0인 것들은 지원하지 않습니다.)

 

 

결론적으로 RGBA 16 Bit 와 RGBA 32 Bit 두 종류밖에 쓸 수 없다는 건데..

RGBA 32 Bit 는 무압축 포맷이라 메모리 이슈가 빵빵터져 앱이 계속 죽어 나갈 것이고..(특히 아이폰.. 6도 1기가라는..)

RGBA 16 Bit 는 쓰레기 품질에 압축률도 엉망이라 아트를 볼 줄 아는 사람이 한명이라도 있는 프로젝트에서는 거품 물고 반대할 것이 뻔합니다.

 

1024의 알파 채널이 있는 텍스쳐를 사용하게 될 경우

RGBA 32 Bit의 용량은 4MB

RGBA 16 Bit의 용량은 2MB

 

사이즈가 작은 캐주얼 게임이라면 별 상관없을거 같긴한데.. 대규모  RPG같은 알파 텍스쳐 사용량이 100개 이상 넘어가는 프로젝트라면

너무 큰 클라이언트 용량으로 출시가 힘든 상황이 올수도 있습니다. 특히 중국쪽은 더더욱..

 

 

이런 문제들을 해결하기 위해서 Etc1 4Bit 2장을 이용하면 간단히 해결이 됩니다. 한장은 오파큐텍스쳐로 쓰고 한장은 알파텍스쳐로 쓰면 되지요..

 

1024 텍스쳐의 Etc1 4bit의 용량은 고작 512 KB~~ 2장을 써도 1024 KB~~  쓰레기 품질의 RGBA 16Bit 한장을 쓸때보다도 1/2 용량이라는 어마어마한 이득을 취하면서도 괜찮은 품질을 얻을 수 있습니다.

 

이 방법을 쓰기 위해서는 셰이더를 새로 짜고 텍스쳐 분리 작업을 하고 여러가지 해야할 일거리가 여기저기 터지지만 메모리 이슈로 게임을 출시 못하는 거보다는 낫지 않을까?

 

이방법을 쓸 때 유의 사항.

1. 1드로우였던게 2드로우가 되므로 드로우콜에 유의하자.

2. 알파 채널이 필요한 경우도 반드시 생기므로 알파 채널에 대한 연산 부분도 포함하자.

 

 

아래는 etc1 2장으로 처리할 수 있는 간단한 알파 블렌드 셰이더 코드 입니다.

 

 

Properties    {
        _TintColor ("Tint Color"Color) = (0.5,0.5,0.5,0.5)
        _MainTex ("MainTex"2D) = "white" {}
        _Alpha ("Alpha"2D) = "white" {}
    }

    SubShader {

        Tags {"IgnoreProjector"="True" "Queue"="Transparent" "RenderType"="Transparent"}
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            Blend SrcAlpha OneMinusSrcAlpha
            Cull Off
            ZWrite Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

        uniform sampler2D _MainTex; 
        uniform fixed4 _MainTex_ST;

        uniform sampler2D _Alpha; 
        uniform fixed4 _Alpha_ST;

        uniform fixed4 _TintColor;

        struct v2f 
        {
            fixed4 pos : SV_POSITION;
            fixed2 uv : TEXCOORD0;
            fixed2 uv1 : TEXCOORD1;
            fixed4 color : COLOR;
        };


        v2f vert (appdata_full v) 
        {
            v2f o;

            o.color = v.color;
            o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

            o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
            o.uv1 = TRANSFORM_TEX(v.texcoord, _Alpha);

            return o;
        }

        fixed4 frag(v2f i) : COLOR {
                 fixed4 _MainTex_var =  tex2D(_MainTex,i.uv);
                fixed4 _Alpha_var = tex2D(_Alpha,i.uv1);

                  fixed3 emissive = _MainTex_var.rgb * i.color.rgb;
                  fixed node_9936 = _Alpha_var.r;     

                fixed3 finalColor = emissive * (_TintColor * 2);

                return fixed4(finalColor, (i.color.a * _MainTex_var.a * node_9936));
            }
            ENDCG
        }
    }//SubShader

반응형
반응형

 

 사장님께서 각 팀 팀장들에게 모바일 게임 최적화에 대한 교육 요청을 해주셔서 진행한 PPT입니다.

일시 : 2015년 12월 7일 대회의실

 

 

참고 자료

[데브루키/141206 박민근] 유니티 최적화 테크닉 총정리

http://www.slideshare.net/agebreak/unite2015-47100325?related=1

 

유니티 그래픽 최적화, 어디까지 해봤니

http://www.slideshare.net/ozlael/graphics-opt-ndc?related=2

반응형
반응형

참고 자료

[데브루키/141206 박민근] 유니티 최적화 테크닉 총정리

http://www.slideshare.net/agebreak/unite2015-47100325?related=1

 

유니티 그래픽 최적화, 어디까지 해봤니

http://www.slideshare.net/ozlael/graphics-opt-ndc?related=2

 

최적화 내용 간단 정리

** 가장 중요한 것은 병목 지점 파악~(메모리인지, 콜인지, CPU인지, 버텍스연산인지.. 아니면 다함께..)

** 리소스 아껴 쓰기

** 드로우콜 관리하기

** 모바일 사운드는 모노로 사용하기~

** 가비지 컬렉터 관리~~

** 스크립트 함수에 무거운 함수 쓰지 않기~

** 셰이더에 무거운 함수 사용 줄이기~

** 물리 사용은 최소로~

 

1. 프로그램 최적화

* 스크립트 최적화

--- 유니티 객체들을 변수에 저장하고, 캐싱해서 사용하는 것이 좋다.

--- FindObject 계열 함수들은 매우 느리다. (미리 찾아서 캐싱)

--- Update 함수 보다는  Coroutine을 활용한다.

--- 박싱과 언박싱은 부하가 큰 작업이다.

--- 나눗셈보다 곱셈이 몇십배 빠르다.

--- 삼각함수의 값은 상수로 저장하고, 사용하는 것이 좋다.

--- 문자열은 readonly 혹은 const 키워드를 사용하여, 가비지 컬렉션으로부터 벗어나도록 한다.

* 문제의 원인 : 가비지 컬렉터

--- Mono의 동적 메모리 관리 때문에, 메모리 해제를 위해 GC가 자동 호출 된다.

--- GC는 언제 일어날지 모른다.

--- 오브젝트(or 프리팹)의 동적생성과 해제는 부하가 크다.

--- 오브젝트 풀링 사용은 선택이 아닌 필수!

--- 문자열 병합은 StringBuilder

--- foreach 대신에 for문 사용 (foreach는 한번 돌때마다 24Byte의 쓰레기 메모리를 생성)

--- 태그 비교에는 compareTag() 사용

--- 데이터 타입에는 Class 대신 구조체 사용

--- 즉시 해체할 때는 Dispose 수동 호출

--- 임시 객체들을 만들어내는 API들을 조심하라.

* C++ <-> C# 오버헤드

--- 객체의 변경 사항을 캐싱

--- 컴포넌트 참조를 캐싱

--- 빈 콜백 함수는 제거

 

 

2. 그래픽 최적화

* 텍스쳐 최적화

--- 권장 압축 사용하기 : 아이폰 -> PVRTC   ,  안드로이드(Tegra) -> DXT , 안드로이드(Adreno) -> ATC , 안드로이드(공통) -> ETC1 / ETC2

--- 텍스쳐 사이즈는 무조건 2의 제곱이어야 한다. POT(Power of Two) 아닐 경우 무조건 POT로 강제 변환함

--- 텍스쳐는 묶어서 사용하는게 이득이다. 한 화면에 나오는 것끼리~ 같은 재질의 오브젝트끼리~ 알파가 있는것과 없는것끼리

--- 32bit 텍스쳐보다는 16bit를 큰 텍스쳐로 쓰는게 이득이다.

--- 모바일뷰에서 가장 최적화된 해상도를 찾는데 주력한다. 이거저거 다해봐도 개개의 소스를 절약하는 방식이 최고임.

* 메쉬 최적화

--- Import시에 언제나 "Optimize Mesh" 사용 - 버텍스 캐쉬를 최적화 해준다.

--- 언제나 Optimize Mesh Data 옵션을 사용한다. 사용하지 않는 버텍스 정보들을 줄여준다.

--- 사용하지 않는 버텍스 정보들을 줄여 준다.

* 드로우 콜

--- 적절한 DP 는 100이하를 추천, 보통 70~100 정도가 일반적

* CULLING

---- 각 Layer 별로 컬링 거리를 설정해 준다. 중요도가 낮은 오브젝트의 컬링커리를 짧게 설정한다.

---- 오클루젼 컬링을 활용하여 카메라 밖은 잘라내도록 한다.

* 오브젝트 통합

---- 성질이 동일한 오브젝트들은 하나의 메쉬와 재질을 사용하도록 통합

*Batch

---- 스태틱 배치와 다이내믹 배치의 적절한 조합

* 라이팅

---- 라이트맵과 라이트렌더 모드 활용

* OverDraw

--- 한 픽셀에 두 번 이상 그리게 되는 경우 OVERDRAW 문제가 발생한다.

--- 기본적으로 앞에서 뒤로 그린다. Depth testing으로 인해서 오버드로우를 방지한다. 알파 블렌딩이 있을경우 소팅 문제 발생

--- 반투명 오브젝트의 개수의 제한을 건다. 뒤에서 앞으로 그려야 함. 반투명 오브젝트 갯수가 늘어날수록 퍼포먼스 직결~!

 

 

3. 사운드 최적화

--- 모바일에서 스테레오 사용은 퍼포먼스에 큰 영향을 끼친다. -> 되도록이면 모두 92 kb, 모노로 인코딩

--- 사운드 파일을 임포트하면 디폴트로 3D 사운드로 설정 -> 2D 사운드로 변경

--- 압축 사운드(mp3. ogg) , 비압축 사운드(wav) 구별.    압축 사운드-> 순간적인 효과음, 이펙트등..      비압축사운드 -> 배경 음악 

 

 

4. 폰트 리소스 최적화

--- Packed Font - R,G,B,A channel에 각각 글자의 형태를 저장하는 방법. 메모리 용량을 1/4로 절약

--- 리소스 기타 - ResourceLoadAsync() 함수는 엄청 느리다.

 

5. 셰이더 최적화

--- 기본 셰이더를 사용할 경우, 모바일용 셰이더 사용 Movile -> VertexLit 가장 빠른 셰이더

--- pow, exp, log, cos, sin, tan 같은 수학 함수들은 고비용이다.

--- 텍스쳐 룩 업 테이블을 만들어서 사용하는 것도 좋다.

--- 알파 테스트 연산(discard)은 느리다. 무조건 최소로..

--- 라이트맵 활용은 필수.

* 실수 연산

--- float : 32bit -> 버텍스 변환에 사용, 아주 느린 성능 (픽셀 셰이더에서 사용은 피함)

--- Half : 16bit -> 텍스쳐 uv에 적합, 대략 2배 빠름

--- fixed : 10bit -> 컬러, 라이트 계산과 같은 고성능 연산에 적합, 대략 4배 빠름]

 

6. 물리 엔진 최적화

--- FixedUpdate()는 Updata와 별도로 주기적으로 불리며, 주로 물리 엔진 처리

--- Default는 0.02초, 게임에 따라 0.2초 정도로 수정해도 문제 없음

--- 물리 엔진이 적용되지 않는 오브젝트는 Static으로 설정

--- 리지드 바디가 없는 고정 충돌체를 움직이면, CPU 부하 발생 - 물리 월드 재구성 - 이럴경우 isKinematic 옵션 사용

--- Maximum Allowed timestep 조정하여 물리 계산을 건너뛸 수 있는 부분은 무조건 건너 뛴다.

--- EDIT -> Project Setting -> Physics 에서 Solver Iteration Count 조정. 높을수록 정교하므로 낮게 설정한다.

--- Sleep 조절 -> 리지드 바디의 속력이 설정된 값보다 작을 경우, 휴면상태에 들어감.

--- Physics.Sleep() 함수를 이용하면, 강제 휴면 상태로 만듬.

--- 래그돌 사용 최소화

--- 태그 대신 레이어 활용 - 물리처리에서 레이어가 훨씬 유리, 성능과 메모리에서 장점을 가진다.

--- 메쉬 콜리더는 절대 사용 금지.

--- 레이캐스와 Sphere Check 같은 충돌 감지 요소를 최소화

--- Tilemap Collision Mesh -- 2D 게임에서 타일맵의 Collison Mesh를 최적화 하라.

 

반응형

+ Recent posts