渋谷ほととぎす通信

完全趣味でやってる技術メモ。※所属団体とは一切関係がありません。

Unity 頂点シェーダ内でライト方向を取得する方法


Unityでシェーダを書く場合、とりあえず開発者が必要そうな変数やら関数はUnity側で用意されていることが多いので
"UnityCG.cginc""AutoLight.cginc""Lighting.cginc"この辺りのファイルたちを眺めると良い感じです。

f:id:esakun:20181212144015g:plain
このようなライト方向とカラーを適用したいわゆるランバートシェーダを書いてみます。
※前提としてディレクショナルライト1個の世界

ライトベクトルは_WorldSpaceLightPos0と記述すればUnityが勝手に値を突っ込んでくれます(とっても便利)。
ライトのカラーはfixed4 _lightColor0と定義すれば、先取同様Unityが勝手に値を突っ込んでくれます。

ただし、Lighting.cgincをインクルードしているとコンフリクトしてコンパイルエラーになるので注意です。

それらのデータを使って処理を書いていくわけですが、こんなに至れり尽くせりなのですが、 _WorldSpaceLightPos0頂点シェーダで使うことが出来ず、フラグメントシェーダ内でしか使えません。エラーは出ませんが、おそらく値が(0,0,0,0)になっています。


上のサンプルはピクセルライティング(ピクセル単位でライト処理を実行している)なのですが、頂点ライティングもやってみます。

ということで頂点ライティングは以下のような実装になります。

  • C#側からシェーダへライトベクトルを渡す
  • 頂点シェーダで頂点単位で拡散反射輝度を計算する
  • フラグメントシェーダで頂点ごとの輝度を描画する

シェーダとC#のサンプルコードです。
これらを描画するメッシュ、GameObjectにアタッチする想定です。

※注意 : もっと簡単な方法を後述しています


と、ここまで書いててあれですが、WorldSpaceLightDirというヘルパー関数があります。
この関数を使えば頂点シェーダ内で、ライトベクトルが取得できることがわかりました。
※C#のコードは不要となりますorz

最終このシェーダだけで頂点ライティングが出来るようになりました。

まとめ

  • 頂点シェーダ内でディレクショナルライトベクトルを受け取る方法は、WorldSpaceLightDir(オブジェクト空間頂点座標)というヘルパー関数を使用する

です。

環境

  • Unity2018.2.12f1

参考