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

テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】モデルを透明にする (2)

今回はよりアニメ寄りというか、正しくないが見た目の良い透明の表現について色々とやっていきます。

f:id:tsubaki_t1:20150910040451p:plain

前回のエントリー(単純に透明マテリアルを設定する方法)はこちら。

tsubakit1.hateblo.jp

目次

透明なオブジェクト

前回のエントリー最後にユニティちゃん(天使)のグロ画像を紹介しました。この絵は間違っているように見えなくもないですが正しいです。

f:id:tsubaki_t1:20150907215905p:plain

透明とは背景が見えている状態ではなく、中身が透けて見える状態を指します。例えばクリオネは透明な体を持っていますが、同時に内蔵も見えています。
つまりサーヴァントやら幽霊が透明になるシーンでは、実際は内蔵や筋肉・骨格が見えた状態でどんどん透明になるという、恐ろしい絵が見える訳です。ああ!

f:id:tsubaki_t1:20150910035814p:plain

単一メッシュで中身が存在しないケースなら兎も角、ユニティちゃんのような複数パーツで構成され内蔵を持つモデルの場合、単純に透明化するとこうなるのは必然です。
ですが、こんなSAN値直葬な絵など見たくはありません。ので、内蔵を取っ払います。

Depthバッファへの書き込み

3Dは概ね、ピクセルシェーダーで色を塗る際にDepth(深度)の判定を行い手前のモデルのみを描画しています。そうする事で、モデルの奥にあるカメラから見えないモデルの描画をスキップする訳です。

例えば「Depthバッファ」のみを設定しモデルを描画しないと、下のようにモデルの位置がポッカリとくり抜かれます。

f:id:tsubaki_t1:20150910041144p:plain

この機能を活用し「モデルの内蔵の描画をスキップ」します。

Depthバッファを書き込みつつ透明シェーダー

この機能を実現するには、「Depthバッファへ書き込みつつ透明」なシェーダーが必要です。Depthバッファへ書き込むと奥にあるポリゴンが塗られなくなるのでナンセンスにも程がある訳ですが、とにかく必要です。

シェーダーとしては、2パスを使用します。1パス目でZ値を書き込みつつ完全に透明、2パス目で半透明の色を塗る…といった感じです。

f:id:tsubaki_t1:20150910042153p:plain

f:id:tsubaki_t1:20150910042206p:plain

ここで問題になってくるのが「Surface Shaderで2パス表現する方法」です。別にSurface shader使わなくても良いと言えば良いのですが、使った方が絶対に楽なので使います。

これはSurface Shaderの中身を2回書けば良いみたいです。ネスト構造でないため気持ち悪い上に文法的に正しいのか微妙ですが、とにかくそうなっています。

gist.github.com

で、そのあたりを色々うにょうにょやった結果が下のようなシェーダーです。1パス目で無色でDepthを書き2パス目でDepthバッファより手前にある部分のみ色を塗ります。

gist.github.com

これでレンダリングがDefferdならば何故か綺麗に出るのですが、Forwardレンダリングの場合は想定通り、半透明キャラクターの後方にある壁が塗られず背景が見えてしまっています(クリアカラーが表示されます)

f:id:tsubaki_t1:20150910044145p:plain

f:id:tsubaki_t1:20150910044137p:plain

これはDepthバッファに書き込んだお陰で、モデルの後方にあるオブジェクトが塗られない為です。
つまり、Forwardで描画したい場合はコレを何とかする必要があります。

二つのカメラで描画する

透明なモデルがZバッファを書く前に完全な背景を描画してしまい、後で透明オブジェクトをブレンドする…そんな考えです。

f:id:tsubaki_t1:20150910044659p:plain

ポイントはClear FlagをDon't Clearに設定する事です。Don't Clearを使用することで前回描画したDepthを使いつつ描画を行う事が出来ます。

これで事前にGhost Shader以外のオブジェクトを描画しておけば、Ghost ShaderのDepthに潰される事なく他を描画することが出来ます。

f:id:tsubaki_t1:20150910050025p:plain

f:id:tsubaki_t1:20150910051005p:plain

逆にDepth Only(デプスだけクリアするよ!)を行うと、Depthがクリアされてしまうのでモデルの奥にあるオブジェクトが塗られます。
これは、カメラ的に現在あるDepthを無視したい時に使えます。

f:id:tsubaki_t1:20150910050016p:plain

2つのカメラで描画する手順

実際の手順はこんな感じです。

まずユニティちゃんと背景を別レイヤーにします。ユニティちゃんは…TransparentFXとかにしておきます。

f:id:tsubaki_t1:20150910045002p:plain

次にTransparentFX用カメラの設定です。

ゲーム画面を描画しているカメラの子オブジェクトとしてサブカメラを設定します。座標は親と同じ位置で、カメラのDepthはメインのカメラより大きい(後に描画)です。
Clear FlagはDont Clearとします。
Culling MaskはTransparentFXのみを指定します。

ちなみにMain Cameraタグを外しておかないと、Camera.mainでこっちが検出されることがあります。カメラをコピーする場合は注意です。

f:id:tsubaki_t1:20150910045418p:plain

最後にMain CameraからTransparentFXを外します。でないと、無意味に2回レンダリングされてしまいます。

f:id:tsubaki_t1:20150910045623p:plain