Search Unity

Visual Effect Graphの新機能で広がる表現

  • アーティスト向け

<このページで学べる内容>

Visual Effect Graphの新機能を利用してゲーム内で見かける演出をC#スクリプトをほとんど書かずに実装する方法を解説します。本記事はUnityステーションで高橋啓治郎氏が解説した寿司エフェクトの内容をベースにしています。本記事を通してメッシュをパーティクルに変換する方法と、SDF(Signed Distance Field)ベイクツールの使い方について紹介します。

Visual Effect Graphの新機能紹介

ここ最近のアップデートによりVisual Effect Graphの機能が拡充され、表現の幅とエディタ機能双方の改善が図られています。今回は特に、有用性の高い以下の2点についてしぼって解説していきます。

  • Mesh Sampling
  • SDF Backer Tool

なお、Visual Effect Graph自体については別記事の美しい VFX をリアルタイムで制作をご覧いただくと理解が深まります。また今後のVisual Effect Graphの展望についてはUnity公式ブログUnity 2020 LTS 以降の Visual Effect Graph が拓く新たな可能性にて書かれているので興味がある方はこちらも読んでおくとよいでしょう。

今回の記事では以下の動画のようなエフェクトを作成する手順を通して、新機能を紹介していきます。

まずはふたつの機能の概観を説明したあと詳細について解説していきます。

今回の記事では以下のバージョンで動作確認をしています。

  • Unity 2021.2.3f1
  • Visual Effect Graph 12.1.1

Mesh Sampling

