【シェーダーグラフメモ その55】ボロノイを利用した、水中コースティクス表現
はじめに
ShaderGraphで水中コースティクス表現を作る方法を紹介します。
水中コースティクスが発生する仕組み
まず最初に、水中コースティクスの発生原理を簡単に紹介します。
水の外からやってきた光が水底にぶつかると、そこにコースティクスが生まれます。
光が水面のどこを通ったかが分かればコースティクスを描画できますが、
光がどこを通ってきたかは未知の情報です。
コースティクスの描画方法 (Backward Ray Tracing)
今回はBackward Ray Tracingと呼ばれる手法でコースティクスを描画したいと思います。
描画したい水底の各点から、光とは逆方向にRayを飛ばします。
Rayが水面にぶつかる位置をコースティクスのテクスチャ座標として利用して、
コースティクスを描画します。
※水へ入射する光はスネルの法則などを利用して屈折させるのが正しいですが、
今回そこは重要ではないので処理を省きます。
水面のコースティクス座標の計算
今回は計算を簡単にするため、水面は平面として扱います。
Rayが進む距離dの計算
初めに、水底にある点から出たRayが水面にぶつかるまでの距離dを計算します。
距離dは、高低差h、Rayの向きL から算出できます。
Rayの向きLは、射し込む光と真逆にします。
Rayが水面にぶつかる座標Cの計算
距離dやRay向きLなどを利用して、水面コースティクスの座標Cを計算します。
点CのXZ座標をUV座標として利用することで、水底に投影されたコースティクスが描画されます。
以上でコースティクスの実装方法の解説は終わりです。
ShaderGraphによる実装
次に、ShaderGraphで水中コースティクスを実装します。
ShaderGraph全体は以下のようになります。
Rayが進む距離の計算
左下の箇所では、Rayが進む距離dを計算しています。
水面コースティクスの位置の計算
その右上では水面のコースティクスの座標を計算しています。
ボロノイの描画
求めた点Cのxz座標をUVとして、ボロノイを描画します。(Voronoiノード)
これにより、水底に投影されるボロノイが取得できます。
最後に、Lerpを使ってボロノイに色を付けます。
以上でシェーダーグラフの実装は完了です。
シェーダーパラメータ
プロパティ名 | 説明 |
---|---|
Light (_Light) |
光の向きベクトル
|
WaterLevel |
水面の高さ(Y座標)
|
CausticsScale |
コースティクスの大きさ調整用パラメータ
|
WaterColor |
コースティクス無しの水の色
|
LightColor |
光の色(コースティクスの色)
|
LightIntensity |
光の強度(コースティクスの強度)
|
VoronoiPower |
ボロノイの鋭さ(Powerノードの指数部分に使用する数値
|
シェーダー内の光の向き(Light)の同期
シーンに配置されたライトの向きをシェーダーのLightと同期させるロジックをC#スクリプトで書きます。
コースティクスを描画するMeshRenderが付いたGameObjectへ、以下のコンポーネントをアタッチします。
using UnityEngine;
public class MaterialSyncLight : MonoBehaviour
{
// シェーダープロパティ _Light にアクセスするためのShaderID
private readonly int shaderId_Light = Shader.PropertyToID("_Light");
[SerializeField] private Light targetLight = null;
private Material _material = null;
void Start()
{
var meshRenderer = GetComponent<MeshRenderer>();
if (meshRenderer != null)
{
_material = meshRenderer.material;
}
}
void Update()
{
if (_material != null)
{
_material.SetVector(shaderId_Light, targetLight.transform.forward);
}
}
}
Material Sync LightコンポーネントのTarget Lightには、シーン内のライト(DirectionalLight)を持たせておきます。
ゲームを再生すると、ライトの向きとコースティクスが同期します。
参考リンク
コースティクスの描画は下記リンクを参考にしました(英語)