Visual Effect Graph は、ノードベースの動作と GPU ベースの演算能力によって、次世代のビジュアルエフェクトを作成することを可能にします。まず、このエディターの概念についてまとめた初心者向けブログ記事を公開しました。また、Unite LA 2018 での初回プレビューリリース以降 GitHub リポジトリに多様な VFX のサンプルを公開しています。ぜひチェックして、独自のエフェクトを作成する際に役立ててください。
これらのサンプルでは、Visual Effect Graph で処理可能な各種制作シナリオを紹介します。単純なものから、非常に特殊な動作を持つ複雑なものまで、さまざまなパーティクルシステムを扱っています。これらのエフェクトはすべて別々のシーンで提供されているので、個々に参照して学習することが可能です。
サンプルの入手
サンプルを入手する前に、まず Unity 2018.3 を実行していることを確認します。最新のバージョンを確実に使用するためには Unity Hub の利用をおすすめします。Visual Effect Graph のサンプルは Windows と Mac 両方のエディターで動作します。
適切なバージョンのエディターを起動したら、サンプルプロジェクトをダウンロードします。Visual Effect Graph の GitHub の「Releases」ページからソースコードの zip や tar.gz アーカイブのダウンロードが可能です。または、定期的に更新したい場合はリポジトリをクローンすることもできます。
サンプルプロジェクトの構造
各サンプルは、Assets/Samples ディレクトリのサブディレクトリに含まれています。メインシーン(プレイヤーのビルド時に使用)は Assets のルートにあります。このシーンは、「Build Settings」ウィンドウの「Scenes in Build」のリストで宣言されているすべてのサンプルを順番にロードするために使用されます。
プレイヤーをビルドする必要がある場合は、VisualEffectsSamples シーンがビルド設定のインデックス 0 に含まれていることを確認し、循環したいすべてのシーンを追加するだけです。
サンプル #01 – Unity Cube
このサンプルは、初期バージョンの Visual Effect Graph を使用して制作されたエフェクトの 1 つです。ボリュームレンダリングによる Unity キューブにパーティクルを引き付ける、移動する放出源を持つ 40 万個のパーティクルで構成されたシステムを紹介しています。
放出している球体とそのモーションはエフェクト内で自己完結されており、位置は各軸の sin(Time) の組み合わせを使用してアニメーション化されます。この演算で興味深いのは、球体の位置の離散化を軽減するためにサブフレームの位置を決定できる点です。このオプションを切り替えると 2 つのモードの違いを確認することができます。下の「TotalTime」のみが使用される例では、球体がすばやく動くので空間内で形状が離散化されます。ところが「Total Time (Per-Particle)」を使用すると、このアーティファクトは完全になくなります。
いったん球体によって放出されたパーティクルは、Unity キューブに引き付けるアトラクターと、引き付けられている間のモーションを強化するノイズという 2 つのベクターフィールドによって駆動されます。また、パーティクルは放出している球体と衝突します。
パーティクルの色は 2 つのグラデーションで決まります。5 秒ごとに循環する、放出している動く球体に接近するパーティクルのグラデーションと、青からピンクへと変わる標準の「Color over Life」のグラデーションです。
このマスキングのテクニックを使用して、放出源がいくつかのフェイクライティングを隣接するパーティクルすべてに適用するというシミュレーションを行っています。
サンプル #02 – Morphing Face
Morphing Face では、ポイントキャッシュを使用してパーティクルの初期位置を設定したり法線などの別の属性を格納したりする方法を紹介します。パーティクルは、Houdini でベイクしたポイントキャッシュからランダムに生成されます。ですが、Point Cache Bake Tool(Window/Visual Effects/Utilities/Point Cache Bake Tool)を使用して、このポイントキャッシュを Unity のメッシュから生成することもできます。
ポイントキャッシュファイルは Unity にインポートされ、各属性につき 1 つのテクスチャーがあるアセットを生成します(Attribute Map)。その後、このアセットは「Point Cache」ノードを使用して参照することができます。「Point Cache」ノードではすべての属性マップが設定され、各属性につき 1 つのコネクターが示されます。それからこれらの属性マップを「Set < 属性名> from Map」ブロックに追加して、値をフェッチすることができます。上の例では、このポイントキャッシュからランダムにポイントをサンプリングして、パーティクルを作成しています。
いったん作成されると、これらのパーティクルは空間に固定されたままになるのでシミュレーションでは更新されず(システムには更新のコンテキストがありません)、古くなったり消滅したりすることはありません。ここで行っているのは、出力のコンテキスト(上の図の緑と赤の部分)においてマスクを時間の経過とともに演算することだけです。
このマスクを使用すると、非金属製の小さなキューブと金属製の長いスティックという 2 つのステートをブレンドすることで、パーティクルの多くのパラメーターを制御することが可能になります。向きも、整列したキューブとランダムな方向を向いているスティックがブレンドされています。
このシーンでは、マスクをアニメーション化しつつマテリアルの変化も示すために、移動する光も使用しています。
サンプル #03 – Butterflies
Butterflies サンプルは、1 つのパーティクルのレンダリングに複数の出力を使用する例を示しています。このサンプルでは、中央の縦軸を周回する蝶の群れをシミュレートします。どの蝶も 1 つのパーティクル要素のみによって定義され、軌道だけが更新のコンテキストでシミュレートされます。下の例では、蝶のパーティクルが赤い点でハイライトされています。
羽と胴体のアニメーションは、3 つの異なる出力コンテキスト(左右の羽に 1 つずつと胴体に 1 つ)で演算処理されています。
蝶の方向を決めるために、前方(速度)ベクトルと少し後傾した上方ベクトルを組み合わせて使用します。これにより、胴体は軌道に沿うのではなく、頭部が腹部よりも上がるように動きます。胴体は、蝶ごとにランダムな頻度でサイン波を使用してアニメーション化されています。また、羽の角度も同様の頻度でサイン波を使用してアニメーション化されていますが、胴体のダンピングと慣性をシミュレートするために時間内にわずかにオフセットされます。
サンプル #04 – Grass Wind
Grass Wind は、通常のパーティクルとはまったく異なる、地形上の草地のシミュレーションを示すサンプルです。地形データから生成されたポイントキャッシュを使用することで、地形の法線からブレンドされた上方ベクトルとワールド空間での上方ベクトルにより、地形に草地を生成します。
そして、各要素が Position、Radius、Velocity パラメーターを使用してプレイヤーとやりとりを行い、エフェクトに送信され、プレイヤーのキャラクターが持つ値に基づいた動きをします。
その後、シミュレーションが以下のルールで行われます。
- プレイヤーの範囲内の草地は、プレイヤーの移動方向にしなる
- すでにしなっている草地はこれ以上影響を受けないため、その上を歩いても何も起こらない
- 草地は、時間の経過とともに元の方向に再生する傾向がある
しなった草地をシミュレートするために、未使用の属性である velocity と alpha に値を格納します。
- velocity には草地がしなった方向を格納する。
- alpha にはしなった状態を格納する。1.0 の場合は草地がまっすぐ立っている状態、0.0 の場合は完全にしなっている状態を表します。最小値(-2.0)は 0.0 と同じで、草地のしなった状態を長く保つために使用されます。
草地の上を歩く際の alpha 属性は、最小値(-2.0)に達するまで一定の速度で下がります。草地の上を歩かない場合、1.0 に到達するまで一定の速度で再生します。0.0 から 1.0 に遷移する際に、velocity の値の固定が解除され、草地が再度垂直になるまで減少していきます。
歩行やしなりの影響を受けない草地ではすべて、出力に追加で風によるゆらぎを適用して、影響を受けないときにただそこに立っているだけになる状況を回避しています。
サンプル #05 – Volumetric
比較的単純な Volumetric サンプルで紹介しているのは、HD レンダーパイプラインのライティングとボリューメトリックフォグへの統合です。シーンは分割された環境でセットアップされており、その背景の空は単純な灰色です。光源にはオレンジと青の 2 つが使用されています。影を付けるために、リアルタイムシャドウをオンにして、カメラの方向を向いた 1 つのスポットライトで各光源を構成しています。また点光源をシミュレートするため、各光源に別のスポットライトを逆方向に構成しました。
パーティクルごとに複数の要素をシミュレートするために、不透明なパーティクルがフリップブックテクスチャーを持つアニメーション化されたソースから生成されます(これにより、実際の 6 倍のパーティクルを使用しているかのような豊かな質感を表現しています)。ノイズを使ってパーティクルの量感を豊かにし、さらにパーティクルはカメラ近くの位置に引き付けられて動きます。
パーティクルは Cast Shadows がオンの状態でレンダリングされ、光がパーティクルを通して漏れるように透過率のある拡散プロファイルを使用します。
次の動画で、このサンプルに使用したライティングの内訳を示します。
サンプル #06 – Portal
この Houdini のチュートリアルを見た後、CG パッケージからエフェクトを作り直して独自の改良を加えるという課題に挑戦する意欲が私たちに生まれました。また、Houdini で作成された RISE FX によるデモリールからもいくらかインスピレーションを得ました。
このエフェクトの内訳についていうと、8 個のラインライトから成るライティングリグ、単一のパーティクルシステム、内部の歪んだ円から構成されています。これらはすべて再生モードで回転します。
パーティクルは生成時に、高速なコロナのパーティクル、衝突するパーティクルという 2 グループに分類されます。ただし、どのパーティクルも地面で衝突します。
サンプル #07 – AR Radar
AR Radar では、連携する多数のシステムを使用した複雑なエフェクトを紹介します。内部でシーケンシングを実行するほか、外部へのシーケンシングも行い、単一の float [0…1] パラメーターである Initialize を通じてタイムラインにシーケンシングします。
このパラメーターは以下のように、グリッドを初期化しながら展開エフェクトを制御するためにグラフ全体で何度も使用されます。
- 0.0 ~ 0.1:点滅している点を制御する
- 0.1 ~ 1.0:グリッドが環境と同様に展開される
敵の機体は、ベースとなるエフェクトを展開した後に Timeline VFX Dedicated トラックを使用してトリガーされます。このトラックは、敵の機体を周囲に生成するイベントを複数回送信します。
中心の点滅している点は、シーンのポイントライトにリンクするために「Position」パラメーターバインダーによって制御されています。
次のビデオに内訳を示します。
サンプル #08 – Voxelized Terrain
VoxelizedTerrain は、それぞれがキューブとしてレンダリングされるパーティクルによって駆動される、ハイトフィールドのシミュレーションです。
各パーティクルは 2D グリッド(256 x 256)上の点であり、オブジェクト空間座標に基づいて 2D テクスチャーからサンプリングされています。地形がスケーリングおよびパンされるように、座標のオフセットおよびスケーリングを実行できます。
このハイトマップをサンプリングして Scale.y に値を格納すれば、実際のサンプリングされた Height を設定するためにすべての点をデフォームしたり、その高さに基づいてキューブに色を付けたり、マテリアルのプロパティー(水のスムースネスなど)を調整したりすることができます。
「Water Level」のほか、(テクスチャから読み取られる)「Input Height」や最終的な「Elevation」を調整することができます。これらのパラメーターはすべて、グローバルなスクリプト(VoxelizedTerrainController.cs)によって公開および制御されます。
このスクリプトはマウス/キーボードのイベントを処理して、カメラのパン、スケール、回転を行い、Visual Effect コンポーネントにすべてのパラメーターを設定します。使用されているのは、パラメーターの文字列値をキャッシュし、(Shader.PropertyToID() から)整数インデックスを返す便利な ExposedParameter 構造体です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
dist = Mathf.Clamp(dist, CameraMinMaxDistance.x, CameraMinMaxDistance.y); ViewingCamera.transform.position = CameraRoot.transform.position + dist * dir; VisualEffect.SetVector2(Position, m_Position); VisualEffect.SetVector2(WorldSize, m_WorldSize); // スライダー float inputHeightMapScale = Mathf.Lerp(InputHeightLevel.x, InputHeightLevel.y, InputHeightMapScaleSlider.value); float elevation = Mathf.Lerp(ElevationRange.x, ElevationRange.y, ElevationSlider.value); float waterElevation = Mathf.Lerp(WaterElevationRange.x, WaterElevationRange.y, WaterElevationSlider.value); CameraRoot.transform.position = new Vector3(CameraRoot.transform.position.x, waterElevation, CameraRoot.transform.position.z); ViewingCamera.transform.LookAt(CameraRoot.transform); VisualEffect.SetFloat(InputHeightMapScale, inputHeightMapScale); VisualEffect.SetFloat(Elevation, elevation); VisualEffect.SetFloat(WaterElevation, waterElevation); |
サンプル #09 – Genie
Genie エフェクトは多数のシステムで構成されています。これらのシステムはいくつかのパラメーターを共有するほか、内部のシーケンシングを使用することで相互に接続されます。このサンプルは、魔法のランプをクリックすることでエフェクトのオンとオフを切り替える単純なスクリプトを使用しています。
このシーンには、ランプから魔法の流れを出すためのベジェ点を定義する 4 つの点があります。パーティクルを駆動するために使用しているのは、速度ではなく、パーティクルの寿命全体にわたるこのベジェに沿った位置と、ベクターフィールドのノイズから計算されるオフセットです。
ベジェの最後の点では精霊の位置が保持され、精霊が 3D サイン波のアニメーションによってビジュアルエフェクト内でアニメーション化されます。これにより、ベジェの最後の点に加え、精霊の胴体と瞳が駆動されます。
このシーンは、単一のタイムラインと、タイムラインを前後に動かす制御リグを使用してセットアップしています。パーティクルの生成の開始と停止を制御するには VFX イベントトラックを使用しています。さらに、このタイムラインは Cinemachine カメラのブレンディングと単純な制御リグを制御します。
その他のビジュアルエフェクトと今後のサンプルリリース予定
新しいサンプルはいずれも、Visual Effect Graph パッケージ(5.x.x-preview)の 2019.1 リリーストラックに含まれています。つまり、ここまでに紹介したすべてのサンプルはこの新しいリリーストラックに含まれていますが、残念なことに 2018.3 のサンプルについてはこれ以上更新される予定はありません。2019.1 向けのリリース時にこのような新しいサンプルをいち早く入手していただくには、Unity の Twitter や Facebook で最新情報をチェックしてください。
また、近日中に Fontainebleau デモと FPS Sample リポジトリでもビジュアルエフェクトを公開いたします。他にも、自作のプロジェクトを構築する際のインスピレーションとなる制作ケースやソリューションもご用意いたします。
近日リリース予定の新しいビジュアルエフェクトもぜひお試しください。
関連する投稿
Comments are closed.
7 replies on “Visual Effect Graph のサンプル”
Git repo download/clone is broken.
Hi there,
at 0:32 of the VFX graph showcase video, you show a multicolored bundle of what appear to be trajectory trails. Is that sample available? How easy would it be to produce each trail from a gameobject position over time? how about and ECS entity over time?!?! ;)
Awesome. Does it work in mobile devices or it is too heavy?
Is there a plan to support LWRP?
I’m excited to see Unity features at GDC 2019
Building the GDC Hype!! WOOT WOOT!
Heey there’s an open issue in that repo! ;)