들어가며

유니티에서 안드로이드 타겟으로 개발하면 텍스쳐 압축을 ETC로 사용하게 됩니다. 기존에는 텍스쳐의 기본 압축 포맷이 ETC1이였는데, 최근 5.2.0부터는 RGBA 텍스쳐의 압축 포맷이 ETC2.0으로 바뀌게 되었습니다. 텍스쳐 포맷을 compressed로 두면 내부적으로는 ETC2를 사용하도록 되는 것입니다. 그래서 그런지 ETC 포맷에 관한 문의가 빈번하게 들어오고 있습니다. 그래서, 잘 오해할 수 있는 부분을 정리해드리고자 합니다.


Open GL ES 버전 & ECT 포맷 버전

ETC2 압축 포맷은 ETC1가 확장 및 개선된 포맷입니다. 때문에, 가능하다면 ETC1보다는 ETC2를 사용하는 것이 당연히 좋습니다. (참고로, DXT1, DTX3, DXT5는 이야기가 다릅니다. 서로 품질과 크기의 조율 선택 사항입니다.) 다만 문제는 ETC2는 Open GL ES 3.0 이상에서만 지원됩니다. 갤럭시 S3 이하 등의 구형 기종에서는 Open GL ES 2.0으로 돌아가기 때문에 ETC2를 사용하는 것이 불가능합니다.


Open GL ES 2.0 기기에서의 ETC2 사용

하지만 막상 유니티에서 텍스쳐 포맷을 ETC2로 두고 Open GS ES 2.0 기기에서 구동을 해봐도 텍스쳐가 정상적으로 그려집니다. ETC2가 Open GL ES 2.0에서는 지원이 되지 않기때문에 텍스쳐가 그려지지 않아야 될 것으로 생각되서 혼란스러우실 수도 있겟습니다. 

이미지 출처 : http://chulin28ho.tistory.com/

사실, 기기에서 지원되지 않는 텍스쳐 압축을 사용하는 경우, 텍스처는 비압축 RGBA 32 형식으로 압축된 텍스처와 함께 메모리에 저장됩니다. 따라서 이러한 경우에는 텍스처 압축을 푸는 만큼 불필요한 계산 시간이 발생하게 되며 메모리 공간도 두 배로 필요해집니다. 이것 또한 렌더링 성능에 심각한 악영향을 미칩니다.

설명이 좀 애매하긴 한데 예를 들자면, OpenGL ES 2.0 기기에 ETC2 포맷을 사용하면 작동하는데에는 문제가 없지만 성능상 효율이 떨어지게 됩니다. 왜냐하면 ES 2.0 기기는 ETC2를 지원하지 않기 때문에 32비트x폭x높이 + 원래의 ETC2 사이즈 만큼의 메모리가 늘어나서 압축 지원도 못받으면서 메모리만 늘어나게 되기 때문입니다. 또한 로딩 타임에 텍스쳐를 소프트웨어적으로 압축을 푸는 시간도 추가됩니다.


ETC2의 ETC1 하위 호환성

ETC2는 ETC1의 하위 호환성을 보유하고 있습니다. 때문에 Open GL ES 2.0에서도 ETC2를 읽을 수 있는 것으로 알고 계시는 분도 간혹 계십니다. 충분히 오해할만 하지만, ETC2가 ETC1 하위 호환을 포함한다는 것은 기기에서 ETC1을 ETC2처럼 취급할 수 있다는 것일 뿐입니다. 앞서 말씀드린대로 유니티에서는 ETC2를 ES2.0 기기에서 올리면 23bit RGBA로 사용됩니다. 


알파 유무의 차이

안드로이드 텍스쳐 압축의 기본 값이 ETC2 로 바뀌었습니다만 모든 텍스쳐가 ETC2로 기본 설정 되는 것은 아닙니다. ETC2가 기본이 되는 것은 RGBA 텍스쳐(즉, 알파를 포함하는)입니다. ETC2는 ETC1과는 달리 알파 채널을 포함할 수 있기 때문입니다. RGB만 존재하는(즉, 알파채널이 없는) 텍스쳐의 기본 압축 포맷은 여전히 ETC1입니다. RGB 텍스쳐를 ETC로 사용하기를 원하시면 Texture Type을 Advanced 로 변경 후 Format 설정을 바꿔주셔야 합니다. 

릴리즈 노트에서 언급한 포맷 기본값이 바뀌었다는 내용은 RGBA 텍스쳐에 해당하는 내용입니다. 기존에는 16bit RGBA였는데 이 것이 ETC2로 바뀌었다는 것입니다. 릴리즈 노트가 부실해서 충분히 오해의 소지가 있을 것 같습니다. (아직 매뉴얼 페이지에는 이 내용이 갱신되지 않은 것 같습니다. 사람 사는데가 다 똑같죠 뭐 헤헤 양해좀 굽신굽신)


Open GL ES 2.0에서의 RGBA 텍스쳐

