2012/01/14

cocos2dでパレットっぽいことをしてみたい



 こんな感じに同じキャラなんだけど色違いのキャラをいっぱい出したい場合、2D表現が主流だった頃はパレットの色を変更することで実現するということがメジャーでした。しかし今の主流はテクスチャを使用した画像処理なためパレットの効果を入れるにはちょっと大変です。cocos2dもOpenGLベースなので条件は同じですね。ということで実現するには…と考えてみた。

●アイデア
1,テクスチャ書き換え
2,白い素材を用意し、マテリアル色指定
3,シェーダーでリアルタイム書き換え

 1と2の方法は「cocos2d for iPhone 1 Game Developer Cookbook」に処理の紹介がありますので、そちらがわかりやすいです。



1,テクスチャ書き換え
 肝はCCTexture2DMultableというテクスチャ書き換え機能のついたCCTexture2Dクラスを使うことですね。これはOpenGL側で管理しているテクスチャメモリを書き換える為のメソッドが追加されたCCTexture2Dだと思えば良いです。

 利点:元になるテクスチャが何色でもOK。

 欠点:色変更後のテクスチャはそれぞれ別にメモリに載るので不経済。テクスチャが共通じゃないのでCCSpriteBatchNodeが使えない。そのため描画が多少遅い。



2,白い素材を用意し、マテリアル色指定
 これは元の絵のなかの色を変えたい部分だけを切り分けた別レイヤーとして素材を用意し、白で描いておく。これを使ったCCSpriteを色指定することで色を載せるというもの。cocos2dの基本機能だけで実現できます。

 利点:テクスチャが共通化するのでCCSpriteBatchNodeが使え、描画が高速なはず。省メモリ。

 欠点:色を変えたい部分を分けた素材を用意するのが手間。



3,シェーダーでリアルタイム書き換え
 OpenGLES2以降であればピクセルシェーダが使えるので、描画時にリアルタイムに色変更して表示することができるはず。

 利点:テクスチャが共通なので省メモリ。

 欠点:僕はシェーダー作ったこと無い。OpenGLES2に対応したcocos2d2.0のベータ版を使わないとならない。描画が遅いかもしれない。シェーダーに渡すパラメータが色ごとに変化するので、CCSpriteBatchNodeで処理させるには難しいかも?



 以上が考えられるなぁと思いました。

 まずはお手軽なところからと、1の案をテストしたのが冒頭の画像です。iPhone4での表示ですが、1キャラあたり6レイヤーつかっていて、50体表示という状態です。これで60FPS出ているので処理能力的には十分かもなぁという印象。ただし、MacBookPro上でシミュレーターでの実行結果は30FPSしか出ませんでした。CCSpriteBatchNodeは使ってません。
 cocos2dのcookbookで紹介されているままの方法では、色変更後のテクスチャはCCTextureCacheへ乗らず、同じ色変更を何度も指定すると同じテクスチャが量産されてしまうコードだったため、その部分は自前でキャッシュへ載せて共用するように直しました。

 次は2のアイデアを試そうと思ってます。そのためには絵素材を色別に分離して別々のテクスチャに分配する必要がありますが、手作業でやるのめんどい…。2の方が処理が速いのであれば、最終的には絵素材の分離ツールを作らないとだなぁとか思ったり。

●追記
 2のアイデアを実装して試したところ、CCSpriteBatchNodeの威力もあるだろうが100人出しても60FPSラクラク回ってました。1レイヤー(というかCCSprite)には1色しか指定できないので、色分だけ枚数が増えてますがそんなの全く影響が見られないですね。下図は1キャラ11レイヤー使ってます。ちなみに、CCSpriteのcolorプロパティで色を設定するとその色が乗算されるので黒の輪郭を色変更せずにそのまま残したいという場合は、どこかのカラーのスプライトに入れ込んでしまってもOKです。黒なので他の色を重ねても黒以外になりませんから。