2014年5月22日木曜日

cocos2d-x CCSprite(テクスチャ)の軽量化

どうも、俺@仕事中です。

今日はcocos2d-xで頻繁利用するCCSprite(またはテクスチャ)の軽量化についてめも。
軽量化というのは、ファイルサイズ的な意味ではなくパフォーマンス面での軽量化という意味です。
ファイルサイズ的な意味での軽量化については最後に記します。

CCSpriteで画像生成するとけっこうなメモリを消費します。
けっこうなメモリとはどのくらいかと言うと、一般的なpng画像(24bitフルカラー)の場合、
1pxあたり4byte(赤8bit + 緑8bit + 青8bit + アルファ8bit)になります。
例えば200x200(px)のpng画像の場合、
200 x 200 x 4byte = 160000byte = 156.25KB
必要です。

なのですが、iPhoneや(ほとんどの?)Android端末で画像を処理する場合、
(2014.5.22修正 iPhoneやAndroidで実際にどのようにメモリ確保されるか不明)
利用するハードウェアによって、
画像(テクスチャ)のメモリは、2の累乗のサイズで確保されます。
どういうことかと言うと、
上の200x200サイズ画像の場合、256x256サイズとしてメモリ確保されるため、
消費メモリは
256 x 256 x 4byte = 262144byte = 256KB
になります。
なんと、これだけで約100KB無駄なメモリ領域が発生してしまいます。

500x600サイズ画像の場合は、
512 x 1024 x 4byte = 2097152byte = 2048KB
になります。
約900KB無駄なメモリ領域が。

画像を大量に使用するゲームアプリなどだと、かなり無駄なメモリが消費されてしまうことになります。


そこでこの問題の解決方法(1)として、スプライトシートを使いましょう。


スプライトシートは複数の画像をまとめて一つの画像として扱うため、
上記で述べたような無駄なメモリ領域というのを極力縮めてくれます。

次に解決方法(2)ですが、pngを出力する際に
透過を使わない → png24で出力
画像が荒くても構わない → png8で出力
という方法もあります。
png24は、24bitフルカラーで透過利用不可になります。
png8はGIFと同じ256色になります。

または、cocos2d-x側で、
    // 透過使わない
    CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGB565);
    // 減色させる(赤4bit + 緑4bit + 青4bit + アルファ4bit)
    CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGBA4444);
を呼び出しておく、という方法もあります。

このpng8で出力、またはkCCTexture2DPixelFormat_RGBA4444の設定は非常に効果的なのですが、画質が目に見えて荒くなるのが分かるのが残念です。
特にグラデーションは目も当てられません。

そこで、TexturePacker(基本有償)というツールを使いましょう。

有償なだけにとても高機能で、
TexturePacker上で画質を上述したRGBA4444に減色出来ます。
またすごいのが、画質が落ちた画像ファイルをディザリングという機能でキレイに加工してくれます。

例えば下の画像はRGBA8888の綺麗なままのpng画像。
※見やすいように拡大表示しています。

これをRGBA4444に画質を落とすと、
のようにグラデーション部分に荒い線が浮き出てしまいます。

これにディザリングをかけると、
のようになります。
荒いポツポツが目立ちますが、
拡大表示していることが原因で、実物サイズにすると
ほらキレイ。
目を細めてみると ほぼ元画像との違いなんて分かりません。

ちなみに、RGBA4444画質の元サイズはこちら。
うーん、、、
画像が小さいからあまり違い分からないですが、
やっぱりグラデーションが汚いです。そう思って下さい。

というわけでTexturePackerを使えば、
スプライトシートを生成できるだけでなく、画質の調整もできちゃうのでオススメです。



冒頭に書いた「ファイルサイズ的」な軽量化についてですが、
MacだとImageOptimがオススメです。

いろんなアルゴリズムを駆使して画像ファイルを圧縮し、ファイルサイズを小さくしてくれます。
ものによっては60%以上ファイルサイズが軽量化することもあります。
配布するアプリサイズが小さくなるので良いですね。
メモリへのロードも早くなるのかな?


あとは、CCSpriteBatchNodeを利用して、描画も軽量化させると見違えるほどアプリが軽くなります。

以上でぇぇぇぇぇす。

0 件のコメント: