Unity 2022 LTS で Shader Graph を使用して自然環境のシェーダーを作る方法

TRACY CHEN / UNITYContributor
Jul 28, 2023|15 分
Unity 2022 LTS で Shader Graph を使用して自然環境のシェーダーを作る方法

このブログでは、2022 LTS でユニバーサルレンダーパイプライン(URP)を使用して、2 つの異なる自然環境のシェーダーを作成する方法をご紹介します。また、スタイライズされた水シェーダーとセミリアルな砂シェーダーの作り方もご紹介します。アセットは、新しい URP 3Dサンプル シーンとともにリリースされます。

これらのビジュアルエフェクトは一見複雑ですが、機能の背後にあるデザインベースの思考プロセスを深掘りし、エフェクトを実現させるテクニックをステップごとに詳しく説明していきます。シェーダー開発の複雑さを探求し、壮観な自然環境のシェーダーを作りましょう。

水のシェーダー

ここでの目標は、上の動画のように、日本庭園の中央を流れるスタイライズされた小川を作ることです。環境の他の部分に基づき、静かで禅のような雰囲気に仕上がっていて、写実的というよりはアニメーションの様なアートスタイルが採用されています。

このシーンに組み込まれた地形の影響で、ここには 2 種類の水があります。滝と、橋の下を流れる小川です。スタジオジブリが描く水のシーンはとても見事で、しばしば以下の 3 つの要素が含まれます。

目次水の流れを形作るフローライン

2.水が周囲の地形に作用されていることを示す端のハイライト

3.カスケードや滝をリアルに見せるための泡エフェクト

ここで作成する水シェーダーには、これらの要素がすべて含まれます。それでは、このようなビジュアルを実現する方法を詳しく見ていきましょう。

滝:泡と水しぶき

滝には 2 つの異なるメッシュがあります。メインの滝のメッシュと、波紋を生成する円盤状の平面です。波紋用に別の Unlit シェーダーを用いると、ノイズノードをタイル状に並べ、それをシェーダーのアルファ値として使うことができます。こうすることで残りの領域がマスクされ、波紋が意図した場所に現れるようになります。

波紋を生成するための主要な滝メッシュと円盤型の平面への分解

一番重要なのは、メッシュの各領域が異なる動作を行えるようにすることです。これは、メッシュの頂点色を赤(R)、緑(G)、青(B)のチャンネルであらかじめペイントすることで実現できます。頂点色はその後マスクとして、特定の領域で演算を分離するために使われます。

Shader Graph で、Vertex Color ノードを使用してペイント済みの頂点色データにアクセスします。下の画像の右側にあるように、頂点色の赤チャンネルを T 値として使用し、滝の垂直部分と水平部分の間を補間(Lerp)することで、滑らかな遷移を実現できます。水が滝のように流れる効果を作るには、2 つの Voronoi ノードを、それぞれ異なるタイリングとオフセットで組み合わせます。こうすることで、滝の動的なビジュアルを生み出すことができます。

Shader Graph の頂点カラーノードの分割ビュー。赤(R)チャンネルの頂点カラーを表示している。

実際の滝では、水が上の水平面から流れ落ちる部分と、水が下の水平面に当たる部分は、泡や水しぶきの層が厚くなっていることがよくあります。このシーンでは、青チャンネルで頂点色をあらかじめペイントしておくことで、エフェクトが特定の領域だけに表示されるようにすることができます。頂点色マスクを使うと、最大 4 つの異なるエフェクトを 1 つのデータにまとめることができます。この手法は、エフェクトごとに別々のグレースケールマスクテクスチャを作成するよりも効率的です。

端から落ちる水の層が幾重にも重なっているように見せるには、スケールとスピードの異なるノイズノードを使用します。スケールが大きいノイズノードを遅いスピードでスクロールさせ、スケールが小さいノイズノードを速いスピードでスクロールさせることで、このような効果を生み出すことができます。滝の水平部分との一貫性を保つためには、小川の水のデータを再利用しましょう。小川の水については、これから詳しく説明します。

Shader Graph の頂点カラーノードの分割ビュー。青(B)チャンネルの頂点カラーを表示している。
小川:反射、端の泡、水のトレイル

これで落ち着いた雰囲気の滝が完成しました。次は小川を作成しましょう。アニメーションスタイルの水には、よく見られる重要な特徴がいくつかあります。現実の岸辺に現れる泡に規則性はありませんが、ジブリスタイルの小川の場合、岸辺付近に非常に薄い泡があることが多いです。また、 水が尾を引く様子を見せることで、水が動的で生き生きとした印象になります。このシーンは夜の場面を再現しているので、説得力のある反射効果も必要です。どうすれば Shader Graph でこれらの効果を生み出せるのか、詳しく見ていきましょう。

