読者です 読者をやめる 読者になる 読者になる

【Unity】Texture Format

はじめに

はじめまして。カヤックの技術基盤チームの 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 メタファイルのイメージは以下のようになります。

image

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にインポートすることでだいぶ実用的になります。pngquantunity-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 にコンバートし、横並びにして、画質の比較です。 (参考)

image

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 と似てる画質が (一番右)。

image

おわりに

適切な Texture Format はゲーム開発には重要なんですが、最初からやる必要がないです。ある程度 UI や in-game が出来てから、軽量化やパーフォマンスチューニングの時にやった方が良いと思います。明日はRender Textureについてになります。 担当は清水です。 お楽しみに!