【Unity】初めて『シェーダーグラフ』でシェーダーを学んでみる 基礎編.⑩
こんにちは。
シェーダーを一度も触った事のないデザイナーが、Unityの「シェーダーグラフ」を使ってシェーダーを学んでみるシリーズ。
このシリーズでは、公式のサンプルシーンを元に僕がシェーダーグラフで学んだ事を解説していきます。
シェーダー学習初という事もあり、たくさんの方のブログを拝見し、勉強させていただきました。
このシリーズには僕が参考にさせていただいたブログのリンクを貼らせていただいておりますので、そちらも併せて読んでいただくとより一層理解が深まるかと思います。
今回は「基礎編.⑩」という事で、公式のサンプルシーンにある上の画像の左右に移動する図形がどのように作られているかを解説します。
今回のシェーダーは、僕が初めてシェーダーを開いて見たとき「何じゃこりゃっ!全然分からん!」と、一瞬シェーダー学習を挫折しようかと思ってしまうくらいそれぞれのノードが何をしているのかさっぱり分かりませんでした。
Sineとか数学的なノードも出てきましたし・・・。
ただ、一つ一つのノードの役割を調べて作りを紐解いていくと、「こういうことか!」と理解する事ができました。
僕のように「難しい!」と思ってしまう方もいるかもしれませんが、一つ一つ丁寧に解説していこうと思いますので、ぜひ、ひるまずに読み進めていただきたいなと思います。
ではいつもの流れで解説を始めます。
まずはこちらの記事で紹介したサンプルシーン「Shader Graph Example Library」を開いてください。
シーンは開けましたか?
それではシェーダーの解説に入ります。
シェーダーを開く
サンプルのシーンを開いたら、「Procedural-UV-OffsetPingPong」というファイルをダブルクリックして下さい。
するとシェーダーグラフのエディターが立ち上がります。
※Propertyにコンバートされていたノードは「Convert To Inline Node」で元に戻してあります。
全体の流れ
個々のノードを見ていく前に、このシェーダーが何をしているのか、全体の流れを軽く把握していきましょう。
このシェーダーは、①②でアニメーションの速度を指定、③④で速度に対するアニメーションの動き具合を指定、⑤⑥でアニメーションの幅(最小値と最大値)を指定、⑦でそれらを合成し、アニメーションするUVオフセット用の値を出力しています。
そのオフセット用の値を受け取ったPolygonノードがアニメーションする図形を作成し、最後にColorノードから出力された緑カラーをMultiplyノードで乗算して、下記の絵が完成します。
重要ノードの解説
さて、全体の流れを把握した所で、今回のシェーダーで重要な役割を持つノードを詳しく見ていきましょう。
① Time
このノードは、シェーダー内でアニメーションをさせるのに必要なノードになります。
5つのポートがありますが、各ポートの説明は下記のサイトを参考にしてください。
今回の「Time」というポートは、シェーダーコードでは「_Time.y」を表します。
「_Time」は時間の流れる速度を表します。
ここでは余談ですが、「_Time」というコードには「_Time.y」を含め4種類あるようです。
※このノードでは「_Time.y」しか使用できません。
- _Time.x : 1/20 秒
- _Time.y : 1 秒
- _Time.z : 2 秒
- _Time.w : 3 秒
この種類に関しては下記のサイトを参考にさせていただきました。
- UnityのShaderのことはじめ_#001_Shaderの種類、Shaderでアニメーションを作る! - グラフィックスとか数学…etc
- Unity シェーダーチュートリアル 滝を作ってみる – Tsumiki Tech Times|積木製作
という事で、今回このノードから出力される値は1秒(等倍速)という事になります。
② Multiply
このノードでは、①Timeから出力された値を、B入力に繋いだVector値で乗算しています。
Vectorの値を2、3と変えていくと、最終結果の図形が移動する速度が速くなると思います。
これは、①Timeで出力された時間の流れる速度「1」に対して乗算しているので、2倍速、3倍速という感じになるからです。
マテリアルから倍速の値を調整するためにここで乗算しているんですね。
マテリアルから調整する必要がない場合はこのMultiplyノードは必要なく、①Timeノードを直接③Sineノードに繋いでしまうのも有りです。
③ Sine
ここでは、②Multiplyノードから送られてきた時間に対して、どのような値の変化を与えるかを決めています。
このノードは、三角関数の「サイン、コサイン、タンジェント」のサインです。
このノードが計算する値の変化はサインカーブで表され、時間の経過に対して下図のように値が変化していきます。
このようにサインカーブは、時間の経過に合わせて「-1~1」の範囲を繰り返します。
ちなみにシェーダーグラフにはCosineノードもあり、コサインカーブはサインカーブと比較すると下図のようになります。
得たいアニメーションに合わせてどちらを使うか選ぶと良いかと思います。
三角関数については下記のサイトを参考にさせていただきました。
- [連載]やってみれば超簡単! WebGL と GLSL で始める、はじめてのシェーダコーディング(3) - Qiita
- 数学も道具の1つと考え、慣れ親しもう>>CGデザイナーのための数学講座 | 記事を読む | CGWORLD Entry.jp
- sin cos 2 ( CG Mathematics - AD05 )
- 4.2 三角関数 | Yasushi Noguchi Class
- 【数学】 sine curveを正確に書く 【三角関数】 - YouTube
④ Remap
このノードでは、③Sineノードから受け取った値を「Out Min Max」で指定した値に変換しています。
③Sineノードでは「-1~1」の範囲でアニメーションしますが、これを「0~1」の範囲でアニメーションするように変換しているのです。
例えば、下図のように「In Min Max」と「Out Min Max」の値が同じであれば、計算結果に変化はありません。
X:-1の値を受け取った時にX:-1の値に変換、Y:1の値を受けとった時にY:1の値に変換という計算をするのでこのようになります。
今回のシェーダーの場合だと、X:-1の値を受け取った時にX:0の値に変換、Y:1の値を受けとった時にY:1の値に変換という計算を行います。
サインカーブのままだと最小-1の値まで変化していたので画面が黒い時間が長いですが(0以下は黒のため)、Remapで最小0の値に変換されたので黒くなってもすぐ白に変化し始めますね。
カーブで見るとこのように変換されています。
このRemapノードは、Sineノードだけでなく、いろんなノードから受け取った値を別の値に変換できますので、利用する機会は多そうです。
⑤ Negate
このノードは、受け取った値を+と-を反転して出力します。
例えばVectorノードで-1をつなぐと+1の値になりますし、Vectorの値を+1にすると-1の値になります。
このシェーダーでは+0.5の値を受け取っているので、このNegateノードは-0.5の値を出力しています。
⑥ Lerp
このノードは、A入力値を最小値、B入力値を最大値として、T入力値0~1の範囲で値を線形補完するノードです。
このシェーダーでは、A入力値が-0.5、B入力値が0.5、T入力値が0~1の範囲でのアニメーションとなっています。
この場合、Tが0の時は-0.5、Tが1の時は0.5の値が出力される事になります。
線形補完とは2つの値の間を等速で移動する補完の事で、今回の値の変異をグラフにすると下図のように直線になります。
ちなみにTに入力された値は強制的に0~1の範囲にクランプ(まるめこむみたいな意味)されます。
例えば-2~3の値が入力されていたとしても、その範囲をまるっと0~1にクランプされます。
Lerpノードについて参考にさせていただいたサイトはこちらになります。
⑦ Combine
このノードは、R,G,B,Aの4つの入力値を合成し、新しい値を出力します。
新しい値というのは、入力チャンネルRGBAのRGを合成したVector2、RGBを合成したVector3、RGBAを合成したVector4の3種類となります。
このシェーダーでは⑥Lerpノードから出力された-0.5~0.5の値をRチャンネルに入力してるので、Xの値が時間に応じて-0.5~0.5に変化するVector2が出力されているという事になります。
ここで出力された値が次のTiling And OffsetでUVのオフセットに使われているため、時間に応じてUVのUが-0.5~0.5オフセットするような動きになっています。
試しにGの値を0.5にしてみると、UVのVが0.5オフセットされるため最終結果の図形が表示領域の下に移動し、半分見切れる形になります。
完成!
これで今回のシェーダーは完成です!
まとめ
今回は、アニメーションが入った事により前回までよりもグンッと難しい内容になっています。
ただ、ここまで読み終わった方はなんとなくでも仕組みが理解できたのではないかと思っています。
全然分からなかった僕がこの記事を書き上げたら理解できていたので・・・、たぶん・・・。
もし分からないところがあったら遠慮なくコメント欄にご質問下さい。
さて、今回新しく覚えるべきノードは6つです。
- Timeでアニメーションを使う準備!
- Sineでサインカーブを使用!
- Remapで値を置き換える!
- Negateで+-を反転!
- Lerpで線形補完!
- Combineで値を合成!
この6つを覚えたら次へ進みましょう!