夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

【Unity5でレースゲーム】UnityのStandard Shaderをカスタマイズしてポリゴンの裏面も描画するシェーダーを作る

今開発中のオープンワールドなレースゲームではゼンリンのJapanese Otaku Cityアセットを使わせてもらっています。
このアセットに標準で設定されているシェーダーだと木の影が四角い板のようになってしまうのでNature/Tree Soft Occlusion Leavesシェーダーを使って木の影が綺麗に出るようにする方法を以前ご紹介しました。

tf.hateblo.jp

当時は完璧に思えたこの方法ですが、実は大きな問題がありました。
名前から察するにおそらく葉っぱを描くためのシェーダーなので、光の当たり方によってやたらと眩しく反射して色がおかしくなってしまうのです。
光の当たる向きによってはこんな風に白っぽく光ってしまいます。
f:id:takujidev:20150901205623j:plain

明らかに不自然な色なのですが、Unityに入っている様々なシェーダーを試したのですが、これ以上のシェーダーは見つからなかったのでこれまで我慢して使っていました。

Unity 5で標準的に使われているStandard ShaderでRendering ModeをCutoutにすると一見良さそうに見えるのですが、木の裏側に回ると木が見えなくなってしまうという大きな欠点があります。これは、Back-face Cullingという高速化手法によるもので、通常は見えないポリゴンの裏面は描画しないようにしているためです。
Japanese Otaku Cityの木は古典的な直角に配置した2枚の平面ポリゴンなので、すべての方向から木を構成するのポリゴンが見えるようにするためにはBack-face CullingをOFFにして、ポリゴンの両面が描画されるようにしてやる必要があります。

Nature/Tree Soft Occlusion Leavesシェーダーだと表示されていた木が…
f:id:takujidev:20150901210635j:plain

スタンダードシェーダーに切り替えるとBack-face Cullingのせいで消えてしまいました。
f:id:takujidev:20150901210707j:plain


スタンダードシェーダーにはBack-face Cullingを切るための設定は用意されていないので、シェーダーのソースに手を入れてBack-face Cullingを切ってみました。
なお、今回紹介する方法は私の環境では動いていますが、正しいやり方なのかどうかはわかりません。
何かおかしな点にお気づきの方は是非お知らせいただけると嬉しいです。

さて、シェーダーに手を入れるにはまずシェーダーのソースを手にいれる必要があります。

Unity - Download Archiveのページにアクセスし、

Downloadsボタンをクリックすると選択肢の中にBuilt in shadersがありますのでダウンロードします。
f:id:takujidev:20150901211521j:plain

ダウンロードしたファイルのDefaultResourcesExtraフォルダーの中にStandard.shaderというスタンダードシェーダーのソースファイルが見つかるはずです。

これを例えばStandardCullOff.shaderなど適当にリネームしてプロジェクトのAssetsフォルダーにコピーします。

あとはこれを適当なエディターで開いて編集します。
まずは先頭の行で定義しているシェーダーの名前をこんな感じに適当に変更します。

Shader "StandardCullOff"

なお、Macのテキストエディットで編集するのはお勧めしません。ダブルクオーテーションの閉じる方が違う文字に変換されたりしますので。

次に、下記のようにPassで始まるブロックがいくつもありますので、それぞれにCull Offという行を追加します。そのうち何箇所かにはすでにCull Offが書かれていますので、そこはそのままで結構です。

注:先ほども書きましたが、この方法が正しいという保証はどこにもありません。

		Pass
		{
			Name "FORWARD" 
			Tags { "LightMode" = "ForwardBase" }

			Blend [_SrcBlend] [_DstBlend]
			ZWrite [_ZWrite]

			Cull Off <------- これが追記した行

			CGPROGRAM
			#pragma target 3.0
			// TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
			#pragma exclude_renderers gles
			
			// -------------------------------------
					
			#pragma shader_feature _NORMALMAP
			#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
			#pragma shader_feature _EMISSION
			#pragma shader_feature _METALLICGLOSSMAP 
			#pragma shader_feature ___ _DETAIL_MULX2
			#pragma shader_feature _PARALLAXMAP
			
			#pragma multi_compile_fwdbase
			#pragma multi_compile_fog
				
			#pragma vertex vertForwardBase
			#pragma fragment fragForwardBase

			#include "UnityStandardCore.cginc"

			ENDCG
		}

追記が完了したらファイルを保存します。

すると、マテリアルのシェーダーの選択肢に先ほどカスタマイズしたシェーダーが現れます。
f:id:takujidev:20150901213721p:plain

木のようにテクスチャーの透明部分を表示したくないポリゴンの場合はRendering ModeをCutoutにします。
Alpha Cutoffの値で透明部分の閾値を設定します。
Metallic, Smoothnessは両方とも0にします。0でないとポリゴンの裏面が白っぽくなったりしますのでご注意ください。
f:id:takujidev:20150901214622p:plain

動画です。最近の他の動画と比べると木の色が自然になっているのがわかりますでしょうか?
特に、裏のストレートの高速道路下の道路の脇の木の色の違いがわかりやすいとおもいます。

https://itunes.apple.com/jp/app/toraberushutingu-retorona/id917570972?mt=8&uo=4&at=10laCt
https://itunes.apple.com/jp/app/beecluster-wu-liaono-zongsukurorushutingugemu/id663801586?mt=8&uo=4&at=10laCt