リフレクション

水面の反射を再現する方法はいくつかあります。最も効率的な選択肢は、URP に組み込まれている GlossyEnvironmentReflection 関数を呼び出す Custom Function ノードです。この関数は、シーン内のボックス投影反射プローブからサンプリングされた反射色を表示します。関数が必要とするワールド空間の位置、ビュー方向、法線、画面の位置を渡すだけで完成です。

エディター内の Reflection ノード設定の分割ビューと、完成した庭のシーンの水シェーダーによる反射

より高いビジュアルクオリティやリアルな反射が必要な場合は、URP の平面反射を使うと良いでしょう。平面反射は、平面を鏡のように反射させるもので、平面構造が平らな水面のメッシュに最適です。

平面反射を実現するには、反射データを保存するため、別のカメラおよびレンダーテクスチャを設定する必要があります。基本的なコンセプトは、反射面(この場合はシーン内の小川)の下に反射カメラを設置し、それをプレイヤーカメラの位置と方向に基づいて更新するというものです。レンダーテクスチャもリアルタイムで更新されます。

利点のひとつとして、リフレクションカメラのニアクリップ面を反射面そのものとして設定できることが挙げられます。これにより、反射面より下に位置するオブジェクトをクリップアウトする必要がなくなり、実装プロセスが簡素化されます。Shader Graph でテクスチャプロパティを作成し、スクリプトで以前に作成したレンダーテクスチャをそのプロパティに割り当てます。

レンダーテクスチャを正常にリンクさせるには、シェーダープロパティを設定する際、設定するプロパティが Shader Graph で作成したテクスチャプロパティの参照 ID と一致していることを確認してください。また、レンダーテクスチャを更新する際に、スクリプトが正確なプロパティ ID を呼び出していることを確認してください。その後、スクリーン位置を UV としてテクスチャをサンプリングします。これで、シェーダーで平面反射を作り出すことができました。

平面反射のサンプルシーン

平面反射の実装には、いくつかの技術的な考慮や詳細が必要になります。より詳しい説明や実装例については、こちらの URP サンプルをご覧ください。なお、平面反射はオブジェクトを 2 回レンダリングするため、リフレクションプローブを使うよりも計算コストがかかる点にご注意ください。

端のエフェクト

端の泡のエフェクトを実装するためには、深度の違いを計算する必要があります。Scene Depth ノードLinear01 オプションは、不透明なオブジェクトに対して 0 から 1 にスケールされたリニア深度値を返します。この値にカメラファークリップ距離を乗算することで、カメラから不透明なオブジェクト(この場合は岩)までの距離を求めることができます。Screen Position ノードRaw オプションの z 成分から、視点空間深度がわかります。これにより、透明な水面と不透明な岩の間の深度差を簡単に計算でき、計算した深度値を Emission の出力値として渡すことで、泡のような効果を作り出すことができます。

エディター内で深度値を計算する場合とシーン内の結果を比較した分割ビュー

シーンから深度値を取得するには、プロジェクト設定で Depth Texture を有効にしてください。Depth Texture オプションは、レンダーパイプラインアセットの General セクションから有効化できます。現在のレンダーパイプラインアセットには、Edit > Project Setting > Graphics > Render Pipeline Asset からアクセスできます。

Unity エディターの Universal Render Pipeline Asset ウィンドウの表示。深度テクスチャオプションを見つける方法を示している。
流線

小川の水の動きを示すトレイルは簡単に作ることができます。2 つの Voronoi ノードをタイリングしてオフセットし、頂点色を使って任意の領域をマスクすることで、水面に沿って流れるスタイライズされた水のトレイルを作成できます。次に、ノイズノードのスピードを、先に作成した滝に合わせて調整します。これで、水面を流れるスタイライズされた水のトレイルが完成しました。これは、滝の流線を作るのに使われたテクニックとよく似ています。

エディター内の Voronoi ノードを使用したフローインジケーターの分割ビューとシーン内の結果
砂シェーダー
シェーダーグラフのナチュラルシェーダーを使用して作成された完成版の砂のシーンの例

今度は趣向を変えて、あまりスタイライズされていない、よりリアルなシェーダーを見てみましょう。この砂シェーダーはリアルな砂漠のシーンで使われているため、実際の砂に近いビジュアルでなくてはなりません。

砂のレンダリングは興味深い挑戦です。普通の PBR シェーダーでは、強い日差しの下にある砂漠の砂は表現できません。砂シェーダーには 2 つの主な特徴があります。繊細ながらも注目すべき砂の輝きと、躍動感をもたらす動的な砂埃です。

