🎇

Tips: Unity Visual Effects Graph

2023/06/22に公開

雑多な備忘録メモ。随時更新していきます。

Shuriken Particle or VFX Graph

VFX GraphはURP/HRDPのみ。Built-in Render pipelineのときは使わないほうが良い。
iOS, Androidでも使えるが、Android ARCoreは2023年1月現在OpenGLES対応のみでVulkanに対応していないので、実質AndroidのARが含まれるときは使えない。ARCoreのVulkan対応してほしい(最新のGoogle ARCoreではされたけど、ARFoundation上はまだっぽい?)。

Shuriken Particleでもカスタムプロパティをシェーダーに書き込む方法はあるので、頑張れば結構複雑な方法は作れる。VFXGraphでやるとクソデカshaderが生成されがちなので、パーティクル数がそんなにでもない。CPUに処理にまだ余裕があるときにはShurikenもあり。

色々Tips

  • まずはじめにやること、Unity の環境設定でExperimentalな設定をActiveにすること。keijiro氏のやつとなにか自分のVFX違うんだけど。と思ったら多分これ。ますこれをOnにしないとカスタムのShader Graphが使えないので、表現力が全然ちがう…。一番目立つところに書いて〜〜〜。この環境設定はGitHubでは共有されない部分なので、一緒にチームで開発してる人がいじれないってなったりする。チーム全体でこの設定を共有すること。
  • Systemで設定されているノードって何やってるかわからんけど、 Inspectorを選択すると生成されるComputed Source Codeを見れるので、そこで理解することも多い。Turbulenceとかもパラメータ意味わからないけど、Computed Source Codeをみると以下のようなものが見れるので一目瞭然。

例えばこんな感じ

float3 vectorFieldCoord = mul(InvFieldTransform, float4(position,1.0f)).xyz;

float3 value = GeneratePerlinCurlNoise(vectorFieldCoord + 0.5f, frequency, octaves, roughness, lacunarity);
value = mul(FieldTransform,float4(value,0.0f)).xyz * Intensity;

velocity += (value - velocity) * min(1.0f,Drag * deltaTime / mass);
  • OutputでLit, Unlitを選べる。Unity Shader Graphでカスタムのシェーダーを設定できるが、Lit, Unlitの設定を間違えたShaderを設定すると問答無用で落ちるし、落ちたあとプロジェクトが開かなくなるので要注意。バージョン管理必須…。
  • Gitとかで管理するときは、.vfxファイルをテキストで扱うか悩む。今の所テキストで扱っているが、Diffを取ることは実質不可能なので、バイナリにしちゃても良いかもしれない。
  • Noiseで直接ポジションをいじるとピーキーすぎるけど、TargetPositionへ設定してTarget PositionへのForceを設定すると良い感じに扱いやすくなる気がする。Turbulenceとやってることは同じ。
    • VFXを設計するときに、直接ポジションをいじるか、Velocityでいじるかは作りたいエフェクトによって変わる。直接ポジションをいじると扱い安いが、自然の動きを表現する、みたいなのはVelocityをいじったほうが自然になる。
  • PackageのSampleの中に、Tween Easing Functionなどの便利コンポーネントが入っている。一度みるのがおすすめ。VFXGraphは増えすぎるとコンパイルが重くなっていくので、サンプルから使うやつだけ抜き取るのが良さそう。
  • 作り始めるときの設計として、「直接Positionをいじるか、Velocityをいじるか」で全然変わる。
  • 一時変数として、Custom Attributeを積極的に値を格納していくとGraphがきれいになる気がする。
  • positionを扱うノードは (L) (W) というマークが付くが、これはLocal Space or World Space.これを勘違いして作るとバグるので気をつける。
    • VFX Property Binder → Transformで送られてくるTransformはVFXがローカルの設定だろうとWorld Positionが送られてくるので、WorldToLocal matrixを使ってLocal座標に直してあげないといけない。
    • ぶっちゃけこの機能はなくしてほしい。Noneをしていることもできるが、一部のノードは強制で意図しないコーディネートに変換されることがあるので、自分で変換するほうがいい。
  • リファクタリングが難しい。Sub Graphを作って、いろいろなエフェクトで使い始めるとあとから変えようと思っても、どこから参照されているかわからないので、うかつに変更できない罠に陥る。SubGraphファイルの.meta をテキストエディタで開き、guidをコピー。*.vfx or *vfxoperatorのファイルからテキストエディタ上で全検索するとguidの参照が見つかる。UnityのQuick Searchで同じことができるとだいぶましになるのだが、やり方が見つからなかった。
  • VFX Property Binderは実際に追加するコンポーネントを隠してしまっているので、実際にそれぞれのBinderコンポーネントが何をやってるかを見たいときは、Unityのインスペクターを一時的にNormalからDebugにすると隠れているコンポーネントが見れる。
  • 積極的にVFX Property Binderを使うと面白いことができる気がした。
  • ↓Look At ノードを使おうとすると、以下のようなエラーがでて半日溶けた。
    (Null Asset) : Exception while compiling expression graph: System.InvalidOperationException: The expression UnityEditor.VFX.VFXExpressionAdd is not valid as it have the invalid flag: InvalidOnGPU, PerElement
    原因は→ "Look At" block in UpdateParticle throws Error - Unity Forum.
    GPUではmatrix-to-eulerっていうオペレーションが使えない。全然違うエラー文言や。最初から言ってくれれば…。added [[2023-01-31]]
    • Node がCPU/GPUどっち側で実行されるのかをデバッグ表示したりできると良い気がする。
  • Sample Meshが動かないときは、とりあえず メッシュのRead/Write がoffになってないか確認すべし。エラーを出してほしいぞ…。
  • VFX GraphとShader Graphを組み合わせて使うときに、VFX Graphで行われているPerlin Noiseなどの処理をShader or Shader Graphでも同じ実装でやりたい!(VFX GraphとShader GraphのVertex Shaderでの処理を同期というUse Case)。そんなときVFX Graph内部のシェーダーをShader GraphのCustom Functionで読み込めることに気づいた。これを使えば同じ処理ができる。
