Shader Graphで波を作ろう。

Shader Graphを触ってみる

Negipoyoc

はじめに

Unity2018からの新機能、ShaderGraphで波を作ってみたので一連の作業の流れをまとめてみたいと思います。

何を作ったか

以下の物を作りました。

  • 見ている角度によって色が変わる(奥のほうは水色ですが、手前は深緑で海っぽさを出しています)
  • 複数のNormalMapの重ね合わせ
  • テクスチャの移動による水流の表現

これの作るにあたっての流れとか注意点とかをまとめていこうと思います。

※ちなみにShader Graphはまだプレビューという扱いなので、今後いろいろ変更になる可能性があります。

Shader Graphとは

ノードベースでプログラミングすることなくShaderを作ることができる機能です。

効果や変数などのノードを作ったあと、ドラッグアンドドロップでつなげることによってShaderを作ることができます。またいちいちビルドすることなくすぐにどういった効果になるかわかります。

現在はLightWeightRenderPipeline(LWRP)向けに作られています。

※LWRP=軽量レンダーパイプラインは、幅広いモバイルプラットフォーム向けの開発や、VR 向け開発、また限られたリアルタイムライティングで事足りるゲームの開発用に提供されているレンダーパイプラインです。

環境と準備

環境

  • Unity2018.1.3f1
  • Windows10
  • Shader Graph ver1.1.9 (Preview)

準備

現在のShader Graphは知識0の状態からの導入でつまづきがちです。理由はLWRP向けに作られておりその設定をしないとPackage Managerでインポートしてきただけでは正しく動作しないからです。

まず、以下の画像に赤枠で示されている「Shader Graph」「SRP(Scriptable Render Pipeline) Core」「Lightweight Render」をインポートします。

その後、以下のようにCreateからLightweight Assetを作ります。

作成できたら、Edit->Project Settings->GraphicsSettingsを開き、SRP Settingsに作成したScriptable Objectを割り当てたら準備完了です。 この割当をしていないとShaderGraphの編集画面上で正しくシェーダが描画されません。

作る

以下の画像が最初で見せた波のノードです。 (この画面に行くにはCreate->Shader->PBR GraphでShader Graphファイルを作成し、ダブルクリックします。)

左からノードをつないでいき、最終的に一番右のPBR Masterノードにまとめられ出力されています。

今回は、上の群が色を扱うノード群(フレネル効果も追加しています)、下の群がノーマルマップの割当や移動を作るノード群として作成しています。

1つずつ見ていこうと思います。

上のノードグループ

以降は左のノードから順に解説をしていきます。

フレネル効果で色に厚みを出す。

Normal Vector:
メッシュの頂点またはフラグメントのNormal Vectorへのアクセスを提供します。座標空間はSpaceのドロップダウンから選べます。(今回はWorldを使用)

Fresnel Effect:
フレネル効果。視点の角度によって、表面の反射を変化させるエフェクトです。(デフォルトではWorldSpaceの法線に従うので↑のNodeはいらなかったかも)
効果の強さもパラメータから変えられます。

これによって、見る角度によって色を変えるShaderが作れました。

色を追加する

色を追加する前に大事な話をします。

以降に頻繁に登場するPropertyというノードがあります。 これは、画像の左にある「Blackboard」というところで定義できるシェーダのプロパティから作られたノードです。

Blackboardに定義されたプロパティは、UnityEditorのInspectorのほうから値を変更できるようになります。


話を戻します。

Power:
AとBの積を得ます。
先程のフレネル効果のOutputをPowerNodeでDeepnessというプロパティでInspectorから変化できるようにします。

Lerp:
AとBをT(0~1)の割合で線形補間した値を返す。T=0.7なら(0.7*A+0.3*B)という値を返す。

ここではDeepColorに深緑を、SurfaceColorに水色を指定し、Deepnessプロパティの値を増加させることで深い色が出やすいようにするといったことができる。


ここまでやると大体こんなShaderができます。海の深みみたいなのはできたので、ここに対してNormal Mapなどを適用して波っぽくしていきます。

下のノードグループ

水流を表現する

Time:
時間経過を表します。

Multiply:
AとBの積を得ます。(PropertyにWaveSpeed係数を用意し、Inspectorからこの値を大きくすると水流が早くなるようにしています。)

Tiling And Offset:
テクスチャにおけるUV値やTiling、Offsetなどを調整するノードです。
OffsetにTimeをベースにした出力を割り当てることで流れを表現します。

※ここでTilingAndOffsetを上下2つに分けているのは、以降で2種のノードを指定し、それぞれのノーマルマップを混合することで簡単なノーマルマップから複雑な波を作り出すためです。
そのため、上のTilingは1を指定し、下のTilingは4をInspectorから指定し、普通のテクスチャと4倍細かくしたテクスチャの設定値を用意しています。(次章を参照)

ノーマルマップを混合する。

Sample Texture 2D: テクスチャを扱うノードです。それぞれのノードにある「UV」入力に対して、先程作成したそれぞれのテクスチャ設定を割り当てます。
テクスチャはPropertyから外部から指定できるようにし、今回は同一のテクスチャを割り当てています。

ちなみにこういった白黒のBumpMapをNormalMapにするにはテクスチャをUnityEditorに持ってきて、Texture TypeをNormalMapに、Create From GrayscaleをチェックしてApplyすればOKです。

Lerp: AとBをT(0~1)の割合で線形補間した値を返す。 これにより、任意の割合で2つのノーマルマップテクスチャが混合されるようにします。


↓の画像は下のノードで作られたものです。(実際は動きます。)

まとめる

以上で作られた2つのノード群を適当な入力に渡すことで完成です。
Materialを作り、ここで作ったShaderを割り当てて、PlaneにでもMaterialを貼り付けると動画で作ったようなものが見れます。

シェーダプログラミングの知識がなくても、かなり簡単に凝ったShaderが作れてしまうのはすごいですね。また、自分はノードベースのエディタは初めて触りましたが直感的でとても良いなと感じました。

最後に動画で見せたものについて、Inspectorで設定したプロパティの設定は大体こんな感じです。

おわりに

もちろん英語ですが、各Nodeの役割はこちらに全て書いてあるので、興味ある方はこちらからどうぞ。

https://github.com/Unity-Technologies/ShaderGraph/wiki/Node-Library