Unity ChromaPack のアルファ対応版を書いてみました
ChromaPackとは、Keijiro Takahashiさんが公開しているUnity用のテクスチャ圧縮プラグインです。
ChromaPack -- Unity でテクスチャ圧縮するプラグイン。色差サブサンプリングを使って見た目の劣化ほぼ無しにピクセルあたり 12 bit まで減らします。透過対応。iOS/Android 対応です。
https://t.co/Fv6Dt0btGU
— Keijiro Takahashi (@_kzr) January 8, 2015
ChromaPackが用いるChroma subsamplingとは、 色をLuma(輝度)とChroma(彩度)で表し、Chromaの方だけを圧縮すると比較的高品質になるという手法です。
ChromaPackは1ビットのアルファしか対応していないので、半透明を表現できません。 そこで、ChromaPackとほぼ同じ方式で半透明も対応したものを作ってみました。 github.com
圧縮の概要
- まず、RGBをYCgCoに変換。
- ChromaPackで使っているYCbCrより計算が簡単。 ただし、行列演算が高速であればYCgCoもYCbCrも計算速度は同じっぽいので要検証。
- Y成分をAlpha 8で保存。
- Cg・Co・Alpha成分を以下のどれかで保存。
- 4bppのブロック圧縮(PVRTC、ETC1、DXT1)。
- 幅と高さを半分にして、RGB565かRGB24。
結果的にサイズは、8+4=12bppとか、8+6=14bppとかになります。
圧縮ツールの使い方
「Window/YCgACo Editor」を開いて、 元画像を選択して「Generate Y, CgACo and Material」 をクリックすると圧縮テクスチャが同じフォルダに出力されます。 出力されるPNGファイルは実は1ピクセルのダミー画像で、 実際のデータは、YCgACoPostprocessor.OnPostprocessTextureで 生成されるようになっています。 AssetImporter.userDataに、元画像のGUIDや出力フォーマット等を書き込んでいます。
例
128x128の半透明テクスチャを圧縮して描画した例です。 酷くセンスが悪いですが、半透明のUIを想定しています。 黄色が今回の手法、白字が他の普通の手法です。 Open GL ES 3 が対応している端末では、 ETC2が使えることになっているので、ETC2を使いましょう。 それ以外の端末向けには本手法も利用価値があるかもしれません。 OpenGL ES 3 普及率をUnityのサイトで確認した限りでは、1年後には新規開発ではES2以下を無視する時代になってそうですが…。
16ビット(RGBA4444)でディザ処理をすると、 ディザのノイズが目立って9-Patchに使えないのが弱点ですが、 上の方法だとその辺も問題無さそうです。 以前、9-Patchのために、16ビットのスプライトシートに32ビットを簡単に埋め込む方法を研究したりしたんですが、それに比べると何倍も役に立ちそうな感じがします。
懸念点
メモリ上ではなくディスク上でのサイズをちゃんと確認した方が良さそうです。 PVRTCやETCなどのブロック圧縮形式をlzmaで圧縮すると、 32ビットのままlzmaで圧縮した場合より大きくなることも多分あり得るので…。