technostallion

Unity、プログラム、グラフィック関係の技術ネタを書き殴ります

【Unity】Alpha CutoutシェーダーでSpineのキャラクターを不透明描画する

昨日のエントリーで触れたSpineキャラクターの半透明問題への限定的な対処方法を思いついたので書き残しておく。
これは半透明の絵素材(例えば宇宙服のヘルメットのバイザーなど)を使ってないキャラクターに対してのみ有効。

パンチスルー

トランスペアレンシー情報を持たないテクスチャから絵部分だけを抽出する方法として、パンチスルー(1ビット抜き)と呼ばれる非常にレガシーな手法がある。
これは予め取り決めたカラーやビット情報と一致するピクセルの描画をスルーするという単純な原理に基づいており、アルファブレンディングがハードウェア的に困難な処理であった時代には特に多用されていた。

Cutoutシェーダー

f:id:helementsof:20150218214333p:plain

Unityにもこの原理を利用したシェーダーがビルトインで用意されている。
Transparent/Cutout以下のシェーダーがそれ。

f:id:helementsof:20150218215114p:plain

Alpha Cutoffパラメータが閾値で、アルファ値が基準に満たないピクセルの描画がスルーされる。
左端に寄せると完全に透明のピクセルだけをスルーし、右に寄せるほど透明度の低いピクセルもスルー対象に判定される。
このシェーダーが設定されたマテリアルは不透明オブジェクトとして描画されるため、パーティクルと一緒に表示しても破綻が生じない。


Spineのデータにこのシェーダーを設定すると別の問題が発生する。

f:id:helementsof:20150218220722p:plain

Zバッファへの書き込みが有効になると面同士の重ね合わせが正確に計算されるようになるため、全く同じローカルZ座標上にパーツを重ねて表示しているSpineのメッシュがZファイティングと呼ばれるノイズを生じさせてしまうのだ。

Unity でのZファイティング(Z-Fighting)の対処法 - 強火で進め

幸いにもSpineにはZファイティングを解消するためのパラメータが用意されている。

f:id:helementsof:20150218220419p:plain

Skeleton Animationコンポーネントがアタッチされているオブジェクトを選択してインスペクタをデバッグモードに設定する。
するとZ-Spacingというパラメーターが表示されるようになるので、ここに小さな負数を入れてやることで、ローカルZ座標上でパーツ同士の間に隙間を作ることができる。

f:id:helementsof:20150218220910p:plain

右がパンチスルーのシェーダーで表示した結果。半透明の球体との重なりが正しく表示されている。

なお、Spineは出力データにRGB888やRGB444のような1ビットアルファテクスチャのエクスポートにネイティブで対応しているので、自前で1ビット抜きのシェーダーを用意するほうがパフォーマンス的には良いかもしれない。

問題点

ジャギが出る。ピクセルを表示する、しないの二択になるので、アルファ付きテクスチャをそのまま表示する場合に比べてかなりエッジが汚くなる。
UnityProならアンチエイリアシングで誤魔化せる。