Mesh Samplingとは、Visual Effect Graph内でメッシュ内からパーティクルの位置をサンプリングすることができる機能です。現在はまだExperimentalな機能ではありますが問題なく利用することができます。(ドキュメントはこちら

以下の画像のようにメッシュの面(設定により変更可)からパーティクルを生成することができます。

設定は以下のように複数あり、設定に応じてパーティクルの生成位置が異なります。表現したい演出に応じて設定するとよいでしょう。

SDF Bake Tool

次に紹介するのはVisual Effect Graph 12で新しく追加されたSDF Bake Toolです。本機能が追加される前は外部ツールを利用してSDFファイルを生成していましたが、本機能の追加によりUnity内でファイル生成からエフェクト制作まですべてを行うことができるようになりました。

以下の画像のようにMeshを指定してBake meshボタンを押すだけで手軽にSDFファイルを生成することができます。

SDFファイルとは

SDFファイルはSigned Distance Fieldの略で内容はTexture3Dです。ベイクツールは対象MeshをBoxですっぽり覆い、そのBox内の空間点(※1)から最寄りのオブジェクト表面への距離をテクスチャにベイクします。

※1 … 空間点のとり方はテクスチャの解像度によります。デフォルトでは64x64x64になっているので対象Boxを縦横高それぞれ64分割した点ということになります。

なお、これら新機能に関してはWhat's new in the Visual Effect Graphで詳細に書かれているので興味がある方は読んでみると新しい発見があると思います。

実装解説

ここからは実際にノードを見ながら実装を解説していきます。冒頭でも書いた通り、実験的な機能なため対象のノードを表示するには設定が必要になります。ウィンドウメニューから「Editor > Preference」を選択し、Visual EffectsにあるExperimental Operators/Blocksのチェックをオンにします。

この設定をすることでVisual Effect Graphエディタに今回紹介するノードが表示されるようになります。

メッシュをパーティクルに分解する演出をひも解く

最初に、メッシュからパーティクルの生成位置を取得・設定する方法について解説します。その後、どうやって冒頭のような演出が可能になるのかを順を追って説明していきましょう。

Static Meshからパーティクルの生成位置を取得する

今回の例では主にスキンドメッシュからパーティクルを生成しますが、まずは利用がシンプルなstaticなメッシュからの方法を説明します。メッシュ位置から位置を取得・設定するには主に2つの方法があります。1つ目は初期化時にデフォルト値として設定する方法です。以下の画像のように、Initialize Particleコンテキスト内にPosition (Mesh)ノードを配置し、メッシュとサンプリング方法を設定することで行なえます。

使い方はシンプルです。まずMeshに対して対象となるメッシュを設定します。Placement Modeは上図で説明したようにサンプリング位置を決める方法です。Spawn Modeは特に気にしなければデフォルトのRandomでいいでしょう。Customにするとランダムさを調整することができます。

もうひとつはSample Meshノードを利用した方法です。こちらはInitialize Particleコンテキスト内に作るブロックではなく一般的なノードです。そのため演出に利用する場合はこちらを主に使うことになるでしょう。今回の例ではどちらも初期位置を決めるために利用しているので結果に違いはありません。

左に表示されているのがSample Meshノードで、出力であるPostiionSet Positionに接続しています。設定項目は3つで、Meshはそのままメッシュの指定です。続くTriangleは、メッシュ内のどのポリゴンを対象にするかを指定します。最後のSquareは選択されたポリゴン内のどの位置を生成位置とするかを指定します。

これを応用すると以下のようなエフェクトも簡単に作ることができます。

SkinnedMeshからパーティクルの生成位置を取得する

Mesh Samplingの大まかな使い方を理解したところで、本題のスキンドメッシュからパーティクルを生成し活用する方法を見てみましょう。といっても実は使い方はほぼ同じです。

ノード名もほぼ同じSample Skinned Meshで、設定項目もほぼ同じです。違いはインプットがMeshではなくSkinned Meshになっている点のみです。使い方も若干ですが異なります。Meshはアセットを指定するのに対し、Skinned Meshはコンポーネントを指定する点が異なります。通常のメッシュは頂点をまとめたただのデータであるのに対し、スキンドメッシュは実際にシーン内に配置され、アニメーションするオブジェクトが対象なためです。そのためVisual EffectコンポーネントをGameObjectにアタッチし、インスペクタから(あるいはC#から)設定を行う必要がある点に注意してください。

言い換えれば、この設定以外に使い方の違いはありません。

Mesh Samplingを演出に使う

メッシュからパーティクルの生成方法が分かったところで、今回用に作成したサンプルを通してどういった演出が可能になるのかを見ていきましょう。冒頭でも紹介した以下の動画のエフェクト作成を通じてMesh Samplingをどう使うか見ていきます。

今回のエフェクトの全体は以下のようになります。エフェクト全体としてはこの他にShader GraphとTimelineも使用していますがここでは詳細を割愛します。実際の動作を確認したい方はGitHubに今回のサンプルがアップされているのでそちらをご覧ください。

まずはメッシュからのサンプリングから見ていきましょう。前述したように、Sample Skinned Meshを利用してパーティクルの生成位置を決めます。サンプリングしている部分を展開した拡大図を以下に示します。

Sample Skinned MeshTriangleはポリゴン位置を決めるパラメータです。パーティクル1つごとにどのトライアングルから位置を求めるか、という意味です。そのため、メッシュの持っているトライアングル数(=ポリゴン数)以上の値からランダムな値を生成して利用することでメッシュ全体からパーティクルが生成されるようになります。Squareの値はTriangleが決定したあと、そのトライアングル内のどの位置をパーティクル位置にするか、という意味になります。X, Yどちらも[0 - 1]の間で指定するため、今回は[0 - 1]の間でランダムな値を返すノードを2つ作成し接続しています。

そして決定した位置(Position)を、さらにTransformノードでアニメーション中オブジェクトの位置を適用して変換します。これが最終的なパーティクル位置となります。この操作が必要な理由は、Sample Skinned Meshから得られる頂点位置がローカル座標なのでワールド座標位置に変換する必要があるためです。

最後にそれを初期位置としてSet Positionに接続します。加えて、これをあとで計算に利用するためCustom AttributeであるSet Pにも接続しておきます。

カスタムアトリビュートについて少し補足しておきます。これは言ってみれば自由に宣言できる変数のようなものです。コンテキスト内でメニューを表示し、「set custom」と検索すると以下のようにカスタムアトリビュートを追加することができます。

これを選択、追加するとデフォルトでは以下のようになります。

実はカスタムアトリビュートはインスペクタで変更することができるようになっています。変数名も任意に変更できます。

任意というのが分かりやすいようにHogeという名前にしてみました。自由に名前と型を選択できることが分かると思います。これを利用する場合は同様に(コンテキスト外で)メニューを表示し、「get costom」と検索して追加することができます。

そして同様にインスペクタから名称と型を設定すれば、さきほど設定した値を取り出すことができるようになります。まさに変数ですね。

閑話休題して、アニメーションを行っている部分を見ていきましょう。アニメーション計算部分を展開したものを以下に示します。

アニメーションはPerlin Curl Noise 3Dを利用します。カールノイズ自体の説明はここでは割愛しますが、これは流体っぽいアニメーションを表現する際によく使われるノイズです。比較的手軽にきれいなアニメーションが作れるので利用頻度は高いでしょう。そしてこのノイズは入力として位置を取るので、そのための情報を画面左部分で作成しています。

具体的になにをしているかというと、時間経過によって徐々に移動する位置とさきほどカスタムアトリビュートで設定した値(Set Pした値)を合成し、毎フレーム少しずつ位置が変化するようにしています。そしてその値をカールノイズノードに接続し、得られた結果とSet Pした値とを合成して最終的なパーティクル位置としています。カールノイズノードへ同じような位置情報(Get P)を渡していて冗長なように感じられますが、カールノイズノードから得られるのはGet Pの値自体を動かした結果ではなく、少し移動した差分ベクトルになります。そのため、元の位置と再度合成する必要があるわけです。

これで位置が決まりましたが、参考動画を見ていただくと最初の数秒はパーティクルが移動せず、メッシュの表面にとどまっているのが確認できます。これは、カールノイズノードのAmplitudeの値を操作して表現しています。Amplitudeは振幅を表し、これを0にすることでノイズによる移動がなくなります。これを時間で操作することでサンプルの表現を実現しています。この値はTimelineを利用して変更を行っています。

こうした面白いエフェクトがとてもかんたんに制作できるので、ぜひ新機能であるメッシュサンプリングを試してみてください。

SDF Back Toolを使ってSDFファイルを生成する

次に紹介するのはSDF Back Toolです。もともとVisual Effect GraphにはSDFを利用するためのノードは存在していました。しかし肝心のSDFファイル生成は外部ツールや外部ライブラリを利用する必要があったため、ひと手間かける必要がありました。しかし新機能である本ツールを使うことでUnityだけでSDFファイルを生成し利用することができるようになりました。ここではツールの使い方と、SDFファイルの概要、そしてそれを利用した簡単なエフェクトを紹介します。

SDFファイルの中身

SDFを利用したエフェクトの解説の前に、そもそもSDFファイルがなんなのかについて解説します。冒頭でも少しだけ触れましたが、ここではもう少し踏み込んで内部にどういう情報が保持されているのかを確認します。

前述の通りSDFファイルの実体はTexture3Dです。Unityのドキュメントを参照すると以下のように説明されています。

> Signed Distance Fields (SDF) are 3D textures where each texel stores the distance from the surface of an object. By convention, this distance is negative inside the object and positive outside. SDFs are useful for creating particle effects that interact with complex geometry.
Texture3Dの各テクセルはメッシュ表面への距離を保持しています。外側はプラス、内側はマイナスとなる値が格納され、これがSignedの由来となります。UnityではSDFファイルを3つのモードで可視化することができます。

SDF Bake Toolの利用方法

ここからはSDF Bake Toolの使い方を解説していきます。SDFファイルの生成方法は大きく分けて2つあり、ひとつはSDF Bake Tool Windowを利用する方法、もうひとつはSDF Bake Tool APIを利用する方法です。

SDF Bake Tool Windowを使ってSDFファイルを作る

まずは一番良く使われるであろうSDF Bake Tool Windowから解説していきましょう。こちらはいわゆるユーティリティとなっていて、ウィンドウメニューから開いてGUI操作によってSDFファイルを作成するものとなります。ウィンドウメニューの「Window > Visual Effects > Utilities > SF Bake Tool」から起動することができます。

起動すると以下のようなウィンドウが表示され、Meshに、ベイクしたいメッシュを設定してBake meshボタンを押下するとベイクされます。

画像下の赤いボックス状になっているのがベイクされたSDFです。いくつか見た目を変更することができ、SDFモードにすると以下のように輪郭がはっきり見えるようになります。

最後にSave SDFボタンを押してアセットとして保存すればVisual Effect Graphで利用することができるようになります。

SDF Bake Tool APIを使ってSDFファイルを作る

こちらはC#スクリプトからSDFを作成する方法です。APIの利点としてランタイムでSDFを作成することができます。つまり、アニメーション中のスキンドメッシュからSDFファイルを作成して利用することが可能となります。とはいえ生成にはそれなりにコストがかかるため、あまり大きなオブジェクトで実行することはおすすめしません。

ドキュメントからコードを引用すると以下のように非常にシンプルにSDFを生成することができます。

```
using UnityEngine;
using UnityEngine.VFX;
using UnityEngine.VFX.SDF;


public class VFXUpdateSkinnedSDF : MonoBehaviour
{
    MeshToSDFBaker m_Baker;
    SkinnedMeshRenderer m_SkinnedMeshRenderer;
    Mesh m_Mesh;
    VisualEffect m_Vfx;
    public int maxResolution = 64;
    public Vector3 center;
    public Vector3 sizeBox;
    public int signPassCount = 1;
    public float threshold = 0.5f;

    void Start()
    {
        m_Mesh = new Mesh();
        m_Vfx = GetComponent<VisualEffect>();
        m_SkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
        m_SkinnedMeshRenderer.BakeMesh(m_Mesh);
        m_Baker = new MeshToSDFBaker(sizeBox, center, maxResolution, m_Mesh, signPassCount, threshold);
        m_Baker.BakeSDF();
        m_Vfx.SetTexture("WalkingSDF", m_Baker.SdfTexture);
        m_Vfx.SetVector3("BoxSize", m_Baker.GetActualBoxSize());
    }
    void Update()
    {
        m_SkinnedMeshRenderer.BakeMesh(m_Mesh);
        m_Baker.BakeSDF();
        m_Vfx.SetTexture("WalkingSDF", m_Baker.SdfTexture);
    }

    void OnDestroy()
    {
        if (m_Baker != null)
        {
            m_Baker.Dispose();
        }
    }
}
```

小さいオブジェクトや頻繁に変化しないオブジェクト(例えば破壊などで形状が変わるオブジェクト)などの場合はランタイムでSDFを生成してエフェクトに利用するしてもいいでしょう。

SDFを利用してパーティクルを制御する

では実際に、SDFを利用したエフェクトを紹介しましょう。このエフェクトは高橋啓治郎氏がUnityステーションでSushiVFXという名前で紹介した中にあったものを調整し、今回用に作成したものとなります。

ここで紹介するエフェクトは冒頭で紹介した以下の動画です。

こちらも同様に全体図を見てから説明を進めていきます。

こちらの例ではParticle Stripという機能を利用して表現しています。ここでは詳細は割愛しますが、かんたんに言うと2つのパーティクルシステムによって表現されるライン状のエフェクトということができます。左側のシステム(点線で囲まれているエリア)が点の位置を更新し、続く2つめのパーティクルシステムが更新された点の位置を元にラインを表現します。

本機能についてはUnity JapanのYouTubeチャンネル内の動画Particle Stripで軌跡を描こう - Unity VFX Graph Advanced Tips #1にて解説されているのでそちらを見ると理解が深まると思います。

この図の右側は標準的なParticle Stripのシステムなので詳細は割愛します。ここでは主に左側のシステムの操作について、つまりSDFの扱いについて説明していきます。

詳細な説明に入る前に、全体の流れを追いやすいように大まかな処理の流れを解説します。まず、SDFファイルを利用してパーティクルの初期位置を決定します。次にパーティクルを動かします。動かす方向は対象オブジェクトの表面を沿うような方向です。そしてその計算にもSDFを利用します。

SDFファイルには表面への距離が格納されていると話しました。実はSDFファイルを扱うノードは距離だけでなく方向も扱うことができるのです。つまり、現在のパーティクルの位置から最寄りの表面までの方向が分かるわけです。方向が分かればその方向ベクトルに対して垂直となるベクトル、つまり沿う方向ベクトルを求めることができます。このベクトルの求め方はかんたんで、外積を利用するだけです。沿う方向のベクトルが求まってしまえば、あとはその方向にパーティクルを動かし続けることで動画のような演出が可能となるというわけです。

パーティクル位置と方向を初期化する

ここからはノードを見ながら詳細に処理を見ていきます。メッシュサンプリングのときと同じように、まずはパーティクルの位置を初期化します。今回はSDFを利用するので専用のPosition (Signed Distance Field)ブロックを利用します。

SDFにはベイクツールで作成したファイルを設定します。上の例では外部パラメータ化して設定できるようにしてあります。そしてField Transformによって位置やサイズを調整します。ここは実装したいエフェクトなどによって適宜変更してください。

位置を決定したら次は初期の方向を設定します。ここは単純にランダムな方向を6パターンから選択して設定します。(上下左右前後の6パターン)

設定された初期方向を元に、Update Particleコンテキストでパーティクルの方向を更新していきます。実際に更新処理を行っているノード群は以下です。やや複雑に見えますがやっていることはシンプルです。ひとつずつ順を追って見ていきましょう。

最初の計算はまさに今回の話題の中心であるSDFの利用です。Sample Signed Distance Fieldノードを使ってSDFからdirection、つまり今のパーティクルから最寄りの表面への方向を取得します。さらに現在の方向を取得(Get Attribute direction (Current))し、ふたつのベクトルの外積(Cross Product Vector3)を取ります。

外積を簡単に説明すると、ふたつのベクトルのどちらともに垂直なベクトルを得ることができる演算です。つまりここで行っていることは、表面へのベクトルに垂直なベクトルを求めているわけですね。言い換えれば表面を沿うベクトルを求めているというわけです。これが今回のエフェクトの肝です。このベクトルが求まってしまえばあとは簡単です。

最後に行っているのは前段で求めたベクトルをNormalizeしそれに係数をかけてパーティクルのスピードを調整しているだけです。そして調整したベクトルをスピードとしてSet Velocityに接続します。

これを実行すればパーティクルがオブジェクトの周りを沿うように動き始めます。

SDFにはこれ以外も面白い動きをかんたんに実現するブロックが存在するので色々試してみるといいでしょう。

まとめ

Visual Effect Graphはどんどん進化していて手軽にかつかんたんに面白いエフェクトを使えるツールなので使ったことがない方はぜひ触ってみることをおすすめします。今回紹介した以外にも面白い機能や便利な機能がたくさんあるので更新情報はたまにチェックすると新しい発見があるでしょう。今回の記事がVisual Effect Graphを使うきっかけになれば幸いです。

--

筆者紹介:えど

ARスタートアップのMESONでUnityエンジニアとして従事。もとはカヤック時代にWebエンジニアとしてリーダーを務め、その後VRと出会いコロプラに転職。コロプラでは仮想現実チームにてXRコンテンツ開発に携わる。Daydream向けゲーム「Nyoro The Sanke & Seven islands」をリリース。またプライベートでもAR/VRの開発をしており、インディー部門でTGSに出展など公私関わらずAR/VRコンテンツ制作に精を出す。プライベートな時間でも開発しているように、新しいことを学ぶ事が趣味で、最近は英語を学んでいる。

Twitter:https://twitter.com/edo_m18
この記事はいかがでしたか?