본문 바로가기

디자인로그/기타자료

모바일 게임 최적화의 정석 - 텍스처 압축

728x90

 

모바일 게임 최적화의 정석 - 텍스처 압축 편

http://littles.egloos.com/3439290

 

http://littles.egloos.com/3439290

모바일 디바이스들의 메모리 크기가 많이 커졌다고는 하나, 늘어난 해상도 대비 게임이 사용할 수 있는 메모리의 공간은 여전히 늘 부족하다. 또한 사용자들은 최소한의 앱 설치 사이즈를 원하므로, 메모리와 저장공간의 측면에서 텍스처 압축은 필수이다.

요새 웬만한 디바이스의 해상도는 720p 이상이므로 화면 전체를 덮기 위한 1280x720 사이즈 이미지 한장의 24bit 무압축 크기는 2.7MB나 된다. 알파채널이 포함되면 3.6MB나 되니, 이런 이미지 몇장만 로드하면 메모리가 금새 가득찰 것이다.

현재 주요 모바일 디바이스에서 고려 가능한 텍스처 포맷은 다음과 같다.

iOS 기기: 32bits RGBA, 24bits RGB, 16bits RGB(A), 4bits RGBA PVRTC, 2bits RGBA PVRTC2
안드로이드 기기: 32bits RGBA, 24bits RGB, 16bits RGB(A), 4bits RGB ETC1, 4bits RGBA DXT1, PVRTC, ATC, S3TC ...

위에서 나열된 주요 텍스처 포맷들의 특성에 대해 간단히 살펴보자.

16bits RGB(A): 알파채널을 쓰지 않거나 마스킹용으로만(565 혹은 5551) 쓴다면 꽤 괜찮은 품질을 보여준다. 다만, 알파채널이 들어가면(4444) 디더링 때문에 원치 않는 품질을 보게 될 것이다. 32bits 대비 절반의 용량이므로 일단 쓸만하긴 하나, 다른 압축 포맷에 비해 메모리 효율이 낮다.

PVRTC: 픽셀당 알파포함 4bits 이므로 32bits 원본대비 무려 1/8의 압축률을 보여주며, 대체로 품질도 좋다. 다만, 알파채널의 이미지에 부드러운 그라데이션이 있다면 노이즈(block artifact)를 보게 될 것이다. 안드로이드의 경우 극소수의 디바이스만이 지원한다. 픽셀당 2bits인 PVRTC2도 존재하나, 품질이 열악하므로 사용될 경우가 거의 없어 보인다.

ETC1픽셀당 알파없이 4bits로 24bits 원본 대비 1/6의 압축률이며, 대부분의 경우 원본과 차이를 못 느낄 정도로 품질이 좋지만, 알파채널을 지원하지 않는다는 큰 단점이 있다. iOS에서는 지원하지 않으며, 안드로이드 2.2(프로요) 이상의 안드로이드 디바이스는 모두 필수적으로 지원한다.

ATC, DXT ... : 일부 안드로이드 기기들이 지원하기는 하나, 각 디바이스마다 지원여부는 천차만별이다. 심지어 S사의 제품들조차 모두 다른 포맷을 지원한다. 그나마 ATC와 DXT 등의 지원 비율이 높은 것으로 통계가 있었으며, 이들 기기만을 위한 별도의 APK를 배포하는 것도 가능하기는 하다.

위의 사실들을 고려하면, iOS에서는 PVRTC4, 안드로이드에서는 ETC1의 포맷을 선택하는 것이 가장 현실적이다.

두 개의 포맷에 심화하여 구현과 최적화 접근법을 살펴보자.


