Open38

読者コミュニティ|Unity ShaderGraph CookBook vol.1

aitaraiaitarai

ツイッターでもいつも勉強させて頂いています。
本の内容を見ながらノードベースでシェーダーの基礎を学び、現在はプログラムでシェーダーを書く勉強をしています(ありがとうございます)。

質問なのですが、
本のツイートにリプライされていたこちらの液体を、シェーダーで再現しようと奮闘中です。
オブジェクトの動きに応じて、動的に変化するところに魅力を感じています。
https://twitter.com/rn49rn49/status/1378726693309882373

考え方は「3Dオブジェクトの中に液体が入っているような感じにするシェーダーグラフ」の応用で、
csファイルでサイン波を制御しているのかな?と思っているのですが、
書き方がわからず、スクリプトをどこかで解説して頂けると嬉しいです。

気が向いた時によろしくお願いします!(質問が直接関係のない内容で申し訳ありません)

かもそばかもそば

ShaderGraphでサイン波を表示させつつ、サイン波の振幅をCSスクリプトで変化させることで液体っぽく見せています。`

サンプル

サンプルデータをGitHubにアップしましたので、ご覧ください

Assets/_SampleData/ShaderSamples/13_Liquid

https://github.com/rngtm/ShaderGraphCookBookSample/

実装(C#スクリプト)

CSスクリプトの実装は以下のような感じです。

Liquid.cs
using UnityEngine;

public class Liquid : MonoBehaviour
{
    [SerializeField] float maxWaveSize = 0.3f; // 波の高さ
    [SerializeField] float k = 1f; // 数値を増やすほど波が速く減衰
    [SerializeField] float waveSize = 0f;
    [SerializeField] float waveSpeed = 0f;
    [SerializeField] Vector3 waveDirection = new Vector3(1f, 0f, 0f); // 波の方向
    [SerializeField] float waveSizeInfluenceByMove = 0.001f; // 移動が波の高さに与える影響
    [SerializeField] float waveDirectionInfluenceByMove = 10f; // 移動が波の向きに与える影響
    MeshRenderer meshRenderer;
    Material material;
    Vector3 position;
    Vector3 previousPosition;

    void Start()
    {
        meshRenderer = GetComponent<MeshRenderer>();
        material = meshRenderer.material;
    }

    void Update()
    {
        previousPosition = position;
        position = transform.position;

        float dt = Time.deltaTime;
        Vector3 diff = position - previousPosition;

        // 波の高さの更新
        waveSize += waveSizeInfluenceByMove * diff.magnitude / dt;
        if (waveSize > maxWaveSize) waveSize = maxWaveSize;

        // 波の速度の更新
        waveSpeed = -waveSize * k;
        waveSize += waveSpeed * dt;

        // 波の向きの更新
        if (position != previousPosition)
        {
            diff.y = 0f;
            waveDirection = Vector3.Lerp(waveDirection, diff.normalized, waveDirectionInfluenceByMove * Time.deltaTime).normalized;
            material.SetVector("_WaveDirection", waveDirection);
        }

        material.SetFloat("_WaveSize", waveSize);
    }
}

ShaderGraph

aitaraiaitarai

波の高さの更新の計算が難しい…
頑張って自分の中に落とし込みます…!ありがとうございます!

aitaraiaitarai

シェーダーについて追加で質問失礼します。
①オブジェクトのローカル座標と、任意ベクトル(WaveDirection)の内積を取る
②TAUと①を掛ける
③ ②で計算したものをサインに使う(時間を引く)

この一連の計算についてですが、
①で内積のBに入力している部分は Normalize しなくても大丈夫なのでしょうか?
②でTAU を掛ける理由があれば知りたいです。

※今朝まで違う質問を投げていたのですが、解決したため内容を変更させて頂きました。

かもそばかもそば

座標をNormalizeしない理由について

①で内積のBに入力している部分は Normalize しなくても大丈夫なのでしょうか?

まず内積について説明すると、
ローカル座標の点とベクトルWaveDirectionの内積は、点をWaveDirectionへ射影した長さになります。(ベクトルの長さが1の場合)

この長さをSineで利用することで、WaveDirectionの方向へ進むSine波を作ることができます。

関連 : 🍇 内積・外積を使ったグラデーション

Normalizeを入れてしまうと、内積結果xはPの長さ(原点からPまでの距離)と無関係な値になるので波が作れなくなってしまいます。

数学的な説明

数学的に説明すると、座標 P と 長さ1のベクトル D の内積は以下のようになります。
P \cdot D = |P| \cdot cos \theta
|P| : Pの長さ
\theta : PDがなす角 (ラジアン)

内積は、以下の図の直角三角形の底辺の長さに一致しています。

座標にNormalizeを適用するということは、座標Pの長さを1にするということですので、

P \cdot D = cos \theta

になってしまいます。(内積結果は、Pの長さとは無関係になってしまいます)

TAUを乗算する理由

②でTAU を掛ける理由があれば知りたいです。

TAUについて補足すると、TAUは 2 \pi という数値を取れるノードです。


sin(x)はxが2 \pi増えるごとに1回の波を描くのですが、これは扱いづらいのでxに2 \pi を乗算しています。
sin(2 \pi x)はxが1増えるごとに1回の波を描きます。

関連 : 【ShaderGraph】ベジェ曲線を波打たせてみる

aitaraiaitarai

図付きで大変分かりやすい説明をありがとうございます!
座標の点とベクトルの内積の理解が曖昧でしたが、今回の件でよく分かりました!本書の知識の応用だったんですね。後者についても同様です… 数学的な理解が深まりました!ありがとうございます。

BloodBlood

ShadeGraphの本を購入し楽しみながらChapter1から勉強中なのですがChapter28,29で詰まってしまったため何か解決策を知っているのであれば教えてもらいたいです。

サンプルプロジェクトではCanvasの設定をScreenSpace - OverRayにしていても動作しているのですが、自分で新しく作ったプロジェクトではScreenSpace - OverRayだと動作しません。

Unity 2020.2.6f1
URP 10.3.2
ShaderGraph 10.3.2

やったこと:
Unityのバージョン変更
→動作せず
URP,ShaderGraphのバージョンアップ
→動作せず
サンプルプロジェクトから自分のプロジェクトにShaderを移植
→動作せず

https://twitter.com/bloody_sweets/status/1449789256134578180?s=20

よろしくお願いします。

かもそばかもそば

ShaderGraphは機能しているように見えますが、Imageがつぶれているように見えました。
ImageやRawImageのRectTransformを以下のように設定して、実行したときにどうなるかを見てみたいです。

BloodBlood

画質は荒いですがこんな感じです。
Materialは本の集中線の自分で作ったものを適用してます。

ちなみにサンプルのConcentrationLine Shaderから作ったMaterialを適用すると以下のエラーが出ます。

かもそばかもそば

ShaderGraphは機能していると思うので、
・ノードのつなぎ方が違う
・ノードのパラメータが違う
などが考えられると思います。

以下のようにノードをつなげば、集中線が出せると思います。

BloodBlood

すみませんどうしてもできませんでした...
もしよろしければプロジェクトデータを送るので試してもらうことは可能ですか?
ご迷惑をお掛けしてすみません。

かもそばかもそば

大丈夫です。
Unityプロジェクトのリンクなどを送っていただければ、時間が空いたときに見てみたいと思います。

かもそばかもそば

修正してみました。

行った作業

  1. Vertex Color を マスターノードのBase Color につなぐ (ImageのColorは黒にする)

  2. Angle Scale を 1 から 10 に変更する

BloodBlood

これ再生したときは問題なく表示されましたか?
自分の方で修正後再生してもやはり表示されなかったのですが...

かもそばかもそば

どうやらCanvasのRender Mode が Screen Space - Overlay だと、
ゲーム再生時に ShaderGraphがついたUIが表示されなくなるみたいですね。
(Unityのバグだと思います)

Canvasを Screen Space - Camera にして、
マテリアルのRender QueueをTransparent(3000)に設定したら
UIが表示されました。

集中線が表示されるようにしたUnityプロジェクトをお渡しします。
https://xgf.nu/mhSd

BloodBlood

本当にありがとうございます。
助かりました。

発酵大豆発酵大豆
かもそばかもそば

@ 発酵大豆さん
ご報告ありがとうございます。
修正させていただきました。

修正前

出力 = \begin{cases} 1 & (In \leq Edge) \\ 0 & (In > Edge) \end{cases}

修正後

出力 = \begin{cases} 1 & (Edge \leq In) \\ 0 & (Edge > In) \end{cases}
9812398123

Hey!
In the Chapter 15 "Absolute node" you mention electrical pattern (ノイズから電気パターンを作る). Is it shown anywhere? I can't figure out how to use it this way.
Thanks!

9812398123

In chapter 27 (🍍 3Dスキャンライン表現) shouldn't we use Position in "Object" mode? Leaving it in "World" will make the scan line move when we move the object (in "Object" the line keeps moving at the same height but in "world" when we move the object UP the line will slide down repeating).

かもそばかもそば

Thank you for the question.

You can use either Object mode or World mode depending on the situation.

When Object mode is selected, the scan lines are affected by the transform (position, scale, rotation) of the Object.
This is good for object effects.

When World mode is selected, the scan lines are not affected by the Object's transform (position, scale, rotation).
This is suitable for world effects.
example : https://styly.cc/ja/tips/unity-shader-worldscanline/

9812398123

Thanks! I didn't think about that. I now see that "World" space can be also very useful for this effect 🙂

9812398123

Hey!
In "Chapter 42 🍍 Soap bubbles (Particle System)" you never explain why do we use "Normal Vector" node.
Is it because by multiplying by normal vector we will preserve the circular shape even though we apply distortion to the vertex ?

IAFIAF

Sharder Graphで輪郭線が描けるとのことで本を購入、試してみたのですがうまくできずアドバイスいただけませんでしょうか。
chapter 17 dot productの記載そのままのつもりですが、
どうにも輪郭が描けないのです。
(画像が一部ぼやけているので多分あっているという程度です)

Inspectorの設定等はいじっていないので、そこにポイントがあるかもしれません。ご教授いただけませんでしょうか。

なお、Unity 2020.3.0f1にて試行(GitHub配布サンプルと同一バージョン)、
モデルはサンプル内のものを流用にて試しています。

以上、よろしくお願いします。

かもそばかもそば

貼っていただいたシェーダーグラフの画像だと、View Direction と Position の内積をとってしまっていますね。
Position の 代わりに Normal Vector を使ってみてください


Normal Vector ノード

IAFIAF

返信ありがとうございます。
本内の絵を拡大してよく見るとNormal Vectorが使われていたのですね。ご指摘いただきありがとうございます。(文書内に赤文字でPositionと書かれていたのでPositionだと思い込んでいました)

Normal Vectorに変え実行したところ、
・DDXYを使用しなければ球(Sphere)はうまく描画できるようでした。球でないモデルでは輪郭線の描画は失敗するようでした。
・DDXYを使用するとどちらもうまく描画できないようでした。

きっとまだ何か間違いがあるとは思うのですが見つけられず…

(DDXY無し…球の表現はうまくいく)

(DDXYあり…黒く表示されるのみになってしまう)

気が向いたらでよいのでもしわかりましたら教えていただけますと幸いです。

かもそばかもそば

返信が遅くなってすみません。

DDXYノードは数値の変化量が大きい部分を抽出するようなノードです。
法線が滑らかに変化する3Dモデルだと輪郭線をうまく抽出できますが、
添付の3Dモデルは、頂点数が少なく、法線の変化が粗いため、DDXYでは輪郭線を抽出できません。

参考 : 例5 : 輪郭線抽出

背面法など、別のアプローチでの輪郭抽出を試してみてはいかがでしょうか。
参考 : https://light11.hatenadiary.com/entry/2018/05/13/183314

IAFIAF

かもそば様
アドバイスありがとうございました。他の方法も試してみます!

taketarou21taketarou21

誤字報告です。
Chapter 01:この本について
「シェーダーを作るのに必要な知識」の最後の行、「ノードを使った表現の実装例をを紹介していきます。」
「を」が重複しています。
よろしくお願いします。

Kazuya YudaKazuya Yuda

分かりやすくて重宝させていただいております.
誤植報告です.

Sineの周期は 2π なので、6.218秒に1回 くらいの間隔で明滅します。

https://zenn.dev/r_ngtm/books/shadergraph-cookbook/viewer/node-sine

2 * 3.14 = 6.28
なので 6.28 秒ではないでしょうか.
よろしくお願いします.

NazNaz

こんにちは。
重宝させていただいております。

SubstanceDesignerでリニアなテクスチャを書き出したいのですが書き出し時のcolorSpaceの挙動が理解できず、教えていただきたいです。
自環境で検証したところ、

  • Linear: ガンマ補正がかかるっているような見た目で出力されている
  • sRGB: SDの2Dビュー(sRGBオン)の見た目のまま出力されている
    のような結果になりました。

Linearで書き出すと緩急のついたテクスチャが出力され、逆にsRGBで書き出すとリニアなテクスチャが出力されてしまうようです。

本来は

  • Linear: SDの2Dビュー(sRGBオフ)の見た目が出力される
  • sRGB: SDの2Dビュー(sRGBオン)の見た目が出力される
    ではないかと思っています。

かもそばさんの以下の記事でも、Linearで書き出したテクスチャが、元の見た目よりも黒い部分が多く何かしらの補正がかかっているように見えています。
こちら何故かご存知でしょうか?

Color Space を Linear に設定し、テクスチャをエクスポートします。
※sRGBでエクスポートしてしまうと、テクスチャにガンマ補正がかかり、アニメーションにもガンマ補正がかかってしまいます)
https://zenn.dev/r_ngtm/books/shadergraph-cookbook/viewer/tips-substance-texture-linear

遊

はじめまして。
unityのエフェクト周りの情報を集めていて、かもそば様の書籍に行き当たりました。
内容が良さそうだったので、是非社員にも見てもらいたいと思い、できれば社内教育にも活用できたらと思っているのですが、そもそも法人利用は可能でしょうか?
教えてもらえるとありがたいです。
よろしくお願いいたします。