#include "Packages/com.unity.visualeffectgraph/Shaders/VFXNoise.hlsl

void VFXGeneratePerlinNoise_float
    (float3 coordinate, float frequency, float octaveCount, float persistence, float lacunarity, out float4 Out)
{
   Out = GeneratePerlinNoise(coordinate, frequency, (int)octaveCount, persistence, lacunarity);
}

ノイズは内部的にはこれを使っているらしい。ライセンスフリー
GitHub - BrianSharpe/GPU-Noise-Lib: Optimized GPU noise functions and utilities

  • Perlinノイズのインプットにはcurrent positionを使うと、チカチカすることがある。初期ポジションはcustom attributeに入れて、それを参照すると良いことに気づいた。

  • Orient Camera Position。VRカメラに使うと、Z rotationをしたときに変な回転が加わるので、回転を無視したカスタムのやつを作った。

  • VFXVelocityBinderはTimelineと一緒に使うと、UnityEngine側のTime.deltaTimeを取得しているためにうまく行かないという問題がある。本来なら、VFXGraph.timeプロパティを使うべきだが。カスタムするか、 PositionとPreviousPositionバインダーを使ってVFXGraph内で計算とかでも良いかも。

  • カスタムSpawnerは結構簡単に作れる。MIDI Note ONイベントに合わせてSpawnするものをつくった。

    • Inputにとれるデータ型は決まっているので、Texture2Dにベークしたものを使っている。
  • 公式のVFXGraphでIn Progressステータスになってしばらく立っているカスタムHLSLをVFXGraphに取り込める機能。早く入れてほしい。元VFX開発チームの PeeweekさんによるPeeweek VFX Graph Extras の中にはすでにその機能がある。公式に取り入れてほしい。

  • "use of potentially uninitialized variable (BuildVaryings)" こんなエラーが出て急にVFXが表示されなくなることがある。これは多分VFX GraphのAttributeの数が多すぎる

    • カスタムのShader Graphを使っている場合、そこでExposeしているパラメータも含まれるので数が多すぎて動かないってやつだった。floatをvector4とかにまとめると良さげ。
  • Initialize Particle, Update Particle, Output Particleで同じ処理でも挙動が違うので、そこの違いを理解するのが大事。

    • Initialize: その名の通り一回だけ計算する。重い計算はここでCustom Attributeに変数として突っ込むのもいいかも。Updateではinterpolateするだけとか。
    • Update Particle: 毎フレーム実行される。ここを軽くするのが大事。
    • Output Particle: Outputは複数持てる。つまりUpdateまでは共通で、Output部分でサイズを変えたtrailを持ったりなどができる

Discussion