PVRTC
모든 iOS 기기에서 사용할 수 있는 효율성 높은 압축 포맷이므로, iOS의 경우 가장 적합한 압축 포맷이다.
RGBA의 4개 채널을 픽셀당 4bit로 표현할 수 있으나, 알파 이미지의 형태에 따라 많은 노이즈 보일 수 있다. DXT3/5 등에서 볼 수 있는 것과 유사한 블록화 현상 또는 알파값 경계선 부분에서의 노이즈가 도드라진다.
만약 원본 이미지에서 알파채널이 없거나, 알파의 모든 픽셀값이 255라면 압축에 의한 노이즈가 많이 사라지므로 충분히 높은 품질을 보여준다.
따라서, RGB채널만을 압축한 PVRTC 한 장, 그리고 알파 채널만을 RGB grayscale로 변환 후 압축한 PVRTC(또는 PVRTC2)의 두 장의 텍스처를 함께 사용한다면 꽤 좋은 품질의 RGBA 렌더링을 수행할 수 있다. 이 경우 픽셀당 8bit(4bit*2)를 사용하게 되나, 여전히 32bit 원본보다는 1/4의 압축률을 가지므로 다양한 경우에 활용할 수 있다. 더 나아가서, 알파 채널의 텍스처에 대해서만 절반 해상도로 줄인다면 RGBA 픽셀당 5bit를 사용하는 셈이 된다. 대부분의 경우 알파 채널의 해상도는 그다지 높을 필요가 없으므로, 알파채널 해상도 최적화는 매우 유용하다.
그러나 PVRTC 압축을 사용하기 위해서는 텍스처의 해상도가 2의 지수승(Power-Of-Two) 정사각형이어야 한다는 제약이 있으므로 그래픽 리소스 제작 당시부터 이 점을 고려해야만 한다는 부담이 있다. 물론 리소스 빌드 과정을 만들어서 자동 스케일링을 할수도 있으나, 아트 원본의 디테일이 손상되거나 메모리 용량이 낭비되는 것을 피할 수 없을 것이다. 만약 원본 이미지가 텍스처 아틀라스의 형태라면, 다수의 원본 이미지로부터 스프라이트들을 추출하여 하나의 POT 아틀라스 텍스처로 압축하는 접근법은 충분히 쓸 만 하다. (아틀라스에 대한 이슈들은 추후에 별도의 글로 작성할 예정)
원본 이미지를 PVRTC 로 변환하는 방법에 대해서는 여기를 참고하면 된다.
게임에서 PVRTC를 로드하는 방법에 대해서는 애플의 PVRTextureLoader 샘플을 참고하면 된다.


ETC1
모든 OpenGL ES 2.0을 지원하는(Froyo 이상) 안드로이드 기기에서 사용할 수 있는 품질 좋은 압축포맷이다. (단, 일부 디바이스에서는 하드웨어적인 디더링 현상이 눈에 띄는 경우가 있다)
RGB 채널만 지원한다는 단점이 있기는 하나, 위의 PVRTC에서 언급한 것과 같은 방식으로 알파채널만 별도의 ETC1으로 압축한다면 픽셀당 8bit의 용량(알파채널 사이즈를 줄이면 5bit)으로 좋은 품질의 RGBA 렌더링이 가능하다.
본래 ETC1 스펙에는 텍스처의 해상도가 4의 배수이어야 한다는 제약만이 있으나, 일부 (유명) 디바이스의 경우 해상도가 2의 지수승이 아닌 경우 렌더링 오류가 나는 경우도 있다. 다행히도 가로세로 크기의 정사각형 제약조건이 있는 디바이스는 아직 본 적이 없다.
원본 이미지를 ETC1으로 변환하는 방법에 대해서는 여기를 참고하면 되며, ETC1을 게임에서 로드하는 방법에 대해서는 java 코드에서 사용할 수 있는 ETC1 클래스, C++에서 직접 로드하는 방법을 참고하면 된다.


기타 참고 사항
  • 위에서 RGBA 원본 텍스처로부터 알파채널만 따로 분리하여 압축하는 기법에 대해 설명하였는데, 본인의 경우 오픈소스 툴인 ImageMagick 을 이용하여 이 과정을 자동화 하였다.
  • 플랫폼에 따라 알파 채널이 별도의 텍스처로 분리되거나 포함되어 있는 경우를 각각 렌더링하기 위해서는 셰이더 코드에서 이를 처리해야 한다. 플랫폼별 매크로 또는 알파 채널 텍스처 파일의 독립 존재여부를 인식하여 셰이더 코드가 다르게 작동하기 위해서는 셰이더 컴파일시에 알파채널 독립 로드 여부에 대한 #define 을 삽입하거나, 셰이더 코드 조각을 선택적으로 삽입함에 의해 이를 구현할 수 있다.
  • 텍스처 포맷과는 관련이 없으나, 안드로이드 기기의 align 되지 않은 apk 내부에 있는 일부 이미지 데이터는 파일 읽기 오류가 날 수 있다. 같은 픽셀값이 다수 반복되는 경우에 발생할 수 있는, 안드로이드 시스템 자체의 버그인 것으로 알려져 있다.

 

TIP> PNG 이미지 최적화 사이트 https://tinypng.com/

 

 

 

 

 

 

 

728x90
반응형
LIST