Unityシェーダーチュートリアル 遮蔽箇所の反射を抑える
シェーダー
部屋の中に机と棚。建築VRでは良くある組み合わせですが、反射の表現は結構難しいです。
とりあえずセオリーとして、部屋の中央に Reflection Probe を配置し、
範囲を部屋のサイズに合わせて、Box Projection を使用します。
分かり易くするために Smoothness を高めに設定しています。
するとこんな反射になりますが、棚の中の反射が明らかに変です。
開口部の強烈な反射が遮蔽を無視して現われてしまうのです。
ディファードレンダリングの場合は、Reflection Probe のピクセルブレンディングや、
スクリーンスペースリフレクションを使用して、ある程度ごまかすことができます。
しかし、フォワードレンダリングの場合は上記の方法を使えないので、
オブジェクトを分離して反射を切ってみたり、
Smoothness を敢えて下げて反射を抑えてみたり、
最悪、妙な反射が残ったままほったらしになっている場合もかなりあるのではないでしょうか。
良くそういうシーンを目にします。
コレがパッと見のクオリティをガクッと下げるのです。
弊社のVRコンテンツは品質とパフォーマンスを考慮し、99%以下の設定で進めます。
・フォーワードレンダリング & MSAA
・リアルタイムGIは使わない
・ライトマップは必ず焼く
・太陽光のみ Mixed で、それ以外のライトはすべて焼き込み
この設定でうまい具合に遮蔽部分の反射を抑えることができるように、
ビルトインシェーダーを少し改造します。
Standard シェーダーの Occlusion
Standard シェーダーには Occlusion という名のテクスチャスロットがあります。
ここに「完全に黒」のテクスチャを入れてみます。
「完全に黒」になりました。
Occlusion に入力された値が、ディフューズとリフレクションの両方に乗算されているのです。
太陽光のみ残っていると言う事は、リアルタイムライトの計算より前に乗算されているのでしょう。
それはさておき、つまりこのディフューズへの乗算だけを取り除いてしまえば、
遮蔽部分の反射を抑える事が出来そうです。
ビルトインのシェーダーファイルをインポート
ビルトインのシェーダーコードは,Unity のインストールフォルダの中に入っています。
[インストールフォルダ → Editor → Data → CGIncludes] を開いてください。
Lighting.cginc / UnityPBSLighting.cginc / UnityGlobalIllumination.cginc
というファイルがあります。
この3つのファイルをプロジェクトにインポートします。
UnityGlobalIllumination.cginc を改造
目的のコードは UnityGlobalIllumination.cginc に記述されています。144行目あたりを見てください。
o.gi.indirect.diffuse *= occlusion;
一目瞭然、ディフューズに遮蔽情報が乗算されているので、この1行をコメントアウトします。
同フォルダにシェーダーを新規作成して、o.Occlusion にテクスチャをセットできるようにします。
すでにカスタムシェーダーを作っていた場合は、Reimportしてください。
すると、、、
ディフューズがそのままで、反射だけが完全に消えている状態です。
真っ黒のテクスチャではなく、Occlusion用のテクスチャを作るとこんな感じになります。
空間の広いところには反射があり、棚の中など遮蔽された狭い場所の反射は消えています。
Standardシェーダーでの動作
上記の手法はカスタムシェーダーでのみ動作します。
ビルトインの Standard シェーダーでも同様の効果を得たい場合は、
インストールフォルダの UnityGlobalIllumination.cginc を直接編集して、Unity を再起動すれば良いです。
しかし、同じバージョンの Unity を使用している他のプロジェクトにも影響が出るので、注意が必要です。