砂は無数の小さな粒からできているため、日光に当たるとキラキラと輝きます。この輝きは、どのように再現すればよいでしょうか。鏡面反射のやり方と同様に、まずサーフェス法線を使用して反射ベクトルを計算します。『Journey』からヒントを得て、法線ベクトルと中間ベクトルの内積を計算する代わりに、法線とビュー方向の内積を計算します。この調整により、見る角度によって輝きのパターンが変化し、シェーダーの視覚的魅力が高まります。

シェーダーには 2 つのノイズマップがあります。1 つは輝きのサンプリングに使用し、もう 1 つは、メインのノイズテクスチャをマスクアウトして、より動的で目を引く仕上がりにするために使用します。先に計算したリフレクションベクトルを使用し、ノイズマスクのサンプリングに使用する UV を歪ませます。

エディター内のノイズマップとシーン内の結果の分割ビュー。砂の輝き効果を示している。

砂埃のエフェクトは、動く砂のトレイルと砂の波の 2 つの要素を組み合わせたものです。コンセプトはいたって単純です。望む効果を得るために、異なる法線マップをタイリングするのです。砂のトレイルで重要なのは、法線マップをマスクアウトして効果をより動的に見せるためのマスクが必要だということです。デフォルトの UV を使用する代わりに、絶対ワールド位置で 2 つのノイズマップをサンプリングします。

注意すべき点としては、レンダーパイプラインの設定によって、Position ノードの World オプションが変わることが挙げられます。そのため、パイプラインを切り替えたときの動作の変化を避けるために、Absolute World オプションを選択してください。次に、2 つのマップを斜め方向に並べ、波紋のような効果を生み出します。その後、砂の波の方向に沿って別のノイズマップをスクロールさせ、砂が離れていく効果を作り出します。

エディター内の Position ノード内で Absolute World オプションを選択する方法と、吹き飛ばされるほこりの効果を示すシーン内の結果の分割ビュー

重要な点は、シェーダーでどのように法線ブレンドを実現させるかです。砂の地形では、アルベドマップが他の地形に比べてそれほど複雑でないため、法線は見た目に大きく影響します。シェーダー内で複数の法線マップをブレンドしてください。アルベドマップのブレンドとは異なり、法線マップは方向を保存しているため、ブレンド方法を変えると結果も大きく異なります。

例として、Shader Graph の Normal Blend ノードを見てみましょう。法線マップ A と法線マップ B をブレンドするとき、Normal Blend ノードのデフォルトオプションは、2 つのマップの x チャンネルと y チャンネルを加算し、z チャンネルを乗算してブレンド法線の 3 つ目の要素を得ます。再配向オプションは、その名の通り、より複雑なプロセスを伴います。このオプションでは、マップ B の法線がマップ A の方向に合わせるように回転されます。この手法を用いると両方のマップから最も多くのデータを保持できる一方、最も計算コストがかかるオプションでもあります。

Shader Graph の Normal Blend モードのブレンド比較の 3 方向表示 - シーン内の再方向付け、デフォルト、メソッド

ここでは、法線をブレンドするという単純な手法を採用しました。法線をブレンドする主な理由は、砂漠の表面を砂が吹き飛んだり動いたりしている感覚を鮮やかに再現するためです。正確さは最優先事項ではありません。さらに、シェーダーは比較的大きな地形メッシュに適用されているため、計算コストを最小限に抑えることも重要です。

これらの要素を考慮し、ここでは分かりやすいアプローチを紹介します。法線マップの赤と緑のチャンネルを足し合わせ、青のチャンネルには値 1 を渡します。そして、法線の強度を少し上げると、素晴らしい結果が生まれます。

Unity サンプルの完成版の砂のシーンの分割ビューをエディター内の設定と比較すると、より大きな法線強度でのアプローチが示されています。

上記で説明した機能に加え、シェーダーには他のコントロールも実装されています。そのひとつが一般的なフェードコントロールで、これはカメラの距離に応じて地形上のどこにエフェクトが現れるかを決定します。これにより、カメラが遠ざかるにつれてエフェクトが徐々に変化し、フェードアウトしていきます。

また、遠景の滑らかさの値を調整することで、砂丘と背景の地形をより適切にブレンドできます。ユーザーがズームインすると、地形の法線は詳細な粒状の法線マップに切り替わります。これにより、砂の表面に細かなディテールやテクスチャが加わり、よりリアルな砂漠を再現することができます。

さて、これら 2 つのシェーダーのそれぞれの機能を一通り学んだので、次は自分のバージョンを作ってみましょう。Shader Graphを使ったシェーダーの作成に強い関心がある場合は、フォーラムまたは Discord にご参加ください。Tech from the Trenches シリーズで、Unity 開発者による今後の技術解説もぜひ引き続きチェックしてください。