このページは情報の再認識のために自身が文字起こししているものです。
他社のコンテンツのためNoIndex/NoFollow・広告Off にしています。
誤って広告等がしている場合は、お手数ですがコメントいただけると幸いです。
VXFグラフでなんかつくる
しゃべりながら、VXFグラフでなんかつくる動画です。
適宜質問が入るためわかりやすく、VXFグラフをやりたいがなにをやったら良いかわからない人向けの導入動画です。
ただ、カタカナ語や、答えが後から出てくるケースもあるため、若干文字起こし時に要約している部分もあります。
前半:VFXGraphを設定してみる
バージョンは 2019.3.9F1(撮影当時2019.3の最新)
元ネタとしてモデルデータを取り込んで、そこからエフェクトを発生させていこうと思います。
ネタとして複雑な形状があった方がよくて面白くなりやすいので、
エフェクト作りを練習するときには、そういうアプローチにした方がいいのではないかな?というのを踏まえて、それをやってみたいと思っています。
モデルデータを作る(ここではBlenderの猿顔)
- Blenderを立ち上げる。
- Add > Mesh > Monkey で既成メッシュを出す。
- File > Export > Wavefront(.obj)で書き出す。(名前をMonkeyとしてdesktopに書き出す。)
- OBJファイルで書き出されたファイルを、unityにimportする(unityのassetsにドラッグして入れる)
■ モデルデータから Point Cash を作る
これをFxのソースとして使用する方法は、
window > Visual Effects > utilities > Point Cash Bake Tool
を開き、mesh(Monkey.objのmesh)をドラッグして指定し、とりあえず初期値のまま “Save to pCash file…” を押してBakeする。(一旦、objと同階層にbake)
バーテックスのデータを画像データに焼いたもの。
Cash とは?
事前計算して再利用できるようにしたデータ全般をキャッシュと呼ぶ傾向があると思う。
シミュレーション結果などを再計算しなくても再利用可能にしたものが、Point Cash や、Vertex Cash などと呼ばれている様子。
(フーディニ等でパーティクルの挙動を物理シミュレーションし、その結果をキャッシュしておく など)
VFXgraphで、
空白部分を右クリック > Create Node > “Point Chash” と打ち込んで選択し、アトリビュートを作成する。
MonkeyのPointCash を drag & drop する。
PointCashのデータを入れると、
PointCount(頂点数)、AttributeMap:position(テクスチャにBakeされたポジションのデータ)、AttributeMap:normal など、Bakeされたデータの項目が現れ、取り出せるようになる。
■ Point Cash を ParticleSystemの初期座標として使う
Initialize Particle に set position From Map(MapからAttributeMapからpositionを拾い出してきてparticleの座標としてセットする)というブロックを置き、これをPoint Cash の AttributeMap:position とつなげると使用できるようになる。
(形がわかりにくい場合は、いったん粒の数を増やしてみる。Spawn の Constant Spawn Rate を 10 → 10000にしてみる)
■ Billboardをカメラ正対にする
横から見たときに板が横を向いてしまうので、
Output Particle Quad に Orient:Face Camera Plane を入れるとカメラ正対し、横から見ても見た目が保たれます。
元のBlenderMonkeyの頂点数より多くの粒が出ている。
これはBake tool のなかの Point Count の数を多く設定し、Distribution:Random Uniform Area(polygon の三角形1枚1枚にランダムに分散) などの設定で頂点数を増やしているものと思われる。
これで、Mesh表面に一様に発生点が広がる。
(ただし、法線に関しては元のMeshからまま拾っているようなので、ある程度細かく割られたmeshのほうが良い。)
Initialize Particle に set Direction From map のブロックを置く。
PointCashの Attribute Map:normal から set direction From map のAttribute Map に線をつなぐ。
inspector のcompositionを Direction → Velocity にすると、法線方向に移動するようになる。
(↓ 置き換え)
Initialize Particle に set Velocity From map のブロックを置く。
PointCashの Attribute Map:normal から set direction From map のAttribute Map に線をつなぐと、法線方向に移動するようになる。
このように名称が定まっているものもあれば、検索に出てこないものもある。
そのためデータを簡略化するためには、ブロックを作成してからinspectorも調整する必要がある。
このままだと無限に出続けてしまうため、
Initialize Particle に set lifetime Random(Uniform) のブロックを入れ、A:2 ~ B:3(2~3秒間で消える)という設定にしてみる。
- B:set Velocity From map → set Direction From map に戻す。
get Direction のAttributeをつくり、Update の中にsetVelocity を作り、つなぐ。
この状態では動きは元のまま変わらない。 - A:sample curve のAttributeを作る。
これで自由に設定したカーブをサンプルして値として使うことができる。
これに対し、Age Over Lifetime のAttributeを作り、sample curveのTimeにつなぐ。
こうすることで、パーティクルが生まれたとき0で死ぬときに1っていうふうな時間の推移を指示することができる。
この2つのAttributeをmultiply(掛け算)のそれぞれA・Bに入れ合わせ、Update の中のsetVelocity に繋ぎ直すと、Lifetimeの推移での動きが加わる。
SpawnがConstantSpawnRateだと常にparticleが発生しているためメリハリがないため、発生の仕方を変える。
PeriodicBurst にし、発生しては飛んでいく感じに変えてみる。
┗ Count:1000 / Delay:2 → 2秒おきに1000個のparticleが発生
ただし、initialize Particle のCapacityを多くしておかないと発生できなくなるため、増やしておく。
この状態だとコンパイルした(発生命令から実行に移った)後 0~2秒までparticleが発生しないため、Spawnの最上位にsingleBurstのブロックを置き、補完する。
┗ Count:1000 / Delay:0 → 開始から0秒の時に1000個のparticleが発生
また、Bounds(バウンディングボックス )が小さいとカメラから少し外れただけで消えてしまうため、大きめのエフェクトを作る際はとりあえず大きくしておくとよい。
(完成してゲームで使う際は、視界外にある時は描画する必要がないためなるべく小さい値にしたほうが良い。)
■ Particle毎のばらつきを与える。
RandomNumber というAttribute をmultiplyの3項目(Bの下、適用前は空白の丸)につなぐ。
min / maxに差をつけると、Random性が出る。
元となったMeshが、ややポリゴンが荒く平面的なため、法線に沿って飛ぶ際に平面感が出てしまっている。
Initialize Particle に Add Direction を足し、inspectorの Random をPar Componentにする。
min / max を -1 -1 -1 / 1 1 1 とするとランダムに飛散するようになる。
このようにすべての絶対数が同じときは、float という Attribute で 1 という数値を指定し、min を指定する方にはNegate(-x)(float)をかませて繋ぎ、maxの方にはそのままつなぐと、-1 -1 -1 / 1 1 1 と同じRandomを指定したことになる。
■ アルファを加えて消していく
Output Particle Quad に SetAlphaOverLifetime というブロックを追加する。
(OutputではなくUpdateの方に入れてもよい。)
■ 色をばらけさせる
Output Particle Quad に Set Color Random from Gradientというブロックを追加する。
Alphaは別で設定しているため、ここではColorMode:Color にして色だけを設定する。
Gradationの面積によって確立が変わるため、赤~オレンジをメインにし、青の範囲を狭めることで、低い確率で青が出るようになる。
(ここまでは StartColorのRandomGradation と一緒、sample Modeを OverLife にするとColorOverLifetimeと同じになる。)
HSVを使用して色を指示するのも便利です。
HSV to RGB というAttributeを作る。(色表現を HSV から RGB に変換してくれるもの。)
X:Hue・色相
Y:Saturation・彩度
Z:Value・明度
とりあえず作業前は 1 1 1 に設定しておく。
■ 再生されてからの時間で、発生する粒の色を変える
Total Time というAttributeを作ります。
色相は 0 – 1 の間で与えないといけないため、Fractional を間に挟み、HSVtoRGBの X につなぐ。
これをSetColorのBlockにつなぐと、発生する色がStartColorに合わせて動く。
・表示部分(Rendering。前に置いた Set Color Random from Gradient)においてしまうと、すべての色が一様に変えられてしまうため
・発生したときに1回だけ変わるようにするためには、
Initialize Particle に Set Color Random from Gradient を置き、
粒の発生サイクル と 色繊維サイクルが同期しないように、Multiplyを挟み(Multiplyを作成し、Total time からの腕をMultiplyのAにつなげる)、Bに適当な乱数を入れてFractionalに返す。
Output Particle Quad にある Set Color の inspector のcomposition がoverwriteだと上書きされてしまうため、multiply などにする。
■ 原点からの距離で粒の色を変える
SetColorを消す(Fractionalからはそのまま使う。)
Get Attribute:Position を作成し、Distance を挟み Fractionalにつなぐ。
後半:particle Stripの使い方(トレイル)
1:43:30頃から後半開始。
ParticleStripは発生させたparticle同士を線でつなぐことができる機能。
■ Particle Stripを出す基本手順
一旦、決まりきった手順と思ってやってください。
このアップデートパーティクル(パーティクルをアップデートする処理)の中で、イベントを発生させます。
Trigger Event Rate (OverTime)のブロックを追加し、秒間 何回のイベントを発生する というのをここで定義することができる。
60フレームぐらいで動いてるので、秒間 60 回のイベントを発生させるよう入力する。
このEventの右手を出し、GPUイベントをつなげる。
GPUEvent といって、イベントの受け口を作ります。
このイベントが発生したら、パーティクルがイニシャライズされるというふうに、下から手を出しinitialize Particle を繋げてあげ、これのinspectorのdata type をparticle Strip にすることで、initialize particle Strip になる。
Strip Capacity というのは、点と点をつなぐ線が何本まで表示できるかというキャパシティで、
Particle per Strip Count は、その1本の線の中に何個までパーティクルが存在しうるかというふうなキャパシティをそれぞれ別々に設定できるようになっています。
一旦、元となるパーティクルの
- initialize のCountを1000個に、
- Spawn数を、500 の2秒サイクルくらいに
制限しておく。
あまり大量に発生させると重くなると思うので少し減らしておく。
なので、こちらでは1,000本のStripを扱うようにして、パーティクルのカウントは1本あたり、多分500個ぐらいは使えれば十分だと思うんですよね。
こんなふうにスリップのキャパシティを設定してあげます。
ここでこのイベントが発生したときのパーティクルのポジションというのをinitialize Particle Stripに引き継がせます。
これはInherit source position(unity6からは、Inheritという単語が存在しない) っていうノードをここに置くことによって、親のパーティクルのポジションをここにコピーすることができる。
生存期間を適当に setLifetime で 2秒 を設定する。
この下に Update Particle Strip をつなげ、最後に下にOutput Particle Strip line にすると、particleの移動に沿って軌跡がトレイルとしてつくことができる。
大体どんな使い方をしようとしても、ParticleStripはparticleの軌跡に出すことになると思うのでこの形になると思います。
ここから、initializeに InheritSourceColorを入れて親の色を軌跡に継承してみたりできる。
動きがつまらない場合は、UpdateParticleStripにTurbulenceを加え、出てきた軌跡がさらにアニメーションするなども可能。
そのまま消えるのが良くない場合は、OutputにmultiplyColorOverLife を入れ、白から黒に変わるようなGradationを入れる。
再説明。
元のParticleが動き、秒間60(ほぼ毎フレーム)イベントが発生。
それがsplitにコピーされ、コピーされた点を結んだ線となってRenderingされる。
コピーされた点はLifetimeで消えていくが、この秒数が大きくなればなるほどCapacityが必要になってくる。
そのCapacityを決めているのが、Particle per Strip Count。
Strip Capacityで線の本数、
線の中に何個Particleが存在できるかを決めるのがParticle per Strip Countで、
initialize Particle Strip の中で 1000×500 のParticleを管理している。
容易にデータが大きくなるので、ここの数値を増やしすぎないように注意が必要。
StripのRenderingはいくつか用意があり、
Output Particle Strip Quad にすると、幅を持ったラインで表現することもできる。
Set size を足して、太さの操作もできる。
テクスチャも変えられる。
Output Particle Strip Quadは、カメラの方を向いたラインを自動的に生成するため、どんなカメラ方向でも矛盾しない形で太さを持ったラインを引いてくれる。
Output Particle Strip Lit Quad にすると、ディレクショナルlightの方向や、Point light の位置で光を反映させたりすることができる。
Metallicやsmoothnessがはんえいできるため、金属みのあるリボンなども表現できる。
inspectorの cast shadows を入れれば、影の落ちた状態を作れる。
(PointLightのshadow map のEnableをOnにする)
inspectorのnormal Bending をOnにすると、見た目がチューブ状になるように法線を曲げてくれる。
KeijiroがVFXGraphのテストベットとして使っているリポジトリがある。
ここに、いくつかのサンプルを上げてあるため、使い方の例になる。
動画内の質疑応答まとめ
前半~休憩
質問:Outputにメタリックなどは使える?
→ 使える。
Output を Lit sphereにしてみる → 光の影響を受けず、黒い丸が出る
sceneのhierarchyにDirectional light を置く → 光の影響を受け、色が顕示される。
この状態であれば、SmoothnessやMetallicなどを使うことができる。
質問:ドキュメントが拡充されていない
→ 翻訳が追い付いていないので、英語のものをいったん翻訳しながら学習してください。
ウェブから入ったときに古いバージョンが表示されてしまうが、画面上部の青いボタンの”View latest version”を押すと最新のバージョンに切り替わる。
質問:nodeの整列はできる?
→ ない。スナップ等もない。
また、項目数が変わるとずれるため、たぶんなかなか作られない。
そのため、ある程度設定が固まったらグループ化・SUBGraph化(項目を選択し、Convert To Subgraph Operatorで保存)して整理すると良い。
■ lifetimeの乱数を強くする
Set Lifetime Random from Curve にしてみる。
右上がりのlinearにするとRandomConstantとあまり変わらないが、
急激なカーブでLifetimeが極端に長いゾーンを狭い幅で作ったりすると、大きく見た目が変わってわかりやすい。
質問:unityのCurveはどうやって受け渡しているの?
unityの場合、Curveの受け渡しは1次元テクスチャにベイクして渡している。
数式の場合フーリエ変換と同じように制度に限度があるため、画像にベイクしている。
数式の方がコンパクトだが、係数等の関係で再現怒涛に制限が出やすいため、少しデータが増えてしまうが自由度の高い画像へのベイクを採用している。
質問:今の画面のPostProcessは何がかかっている?
→ BloomやTonemappingのほかに、Keijiro作の Streak というものがかかっている。
これは、横方向に光が伸びるもの。
アナモーフィックレンズフレア といって、映画とかで使われているカメラレンズを使うとフレアが横方向に伸びる現象があり、映像作りでとりいれる人が多いのでそういうカスタムエフェクトを作って入れている。
なので単純にブルームで光る以上に、横方向にピカピカと光るエフェクトがつけてありますという感じですね。
Keijiroが作るカスタムエフェクトの公開場所は、すべてKino
というリポジトリに入れている。
これのほかに、グリッチFxなどもある。
質問:カスタムのHLSLのコードをノードとして使うことはできますか?
→ できるが、やらない方が良い。
Updateされた際に置換が手間なため、SubGraphを利用した方が良い。
質問:Set old position というAttributeはどう使うの?
→ 使わない。使い道はない。
1f前のポジションを使うことができる機能がだ、Setする意味がない。
また、custom Attribute 等があるため、OldPositionをこねくりまわして変数に使ったりはしない。
そのため、見る専用で使うことのないAttributeで、使い場所はない。
質問:SDF(Signed Distance Fields)をベイクするとき、いびつな形でベイクされてしまいますが、対処法は?
→ まず解像度を上げる、それで正しく出せるのであればそこから適切な解像度まで下げていく。
フーディニでDistanceFieldをベイクするときの話だと思うが、https://github.com/keijiro/VectorFieldExamplesのGifにあるように、フーディニ上でディスタンスフィールド焼き付けてVFXグラフで使うということができます。
ぶっちゃけ解像度を上げれば綺麗になるので、ディスタンスフィールドのボリュームデータの解像度を上げてくというのが回答になると思う。
ただし、解像度を上げれば上げるほどデータ構造が大きくなっていくので、むやみに上げることもできない。
質問:公式でSDFをベイクするツールを提供する予定はあるか?
→ フーディニのプラグインは配っている。unity上でベイクするツールは今のところ公式では予定していない。
質問:エフェクトの逆再生はできる?
→ 現状はできない。
質問:機能リクエストの方法は?
→ 各機能のフォーラムに質問スレッドがあるため、そこを使うのが良い。
質問:はじめてFxを置くと黒くなってしまうがどうしたら良い?
→ プロジェクトを作り、シーンを作り、シーンにdefaultのVFXGraphを置いてみても何も出ていないor真っ黒であれば、何かがバグっているため手順を見直してください。
質問:Particle同士の距離を計算することはできる?
→ できないと言っておく。
ParticleStripを除き、前に生まれたり隣にいるものなどを認識して挙動を変えるなどはできない。
質問:VFXGraphのカラー情報をShaderGraphに渡す方法が知りたい
→ GetColorからしてShaderGraphの引数に入れ直してください。
まず、ビジュアルエフェクトグラフでシェーダーグラフを使うことができます。
作り方は Create > Shader > VFXShaderGraph を選択し、ビジュアルエフェクトの中で使うシェーダーを定義することができる。
例えば、
カラーとかを作ってあげて、カラーを出力するだけの簡単なシェーダーを作ります。
これをVFXGraphのエフェクトで使おうと思ったら、作ったシェーダーグラフをOutputParticleQuadのShaderGraphに入れると、適用されて使えるようになる。
ここにパーティクルのカラーの情報を渡そうと思ったら、ちょっと面倒くさいが、一旦GetColorとかで現在のパーティクルの色情報を取得して、さっき作ったプロパティ(ShaderGraphを入れたブロックのColorにつなぐ)に入れてもらう必要がある。
これをしたうえで、Initialに SetColorRandom from Gradientなどを設定すれば、カラーが反映される。
やらせ質問:おすすめの椅子は?
→ スチールケースのオフィスチェアをunityで使っている。
高い椅子に座ると、グレードを落とすと勝てない。
後半~ラスト
質問:ユナイト東京2019でおっしゃっていた、自作で2次元テクスチャーにレイクスればいろいろ作れるというお話があったんですが、ベイクするテクスチャーの使用はどこを見ればわかるでしょう?
→ BAKEする手順については、
https://github.com/keijiro/Smrvfx の中のskinned mesh
を参考にするとよい。
のアニメーションしてるモデルの頂点情報を、テクスチャーにBAKEしてVFXグラフの中で使うっていうサンプルなんですが、テクスチャーにBAKEして渡す系のプラグインとしては一番これが単純な構造をしてると思います。
実際にsourceを見てみると、
- 本体のスクリプト:SkinnedMeshBaker.cs
- ユーティリティ:Utility.cs
- コンピュートシェーダー:SkinnedMeshBaker.compute
で構成されていて、すごくシンプルにできているので、このソースコードを見て実際どういうことをやってるのかっていうのを把握してもらうのが一番参考になると思います。
質問:Android向けのVFXグラフの動作は対応チップのコンピュートshaderの対応有無によってしまうのでしょうか?
→ VFXグラフのバージョンアップの度に試してはいるものの、少し古めの手持ちの端末では全く動作しません。
一応理屈としては、コンピュートシェードが動くスペックのAndroid端末であれば動きますよというふうに言ってはいるんですけれど、実際問題としては、やはりおっしゃられてるように動かない端末動かない環境っていうのが存在してしまっているようです。
将来的はその辺の問題も解決して、コンピュートシェーダーが動く端末であればここまでのビジュアルエフェクトは使えますという情報をまとめたいと思ってる。
(iOSは検証がしやすいため知見もたまっているが、androidは世界が広すぎて断定がしづらく対応が遅れがち)
質問:普通のParticleは1ポリで書いていると思うが、LineStripはどう描画されている?
→ scene viewのワイヤーフレームで見てみると、Particle1個1個が短冊1個1個を世話していてそれをStrip状につないでいっている感じ。
これで、カメラ方向を常に向くようにVFXGraphでお世話してくれている。
質問:ノードを置いていく際に、どのノードがどのくらいのパフォーマンスを食うというかの目安はあるんでしょうか?何かプロファイラーで見るとか。
→ 撮影当時は用意されていないが準備中。
at / set / Multiply / give などの基本的なオペレーションに関しては、ほとんど負荷は発生していない認識で良い。
一番負荷を発生させやすいのはnoiseのため、noiseを使用した複雑なシステムをなん十個も並べると思いだろうが、他はあまり気にしなくても良い。