#はじめに
2017年5月7日(月)・7日(火)・9日(水)に行われた Unite 2018 新機能Shader Graphを使えばプログラミング無しにシェーダーが作れるようになります! 講演の資料が動画しかなかったので複写する感じの記事になっています
タイムライン付き
#ShaderGraphとは
Unity 2018から使える新しいシェーダーの仕組み
いわゆるノードベースのシェーダーエディター
ノードとはグラフ上でボックスを配置し線で繋げて マテリアのデザインをする
リムライトの例 ライティングのエフェクトを強化する為にも使えます
#簡単な例 マルチテクスチャ
マルチテクスチャとは 3Dモデルに2枚のテクスチャを重ねるように貼り付ける
ちなみにデモでは樽のオブジェクトを使ってます
次にテクスチャを貼りたいので適当な空いてる場所で右クリック→CreateNode→検索でSampleTexture2Dを配置しTextureプロパティにテクスチャを配置する
RGBA(色情報)からドラッグ&ドロップすると線が出るのでマスターノードのAlbedoに繋げます
結果
補足として
処理の流れとして左から右に流れます
ノードの見方は基本 左が入力で右が出力です
ノーマルマップも貼れます
SampleTexture2Dを出して、Textureプロパティにテクスチャを追加、TypeをNormalに変更
そしてRGBA(色情報)をマスターノードのNormalに繋げる
マルチテクスチャなのでもう一枚テクスチャ作ってあげてブレンドして出力してあげる
SampleTexture2Dノードを出して、TextureプロパティにUnityロゴのテクスチャを指定して
Blendノードを出して、2つのSampleTexture2DノードとBlendノード繋げる
BlendノードにはいろんなBlendモードが用意されている
例えば「Lighten」を選ぶと明度が高い方を前に出すとゆう事ができる
BlendノードのOutからマスターノードのAlbedoを繋げると合成された状態で出力されます
このままだとUnityロゴがでかすぎるのでUVをリピートさせます
UVノード(UVをいじる時必要)を出して、Multiplyノード(掛け算)してあげればいいです その情報をSampleTexture2DノードのUVプロパティに流すと完成です
今までのUnityはレンダリング方式(「Forward」とか「Deferred」)切り替えるたびにシェーダーを変えないといけなかった
でもこれからはSRP(スクリタブルレンダーパイプライン)が登場します
SRPとはC#を使って描画設計を行う事ができるもの
Unityからは主に「Lightweught」と「HighDefinition」を提供します
今後レンダーパイプラインがいろいろ出てくると、それぞれのレンダーパイプラインに対してシェーダーを書き直すのは運用としては厳しいので、シェーダーグラフがあれば使いまわせところを目指しています。
#セットアップ手順
一番楽な方法はLightweight RPをインストールする
現在Shader Graphの開発はLightweight RP上で開発されている
Lightweight RPすれば勝手にShader Graphがインストールされる
Lightweight RPのインストール方法は大体2通り
Bの方がおすすめ
Bのやり方
プロジェクトを作成する画面でTemplate->Lightweight RP(Preview)を選択してあげてCreateProjectします
基本この状態でShader Graphは使えるようになっています
プロジェクトビューで右クリック→Create→Shader→PBR Graph、Sub Graph、Unlit Graphがシェーダーグラフのアセットです
例えばPBR Graphを選ぶとプロジェクトビューにシェーダーアセットが追加されます
で追加されたシェーダーアセットをダブルクリックするとShader Graphエディタ画面が立ち上がります
#シェーダーグラフの基礎
PBR GraphとUnlit Graphの違い
Sub Graphはマニアックな機能なので今回は説明しません
PBR Graphでちょっといじってみよう
ノードの新規作成は 右クリック→CreateNodeでできます
今回カラーを作ってAlbedoに突っ込むとゆうことやってみたいと思います
Input→Basic→ColorをクリックするとColorノードができます
Colorノードを赤に変えて、マスターノードのAlbedoに繋げる
新規でノード作る際 検索ボックスで直接名前を指定する方法があります
ほとんどのこの方法で作っていくと思います
次にまたColorノードを作って、青に変えて、マスターノードのEmissionに繋げると
発光している色が青色になりました
もう1パターン新規でノード作る事ができ、プロパティからクリックしながら線をひき何もないところで離すとCreateNodeのダイアログがでます
例えば、Emissionに繋がっていたColorノードと Multiplyノード(掛け算)してEmissionに繋げるとちょっと明るい状態で出ます
ノードがでかすぎて小さくしたい時は隠すボタンがある
1つ目 見た目の状態を隠す
↓変化後
作ったシェーダーを使う時はセーブする必要がある
セーブするとコンパイラが走りプロジェクト内で使えるようになる
マテリアルに設定する際は新規でマテリアルを作成して、graphs→NewShaderGraph(今作ってたシェーダの名前)を選択する
でゲーム中のオブジェクトにマテリアルを適応すれば完了です
もう一つ説明したいポイント
シェーダーグラフの値を引っ張り出してくる方法
グラフ内にプロパティブラックボードとゆうのがあるので
+ボタンを押すとプロパティの種類がでる 今回はColorを選択すると
そのプロパティをドラックアンドドロップでグラフ内にドロップすると実体化します
実体化したものは普通にノードとして使えるのでAlbedoに繋げて、セーブして、マテリアルのプロパティに「MainColor」とゆうプロパティが出るので、値をいじってオブジェクトの色が変われば完成です
#例1 ディゾルブエフェクト
ディゾルブエフェクトとは物体がシュワって消えていくのをAlphaCutoutを使って表現するエフェクトの事
AlphaCutoutとは
下記のアルファ値のグラデーションを与えられた時にCutoff値を設定すると、Cutoff値より低いアルファ値のピクセルの描画がキャンセルされるもの キャンセルした所はすり抜けて見える
例
↑みたいのを3Dでやってしまおうとゆうのがディゾルブエフェクト
アルファを抜くだけじゃなく Cutoff値よりちょっと高い領域を切り出して青く光らせる事によってキワの所を青く光らせる事が可能
さてShaderを組んでいきます
先にベースとなるテクスチャを設定していきます
・マスターノードのnormal,Oculusionを設定
・Albeboを白にします
ノイズのパターンを入れる
CreateNode->「noise」と検索->SimpleNoiseを選択
デフォルトだと細かいのでScale(30ぐらい)でモヤモヤっとした感じにしとく
SimpleNoiseをMasterノードのAlphaに繋げが見た目は特に変わらない(アルファ値が変わっただけなので)
AlphaCutoffの値を設定する
・CreateNode->「vector」と検索->vector 1を選択
・vector 1ノードをMasterノードのAlphaClipTresholdに繋げる
でvector 1ノードの値(AlphaCutoffの値)を適当に上げてあげると、はぬけの感じにエフェクトが出来ました
次にきわの部分を光らせようと思います
具体的はCutoffの値よりプラス0.05より低い全部のピクセル値を光らせるようにします
しきい値より上か下かを抜き出したいノード
Stepノードを使うといいです
実際にやってみる
・CreateNode->「step」と検索->stepを選択
・stepノードのEdgeにvector 1ノードの値(AlphaCutoffの値)を与える
・stepノードのinにSimpleNoiseを繋げる
でEdge値で高い領域、低い領域が二分化されます
でstepノードとMasterノードのEmissionに繋げると光るようになる
先ほどCutoff値+0.05とゆう話をしたので
・CreateNode->「add」と検索->addを選択
・addの値をBの値を0.05にする
・vector 1ノードの値(AlphaCutoffの値)をaddと繋げる
・addとStepのEdge値を繋げる
と きわの部分を除外する事ができた
ので反転してあげる必要がある
・色を反転してあげるノード「Invert Colors」をCreateNodeで追加
・Stepノード(出力)とInvert Colors(入力)を繋げる
・Invert Colorsの反転フラグを立てる
・Invert Colors(出力)とmasterノードのEmissionに繋げる
できわの部分が光るようになっています
徐々に完成に近づいてきました
次に自動(時間で)でアニメーションされるようにします
・ゲームが始まってからの時間を秒で返すノード「Time」をCreateNodeで追加
・小数点以下の値を取り出すノード「Fraction」をCreateNodeで追加
例えば
・vector 1ノードの値(AlphaCutoffの値)とaddと繋がっている線をきりFraction(出力)とadd(入力)を繋げる
・Fraction(出力)とMasterノードのAlphaClipTresholdと繋げる
と1秒ごとに切り替わるものが出来ました
あとは色を指定してあげるようにする
消えて聞く時に青白くするようにします
・プロパティブラックボードで「Color」プロパティを選択
・発光する感じを出したいのでModeをHDRにする
・輝度をちょっと明るめにしてちょっと青っぽくする
・「Color」プロパティをドラッグアンドドロップで実体化
・マスクのパターンに掛け合わせたので「Multiply」ノード(入力)に「Color」プロパティを繋げて、「Invert Colors」ノード(出力)を繋げてる
・「Multiply」ノード(出力)からMasterノードのEmissionを繋げる
#例2 エネルギーゲージ
直線的なものに関してスケールや移動などで簡単に実装したりするが
湾曲みたいな形状を実装すると結構難しい
ゲージにそったグラデーションのパターンを用意し、スレッショルドを変更するとゲージっぽい埋まっている状態や空の状態を作り出せる事ができる
これをシェーダーグラフのstepノードを使えば実装が出来ます
手軽なテクニックなのでオススメです
そのうえでゲージの枠を作ってあげて アルファブレンディングで合成して上げて
さて早速シェーダーグラフを使って作っていきましょう
今回はPBRグラフを使わないのでUnlitグラフを使います →ライティングを使わない為
プレビューはデフォルトのスフィアだと見にくいので「Quad」に変更 スプライト的な奴
MasterノードのSurfaceを透明化できる「Transparent」に変更 デフォルトだと不透明の「Opaque」になっています
SampleTexture2Dノードを作り、グラデーションのバーを読み込みます
SampleTexture2Dノード(グラデーションのバー)のRGBA値をマスターノードのColorに突っ込んで
SampleTexture2Dノード(グラデーションのバー)のA値をマスターノードのAlphaに突っ込むと
ゲージのグラデーション素材が読み込まれました
次にスレッショルドを使ってバーを動かす状態にしたいので
Stepノードを作って、SampleTexture2Dノード(グラデーションのバー)のRGBA値をStepノードのInに繋げる
Edgeの値を与えるためにVector1ノードを作ってStepノードのEdge値に繋げる
Vector1ノードの値を変更してあげると変更ができる ちょっと画像が化けているがちゃんとゲージが動いているはず
でこれで作った動きと元で作ったアルファ値を掛け合わせてColorの状態でマスターノードに出力してあげる
具体的なやり方 StepノードとSampleTexture2Dノード(グラデーションのバー)のA値をMultiplyノードで掛け合わせてMultiplyノードをマスターノードのRGB値に与えてあげると以下のようになる
ここで問題がVector1ノードが0の時に満タンになって1の時に空になってしまうので、本当は逆にしたいので、値を逆に変換します。
こうゆう時に使うノードがRemapノード
具体的な例
sin波の場合 −1から1の間を反復する感じになるので
−1から1の間を反復する感じじゃなくて0.3から0.7の間を反復させたい時にRemapノードを使ってください
組み込んでみたが不安が、よく見るとエッジの部分がジャギっている
その理由はStepノードは0と1の間はスパッと切れるので境目がギザギザしやすくなる
解決方法は簡単でSmoothStepノードを使う
文字通りStepノードがなめらになったノード
SmoothStepノードとはedge1とedge2の選択ができる
edge1より低い値は0を返して、edge2より高い値は1を返す
edge1とedge2の間は滑らかに繋いでくれる
で今回は入力値と入力値+0.05の間を滑らかにつなぐようにしてギザギザを目立たなくします
実際やってみましょう
Stepノードの代わりにSmoothStepノードを作ってRemapした値をSmoothStepノードのedge1に繋げる
SampleTexture2Dノード(グラデーションのバー)のRGBA値をSmoothStepノードのinに繋げる
SmoothStepノードのoutと、Stepノードと繋がっていたMultiplyノードを繋げる
Stepノードは消す
0.05プラスしたかったので
Addノードを作ってRemapノードのoutとAddノードのAに繋げて、Bの値を0.05にして、SmoothStepノードのedge2に繋げる
これでSmoothStepが適応された状態になりました
でほとんどゲージはできました。次は色をつけてみましょう
色のグラデーション素材を用意し、これを適応してみましょう
SampleTexture2Dノードを作って、色のグラデーション素材を参照して SampleTexture2DノードのUV値にVector1の値を入れてあげて 値を変更してあげると、1に近づくほど緑になって0に近ずくほど赤になるようになる
このSampleTexture2Dノードの値を掛け合わせたいので、Multiplyノード作ってSampleTexture2DノードとかけてSmoothStepノードに繋がっているMultiplyノードと掛け合わせると色の適用ができました。
次に枠を組み込みますのでアルファブレンディングをしたいと思います
シェーダーグラフでアルファブレンディングをしたいのであればLerpノードが一番簡単
実際に組み込むと
動画 文だとわかりずらいのでここの部分は動画を参照してください
プロパティブラックボードを使って、値をインスペクター上で操作できるようにしたいので、TypeをVector1にしてModeをスライダーにして0から1の間に設定する 設定したものをVector1と差し替える
とできましたが、1点バグがあります
値を1にして満タン状態にするとゲージが上がりきっていない
どうゆう状態かとゆうと、SmoothStepノードで上がりきらない領域ができちゃっている
#例3 古風なTVエフェクト
ノイズっぽいエフェクト よく画像の連番アニメーションや動画などで表現することがあるが、あまりパフォーマンスがよくないのであまりよろしくない
では実際にやってみましょう
・PBRグラフを作って、SampleTexture2Dノードを作りモナリザの画像を読み込んでくる
・SampleTexture2Dノード(モナリザ)をブラウン管テレビのように自己発光的な感じにしたいのでマスターノードのEmiisionに繋げる
・ちょっとテカってて見にくいのでalbedoの色を黒にします あと、マスターノードのSmoothnessを0にします テカリの要素を排除します
こういった簡単な形状のシマシマはテクスチャで作るのもいいがシェーダーでやった方が早い
シマシマを作るにはsineノードがいいのではないかと思います
sineと聞くと子難しい感じはしますが、要するには値が滑らかに上がったり下がったりするするだけです
実際にsineノード作って見ます
UV座標の高さを基準とするので UVノードを作り 縦軸のY軸を取り出してあげる必要がある
実際に使ってみると
・Splitノードを作り、UVノードの値をSplitノードに突っ込んであげる
・SplitノードのGの値をSineノードに突っ込む ちなみに表示ではGになっているが中身的にはY軸の意味です
・これを細かくしたいので、SplitノードのGの値のかけてあげます
・MultiplyノードをSplitノードのGの値とつなぎ Multiplyノードのoutからsineノードと繋げる
・Multiplyノードの掛けている値をあげてあげる
一応できましたですが、Sineには一点弱点がある
sine波は−1から1の範囲なので、 マイナスの値は色に悪影響与えるので
・これをSineノードの値からSaturateノードに突っ込む 見た目上は変わらないですが、将来のバグは防げました。
・SaturateノードとSample2DTextureノードと掛け合わせる(Multiplyノード)てマスターノードに繋げてあげるとモナリザの画像にシマシマが重なりました
・シマシマのせいで画像が暗くなったので無理やり明るくしましょう Multiplyノードで掛けてあげましょう
シマシマのUVアニメーションさせましょう
・Tmeノード作ってAddノードを作り、シマシマのUV値に足してあげます
・デフォルトだと鈍いので、Timeノードが出ている値をMultiplyで掛けてあげます
次は横にぶれるようなノイズを作って見ましょう 単純にU値にノイズをやってあげればいい
ではやって見ましょう
ちょっとここから 複雑で文章より動画を見た方が伝わると思いますので、
こちらの動画を参照してください
おさらいまで
#補足情報
今回使ったプロジェクト
https://github.com/keijiro/ShaderGraphExamples
シェーダーグラフはオープンソース開発されています
何か問題があったら連絡してもらえればと思います
https://github.com/Unity-Technologies/ShaderGraph
カスタムノードが作れることができる
参考ページ
https://blogs.unity3d.com/jp/2018/03/27/shader-graph-custom-node-api-using-the-code-function-node/
実際作って見たのがこれ
#今後の予定
HDRPの対応が早急の課題
頂点シェーダーも対応予定 近日中に実装される
バージョン管理
シェーダーグラフはjsonファイルなのでgitやsvnで管理でいけますが
差分をうまく拾える感じになっていないので、衝突の自動マージができないので、そこらへんは防止は運用でカバーお願いします。
以上終わりです
##今後の記事の更新
・もうちょい初心者でもわかりやすく補足とか入れたい
・AmplifyShaderEditorで例1〜3を作ってみた
・レイアウトも見やすくする