はじめに
はじめまして。カヤックの技術基盤チームの Unity エンジニアのアファトです。この記事はカヤックUnityアドベントカレンダー2016の10日目の記事になります。 今日は Texture Format ついてお送りします。
Texture Formatについて
ゲームに使われる素材の中に、容量的に Texture はだいたい一番多いです。例えばカヤックのソーシャルゲームプロジェクトだと、Texture は全体の容量の6~8割くらいを占めています。そしてメモリーサイズもそれに比例してるので、ゲーム開発には Texture Format は重要なポイントの一つと考えられます。画面に映るものの画質とメモリサイズとパーフォマンス、この3つのバランスが得られるために適切な Texture Format を選ばないといけません。
Texture File と Texture Formatの関係
最初にUnityを触る時に、Texture Fileのフォーマットもあるので、そもそも Unity のTexture Formatはどういうことだ?ときになるかも知れません。簡単に説明すると、例えばあるプロジェクトに body_01_mat.mat
のマテリアルのテクスチャーを body_01.png
にアサインすると、Assetsの中にある body_01.png
画像ファイルと、その画像のImport Settingsと、body_01_mat.mat
マテリアルに実際に使われるテクスチャーのファイルとそれらを結ぶための body_01.png.meta
メタファイルのイメージは以下のようになります。
Texture Import Settings
Texture Import Settings の Texture Type を Advance にすると、全部設定できるオプションが表示されます。Advance 以外の Type だと、その Type に最も関連する設定しか表示されません。
- Non Power of 2 の設定は、2の冪以外 (NPOT, 例えば 100px × 100px) のテクスチャーをどうインポートするかの設定です。古いGPUには、2の冪の形のテクスチャーしか対応していないものがあるので、NPOTからPOTにコンバートするのにどんな方針でコンバートするの選択です。画像のサイズがすでにPOTなら設定が変えられません。
- Read/Write Enabled はランタイムで Texture を編集したり、ピクセルの情報を取得したりする場合 (
Texture.GetPixel()
又はTexture.SetPixel()
)、チェックが必要です。チェックを外すと、Texture は表示のためにしか使えないという設定です。Texture Format が Uncompressed か DXT1 以外はRead/WriteをEnabledに設定してもTexture.SetPixel() は使えません。チェックをした場合、メモリサイズが2倍になってしまうので要注意です。
Texture Format
基本的には3種類に分けられます:Compressed, 16 Bits, True Color。それぞれのフォーマットはピクセル単位のメモリサイズ (bpp, bits per pixel) が付いてます。この bpp で圧縮効率が簡単に計算できます。例えば、 4-bpp の texture format は 32-bpp の texture format の 1/8分のメモリサイズになります。
True Color (32・24bpp)
True Color Mode はもとの画像の画質はそのままで texture をインポートします。このModeは画質は一番良いが、Memoryサイズは他のtexture formatより一番でかいです。 Memoryサイズの計算は pixel数 x bpp、例えば 透明あり1024x1024画像 (32-bpp) は 1024x1024x32 bits (10242 x 4 bytes = ~4MB) のメモリを食います。
16 Bits (16-bpp)
このモードではピクセルの色が 16-bit の color spaceにmappingされます。Alphaがついてる場合 (RGBA)、それぞれのチャネルが 4-bit (RGBA4444 = 16-bits)になりますが、Alphaなしだと、RとBチャネルが5-bits、Gチャネルが 6-bits (RGB565 = 16-bits) になります。
16-Bitsモードは色数がかなり減るので、単色塗りつぶし系の画像に適していますが、グラデーションなど色が滑らかに変わる画像では color banding という現象が発生します。色が滑らかに変わるような画像で使う場合、事前にディザリングを使って色数を落としてからUnityにインポートすることでだいぶ実用的になります。pngquant、unity-dither など、いくつか無料なディザリングツールがあるので便利です。
Compressed
Compressed Texture Formats はPlatformやハードウェアーによって異なります。画像フォーマット(JPG, PNGなど)と違って (lossy又はlossless)、ファイルサイズを小さくするため、ここの圧縮フォーマットは必ず lossyで、メモリ上でのサイズを圧縮するフォーマットです。
ETC (Ericsson Texture Compression) 全てのAndroid機種が対応できるフォーマット。
- ETC1 OpenGLES 2.0以上対応するAndroid機種はサポートします。普通は透明がある画像 (Alphaチャネルあり) は対応できないが、Unity 5.2からsplit-alphaというテクニックでalphaも使えるようになりました。
- ETC2 OpenGLES 3.0対応するAndroid機種はこのフォーマットが使えます。Alphaチャネルもサポートされます。
PVRTC (PowerVR texture compression). iOS全機種が対応できるフォーマットです。Android機種の場合はPowerVR GPUを使ってる機種しかこのフォーマット使えません (Nexus S, Kindle fireなど)。
ATC (ATI texture compression). Qualcomm Adreno GPUを使ってるAndroid機種しかこのフォーマット使えません (Nexus One...)。
DXTC (S3TC, S3 Texture Compression) PCはサポートしますが、モバイルだとNvidia Tegra のGPUしかサポートしません
Androidの場合は、開発しやすくするため、圧縮が必要な時は全機種対応できるフォーマット ETC1 が有力です。ETC1でも透明サポートする設定について
Texture Format の比較
複数画像のセットに様々な Texture Format にコンバートし、横並びにして、画質の比較です。 (参考)
PVRTC画質について
Alphaに対応できるモードがありますが、特に透明部分との境目の画質がかなり落ちます。一つ対策としては UnityのETC1 split-alphaと同じテクニックを使い、RGB 4-bit と A 4-bitを組み合わせることで (PVRTC-RGB4A4, 8-bpp)画質が上がります。以下のようにUnityのデフォルトPVRTC RGBA 4-bppの画質 (右から2番目) が他のフォーマットに比べると、真ん中上にある点線が完全にぼやけてるように見えます。Split-alphaのテクニックを使うと、メモリサイズがRGBA16の半分なのに、RGBA32 と似てる画質が (一番右)。
おわりに
適切な Texture Format はゲーム開発には重要なんですが、最初からやる必要がないです。ある程度 UI や in-game が出来てから、軽量化やパーフォマンスチューニングの時にやった方が良いと思います。明日はRender Textureについてになります。 担当は清水です。 お楽しみに!