どうも、ラブヘイトです。
ここ最近Unity Visual Effect Graph(以下 VFX)にハマっておりまして、様々な動画をみています。
学習のためにも実際にサンプルの中身覗いてみるか!と思い開いた訳ですが......
見る気がなくなるノード構成、意味わかりません。見るだけでなく、1からサンプルと同じようにも作ってもみました。
もちろん同じように動きましたが、どうしてそうなっているのか、何を意図してそのノード構成になったのか全くわからないので、今回はサンプルVFXについて徹底解剖して行こうかなと思います。最初はPortal!
知らないことが多いので、長くなること間違いなし!
サンプルは以下からダウンロードやクローンできます。
https://github.com/Unity-Technologies/VisualEffectGraph-Samples
一応グループ分けされているので、ノードグループごとにどんな役割でどういう計算をしているか、解説していきます。
※リファレンスが存在しない部分は自分が実際に動かしみて、機能を推測している部分もあります。
- 環境
- Wobby Outline
- Source Torus
- Compose Initial Brighness(into Color)
- Compose Velocity(ベクトルの大きさ)
- Pulse rotation Mask
- Particle-To-Center Vector(World)
- Compose Velocity(ベクトル向き)
- Expel Particles on Z Axis based on Wobbly offset
- Get Torus Tangent
- Randomize tangent
- Categorize Particles/Height Mask
- Noise Intensity over Life and elevation
- Cancel Gravity
- その他ノード
- まとめ
環境
Unity 2019.3.3f1
HDRP 7.3.1
Visual Effect Graph 7.3.1
Wobby Outline
このグループの出力は最終的に、Initialize Particle>Add Position from Map>Sample Position
に繋がります
Add Position from Map
Wobbly Outlineを説明する前に、最終接続先である曲者Add Position from Mapについて説明します。
まずこちらノードは検索で出てきません。Set Position from Mapを作成し、InspectorのCompositionをAddに変更することでノード名が変化します。
Add Position NodeはSetしたPositionに位置情報を加算します。
Add Positionを行うと何も設定していなくても、Torusから外れた位置に加算されてしまいます。
Value Biasを「-0.5」に統一するとSetしたPositionの位置に表示されるので、
Add Posisionで必ず初手に行う設定になります。(わかるか!)
そして本題のWobbly Outlineグループが最終的に何をしたいかと言うと、アニメーションした先の、円のアウトラインを歪める表現を行っています。
※わかりやすく別の効果は切ってあります。
Wobbly Outline(計算)
それではやっとWobbly Outlineの中身についてです。上下に分けて説明します。
上2つのノードはパーティクルのPositionと0.34をMultply。0.34はアウトラインの歪み具合なので、この値を増減させることで歪み幅を調節できます。
動的に値が変化するノードはTotal time。これによってアニメーションが実現可能です。
Total Timeはパーティクルごとのデルタタイムで変化していくノード。
Vector3[0,-1,0]の部分で、y軸のみ変化させるように設定しています。
つまりこのグループノードが示していることは、現在のPositionとTotal timeを掛け合わせ、Add Position>Sample Position
に接続すると揺れるアニメーションができると言うことです。調節で多くのノードを配置しているだけで、ほぼ同じ表現をするのに最低限必要なノードはこれだけです。
音ゲーのエフェクトとかに使えそうですね
Source Torus
Initialize Particle>Arc Torus
に遠くから接続されているSource Torusというノードが存在します。これは正しくは、Arc Torusノードで、Sorce Torusと名前を付けたプロパティです。
Torusの半径や位置を簡単にInspectorから編集するためにこのような接続方法になっています。
Compose Initial Brighness(into Color)
これはNodeグループというかただのCurveですが、気になるのはグループのタイトル
初期輝度という意味なので、つまりHDR。
接続先がSet Colorなので、やっていることはわかりますが、その接続方法だけでHDRだけを制御できるの?って話です。
試しにSet ColorにfloatとVector3で入力型を変更してみました。
入力がfloatなら、輝度のみ。Vector3なら色を制御できるみたいです。
これはなんとなく予想できたけど、やっぱり入力型で役割違うのか!奥が深い!
Compose Velocity(ベクトルの大きさ)
このノードグループは様々なノード出力の接続先になっていて一見複雑そうに見えますが、
多分計算ノードが多いからそう見えるだけだなと思います。
Velocityの要素は2つに分けることができて、方向と大きさに分けることができます。この2つを分けて説明していきます。
まずはベクトルの大きさを決めているノードから
Random Numberはその名の通り指定した最小最大の中でランダムな値を出力します。
サンプルでは0.8から2.0の間で速さをランダムで出力しているので、大きく飛び散るもの、小さく飛び散るものがあっていい感じです。
以下Random Number[0.8,2.0](左)と[2.0,2.0](右)で比較した時の画像です。
エフェクトはランダム性があるほどいいですよね。
次、Sample Curve>Time
に他のグループから接続されているので、Timeの値によってベクトルの大きさが変化していきます。
ここで一旦Compose Velocityの他の要素は置いといて、Sample Curve>Time
への接続元である、Pulse rotation Maskグループから解明していこうと思います。
Pulse rotation Mask
Rectangular to Polar
Rectangular to Polarノードはxとyから極座標を求めます。
極座標とはr(動径)とシータ(θ)で点の位置を表す座標です。サンプルでは最終的にシータのみ扱ってます。Angle on TorusグループではTimeとSpeedを掛け合わせてるだけなので、
Remapノードまでを式に表すとこんな感じでしょうか(多分あってると思います)
{(Time * Speed+xθ) % 2π}/2π
Moduloノードは余りを出力するのですが、正直計算式をみても意図が読み取れませんでしたが、θが変化した時の値を追っていくと
グラフにしたら以下のようになります。
このグラフとパルスというグループ名から、円周用パルス信号だと推測しました。
3°ごとにVelocityの大きさが最大になるということがわかります。
ただ、Shader GraphみたいにWaveノードがあればこんなに複雑にならないのでは?と思いましたが、VFXの方には実装されていないみたいです。
Particle-To-Center Vector(World)
このグループでは円の中心とパーティクル座標の差をオフセットとして取得しています。
出力はRectangular to Polarノード
に接続されています。
これで、velocityのベクトルの大きさを決定するノード解説は終わりました。
次はベクトルの向きです。
Compose Velocity(ベクトル向き)
またCompose Velocityに戻って、力の加わる向きについて追っていこうと思います。
ノード内でいうと黄色の接続がVectorなので黄色線を追うとわかりやすいです。
このグループノードではAddしているだけなので、一旦置いときます。
一旦Vectorノードに置き換えている理由は、グループにした時にわかりやすくするためだと思います。
Expel Particles on Z Axis based on Wobbly offset
このグループはパーティクルのローカルZ軸に力を加えます。横からPortalを見て、接続を外してみるとわかります。
ただ、Change Spaceノードでワールドからローカルに変更している意図はわかりませんでした。あってもなくても変化は見られない......。グループ名もよくわかりません。
ここではChange SpaceノードでWorld to Localが出来ることを覚えていればいいでしょう。
Get Torus Tangent
円の接線を取得するノードグループです。
Cross Product
2つのベクトルのベクトル積を計算します。私も詳しいことは知りません。さっき調べました。
Cross ProductからNormalizeノードでなぜ円の接線が取得できるのか、わかりやすく円周上の4つのポイントで考えていきます。
前提は以下です
Torusの中心:(0, 1.07, 0)
TorusのMajor Radius:1
このようにどの位置にいてもベクトルが円の接線上にあることがわかります。これ再現できる人すごいな.......
方向を逆にするにはCross Productを(0, 0, -1)にすればいいと思います。
Random Numberはベクトルの大きさを調節できます。Compose VelocityグループのRandom Numberとの違いはよくわからなかったです。
この接線上のベクトルは次のRandomize tangentグループに渡されます。
Randomize tangent
このノードグループで、先ほど求めた接線上のベクトル方向をランダムに傾けています。
Rotate 3D
Position:velocityを入れます
Rotation Center:TorusのCenter
Rotation Axis:回転させる軸です。(サンプルではZ軸回転)
Angle :Rotateさせる量
傾け方もランダムになっています。
ここまできてようやくVelocityが終わりました、あと少しです。
Categorize Particles/Height Mask
ここで行っていることはHeight Mask(高さの閾値)を設定して、一定以上の高さでパーティクルの生存時間を分岐させています。一定以上と言っているもののRandom Number多用してて閾値の実態が掴めないところがなんともわかりづらいです。
Noise Intensity over Life and elevation
Lifetimeの後半で大きく力が加わるようになっています。ここでもHeight Maskから値を取得しています。
Cancel Gravity
Gravityを切っていたので忘れていました。このグループでは、particleのY軸が0.02より大きい時は重力を与え、そうでない時は0にしています。ポータルの下部は重力の影響を受けていません。
その他ノード
あとはコンテキスト内のなんだこれって思ったノードを調べます。
Set Mass Random
リファレンスには載ってなかったです。MassはRigidbodyで出てくる質量のことなので、パーティクル一つ一つの質量をランダムにしているという推測です。
Linear Drag
オブジェクトの移動による物理計算を考慮するかどうかです。普通のパーティクルでもそんな設定項目があった気がします。
比較も作成したのですが、VFXはgifで載せるとわかりづらいのでやめときます。
Orient Along Velocity
意外と大切なノードで、Velocityの方向にParticleを引き伸ばしてレンダリングします。
このノードがないと結構ダサいことになります。
まとめ
色々調べた結果、ノードリファレンスはVisual effect graph 7.0以降更新させてないみたいです。なのでそれ以降に追加されたノードは公式の説明がない状態でわからないことも多いです。
学べることは多かったですが、文量も多いので第2弾やるかは微妙なところ
早く自分で色々作れるようになりたいぜ!
一番最初に添付した画像ですが、ポータルの中身をShader Graphと組み合わせて歪ませてみました。あとはポータルの中に違う風景を映し込めたら最高ですね!
HDRPで歪ませるShader Graphを作成する方法はこちら
【Shader Graphに入門してみた】HDRPで歪み表現 3日目 - うにty生活
今回最長です。5500文字、頑張った。
それではまた