하지만 그렇다고 Open GL ES 2.0에서 RGBA 텍스쳐를 사용하려면 RGBA 16비트 혹은 RGBA32비트만 사용하여야 하는 것은 아닙니다. Compress using ETC1(split alpha channel)을 선택하면 원본의 RGBA가 유니티 내부적으로 두 개의 ETC1으로 갈라서 하나는 RGB, 다른 하나는 알파 채널 정보를 담는게됩니다. 그럼으로써 ETC2를 사용하지 않고도 알파 채널을 사용할 수 있는 꼼수를 부립니다.

다만, 이렇게 되면 실제로는 2 개의 텍스쳐 슬롯이므로 쉐이더에서도 텍스쳐 레지스터를 두 개를 차지하게 됩니다. 예를 들자면 내장(bult-in)쉐이더 중 Sprite-Diffuse.shader를 살펴보면 다음과 같이 메인 텍스쳐를 읽은 뒤 _AlphaSplitEnabled 조건이라면 알파 채널을 별도로 한번 더 읽는 것을 확인 가능합니다.

fixed4 SampleSpriteTexture (float2 uv)

{

fixed4 color = tex2D (_MainTex, uv);

#if UNITY_TEXTURE_ALPHASPLIT_ALLOWED

if (_AlphaSplitEnabled)

color.a = tex2D (_AlphaTex, uv).r;

#endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED

return color;

}

단, 이 기능은 현재 릴리즈된 버전에는 스프라이트에 쓰이는 경우에만 작동하고 있으며 차츰 사용처를 확대해나가는 작업이 진행 중입니다.


ETC1이냐 ETC2냐 그것이 문제로다

“어쩌라는거야 그럼 ETC1 쓰라는거야 ETC2 쓰라는거야?” 이쯤 되면 이러한 질문이 나오시게 될 것입니다 :) 저도 사실 여기에 대한 명쾌한 답변을 드릴 수는 없습니다. ES 3.0지원 기기의 점유율이 증가하고 있는 추세긴 하지만 아직까지는 ES 2.0 지원 기기들의 점유율이 더 높은 상태기 때문입니다. (RGB 텍스쳐의 압축 기본 포맷은 ETC1으로 유지하는 이유이기도 합니다.) 이는 유니티 하드웨어 스탯 사이트에서 확인 가능합니다. 

다만, ETC2를 사용하면 그 만큼 더 메모리를 절약하고 더 높은 퀄리티를 낼 수 있는 것은 자명한 일입니다. 때문에 제 개인적인 생각으로는 주 타켓 기기를 무엇으로 삼냐에 따라 선택을 달리해야 할 것 같습니다. 물론, 보급형 기기를 타겟으로 하는 가벼운 게임이라면 ETC1을 포기해서는 안될 것입니다. 하지만, 고퀄리티 고성능 기기 게임이라면 ETC2를 사용하고 ES 2.0 기종에서는 낭비되는 메모리만큼 다른 부분에서의 품질을 과감히 포기하는 방향도 그리 나쁜 선택만은 아닐 것입니다. 참고로, SystemInfo.graphicsDeviceVersion를 통해 ES 버전을 확인 가능하고 QualitySettings.SetQualityLevel를 통해서 퀄리티 변경이 가능합니다.


SA

다음 링크들을 같이 참고해보시면 더 추가적인 정보들을 확인 하실 수 있을 것입니다:




더 많은 내용은 "유니티 그래픽스 최적화 스타트업"을 참고하세요

Posted by 오지현 / Unity Korea Lead Evangelis ozlael

댓글을 달아 주세요

  1. Eugene-rho 2016.01.06 11:29  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다. ^^ 궁금했던 부분을 이 글을 읽고 알게되었습니다. 몇년 전에 제가 KGDA 발표한 내용도 글로 작성해 주셨는데, 오랜만에 들어오게 됐네요. 그런데 혹시 유니티에서 근무하시나요?

  2. bonho 2016.02.01 15:36  댓글주소  수정/삭제  댓글쓰기

    안녕하세요. 좋은 정보 늘 감사히 보고있습니다^^
    다름이 아니라 Compress using ETC1 체크를 하면 ETC1으로 변경된다하셨는데요,
    텍스쳐 정보에 체크를 하면 ETC2 8bits로 나와있어서 좀 헷갈리네요.
    표시만 ETC2이고 실제론 ETC1으로 들어가는 것 인지요~

  3. kim 2016.02.16 12:33  댓글주소  수정/삭제  댓글쓰기

    안녕하세요. 좋은 정보 참고하여 업무에 사용하고 있습니다. 다름이 아니라 제가 OpenGL2.0 폰에서 ETC2의 텍스쳐를 올려서 프로파일러로 메모리 사용량을
    확인해봤는데 위에 말씀하신데로라면 메모리가 더 늘어나야 맞는데 OpenGl3.0 폰에서 확인한 메모리와 동일하게 체크가 됩니다..
    이 부분에대해서 궁금하여 이렇게 댓글 남깁니다. 답변 부탁드리겠습니다 ㅎㅎ