家弓メソッドを利用したレイマーチングはGitHubにアップしてあるMaterialCollection内にサンプルが存在していたりします。
しかし、こちらのサンプルは基本的にライティングなどをマテリアル内で行うことを前提として作成しました。
そのため出力はEmissiveのみ、Unlitで行うことを前提としています。
というか、ポストプロセスで利用するのが基本、という感じで作成しています。
少し前に、ある人物からこんなことを聞かれました。
「レイマーチングで描画したものに影を落とすとしたらどうやります?」
それは面白そうだ、やってみよう。ということでやってみました。
家弓メソッドを用いた距離関数の切り替え手法とレイマーチングの行い方は説明しません。
MaterialCollectionの中を見ていただければわかるのではないかと思います。
今回はその結果をEmissiveに出力するのではなく、ベースパスでちゃんと法線を持ったオブジェクトとして描画してみようと思います。
まずマテリアルの Shading Model は Default Lit にします。Blend Mode は Masked にしましょう。まずはここから。
次に距離関数を設定したマテリアルファンクションとレイマーチング命令を内包したマテリアルファンクションを加算します。
加算した結果はあとで別の値に対して加算して、ちゃんとコード生成が行われるようにしましょう。
私が作成したレイマーチング用の関数はCustomノードで使用することを前提としており、1つの関数からワールド座標、ワールドノーマル、レイが衝突したかどうかのフラグを取得することが出来ます。
しかしCustomノードは1つのノードで出力可能な値は1つだけです。1つのCustomノードで3つの戻り値を返すことが出来ないのです。
なので同じ命令を実行し、出力する値をそれぞれ違うものを出力するようにします。
衝突したかどうかは [GetDistanceFieldMask] というCustomノードをチェックします。
このノードの出力は、衝突していたら 1.0 を、そうでなければ 0.0 を出力するように出来ています。
なのでそのままOpacity Maskに入力すればOKです。
Normal も基本的にそのままマテリアル入力に接続しますが、DistanceField関数を定義しているノードを有効化するためにそれらのノードとの加算を取ります。
また、接続するノーマルはワールド空間ノーマルなので、マテリアルパラメータの [Tangent Space Normal] はOFFにしておきましょう。
最後に座標ですが、実際に描画されているオブジェクトとDistance Fieldから深度方向のオフセットを求めます。
レイマーチングの計算で得られた座標と元のワールド座標をカメラ空間に変換し、その差をDepth Offsetに接続します。
あとはカラーを適当な値で出力すればOKです。
このマテリアルをアサインするメッシュは適当な板でOKです。
この板は常にカメラの目の前に置くようにすると、シーン全体でレイマーチングを行うようになります。
コリジョンはなしにしておいたほうが良いでしょう。
今回の手法はベースパスで処理されるため、ライティングもシャドウレシーブも行われます。
ただ、シャドウキャストはうまくいきません。シャドウキャストはOFFにしておくのが良いでしょう。
もちろん、実際に描画されている物体にコリジョンはありませんので、衝突させたくてもうまくいきません。
とまあ…正直なところ、使い物にならない技術かな、と思います。