Open21

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

本の感想や質問をお気軽にコメントしてください。

18 Cross Product ノード/任意方向へ進む波のアニメーションにあるDirノードの出し方について教えていただけないでしょうか?

Unity 2021.1.0f1 です。
create nodeからfilteringしても見つけることができませんでした。

Dirはプロパティです。(シェーダーグラフにDirというノードがあるわけではないです)


Dirの作り方は以下になります。

  1. ShaderGraphのブラックボードの+ボタンをクリック
  2. Vector3 を選ぶ
  3. Dirという名前を付ける
  4. DirをShaderGraphへドラッグ&ドロップする

Dirプロパティが作られている状態だと、create nodeの一覧に出てくるようになります。

ご返信ありがとうございます。
手順動画も付けていただきありがとうございました。
理解できました。

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

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

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

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

シェーダーについて追加で質問失礼します。
①オブジェクトのローカル座標と、任意ベクトル(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】ベジェ曲線を波打たせてみる

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

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を以下のように設定して、実行したときにどうなるかを見てみたいです。

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

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

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

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

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

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

修正してみました。

行った作業

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

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

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

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

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

集中線が表示されるようにしたUnityプロジェクトをお渡しします。

https://xgf.nu/mhSd

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

ログインするとコメントできます