UE5 向けの NiagaraSystem アセットである Anime Aura VFX についての技術解説です。 第1回 Anime Aura VFX の原理 今回はパーティクルの位置を用いて2次元の濃度マップを作製するプロセスについての説明です。 パーティクル以外のパーティクル Set では上から順に、 のようなものの初期状態を決めています。 このエミッターはパーティクルを一切発生させないため、ParticleSpawn / ParticleUpdate ではほぼ何もせずに SimulationStage の処理に入ります。 ScalarFieldGrid のうち、現フレームの情報を書き込む部分を 0 クリアします。 Grid2D について DrawArray / DrawBones / DrawParticle の作用は殆ど同じで、 以下が NM Bones to Scalar Field モジュールのグラフです。 長いコードではありませんが変数の命名がけっこう適当かつコメントが無いので読みづらいかもしれません。 繰り返しになりますが、ScalarFieldGrid の1ピクセル(仮)につき一度このコードが実行されます。 以下に概念図を載せます。 上記の処理で作成されたマップを、「流れ」を加えつつ直前のマップと合成します。 処理の内容を図で表すと以下のような感じです。 Grid2D はテクスチャではないのでそのままではマテリアルに渡せません。 NiagaraSystem を用いてパーティクル(+SkeletalMesh)から2次元のテクスチャ(濃度マップ)を生成するプロセスについて説明しました。概要 この記事について
全3回に分けての解説を予定しています(これはボリューム等を見て変更する可能性があります)。
第2回 パーティクルの投影(本記事)
第3回 濃度マップ→表現
以下の知識を必要とする部分があります。読み進める中で詰まる場合は適宜ほかの資料で補うなどしてください。
Aura VFX NiagaraSystem 全体図
Anime Aura VFX には多くの NiagaraSystem が含まれますが、殆ど全てについて構造は共通しています。
左側の Emitter がパーティクル発生、右側が投影とスプライト表示を担います。パーティクルを発生させる
こちらはごく一般的な Emitter とあまり変わりません。
パーティクルを直接表示しないため、Renderer が無効になっています(有効化するとパーティクルの振る舞いを確認できます)。
キャラクターにまとわせるエフェクトですので、発生位置に SkeletalMeshLocation を用いています。
ここでパーティクルの発生量や位置・速度を制御することでオーラの挙動を変えることができます。
このシステムはGPUでの処理がやや複雑なものですので、パーティクルの数を極力抑えたいのが実情です。
投影処理においては上記のエミッターで発生させたパーティクルの他に、
SkeletalMesh のボーンの位置を「大きいパーティクル」のように扱います。
ボーン由来のパーティクルでオーラの概形を決め、実際のパーティクルで「揺らぎ」を作るような形をとっています。パーティクルの位置を投影する
右側です。本システムの特徴からすると、こちらのエミッターが本体と言えるでしょう。
エミッター(放出するもの)と言いながらパーティクルを一切生成しないのが少し変わったところです。
コメントを付けている部分(DrawArray/DrawBones/DrawParticles)が実際に投影を行っている部分ですが、初期化から順を追って説明していきます。Emitter Spawn
エミッター内で使用するパラメータはここで初期化されます。
さいごに、NM Set Grid Size では ScalarFieldGrid のサイズを決定します。投影処理
上から順に説明していきます。
Clear Working Buffer
ここで ScalarFieldGrid(Grid2D)について触れておきます。
ScalarFieldGrid は Grid2D という型を持ちますが、これは2次元配列状の構造を持ったデータです。
「ピクセルのフォーマットを自由に設定できるテクスチャ」のように考えればイメージとしては大体合っている気がします。
実際、NiagaraEditor の中では Grid2D の値をテクスチャのような感じでプレビューが可能です。
プレビューの様子。
ScalarFieldGrid には
* 1フレーム分のデータを書き込む WorkingBuffer
* フレームを跨いで WorkingBuffer を合成して得る ScalarValue
という二つのスカラー値を保存していますので、二枚の画像を並べたように表示されます。DrawXXX
元となる(仮想的な)パーティクルの位置情報がそれぞれ 「決められたベクトル配列(多分あまり使わない)」「SkeletalMesh から得るボーン位置」「パーティクルの位置」 という違いがあるくらいです。
これらは、パーティクルの位置をスプライトの平面上へ投影して ScalarFieldGrid への書き込みを行います。
ここでは DrawBones を取り上げて説明します。準備
グラフに入る前にモジュールの設定です。
Niagara SimulationStage では「何らかのデータ集合に対して繰り返し処理を行う」ことができます。
何らかのデータ集合とはパーティクルであったりそれ以外(テクスチャ や Grid2D)であったりします。
画像中の Iteration Source に「何について繰り返すか」を指定します。
ここでは Iteration Source として ScalarFieldGrid (Grid2D)を用います。
そうすると、モジュールのグラフ(から生成されるシェーダーコード)が ScalarFieldGrid の各要素(ピクセル的なもの)に対して実行されることになります。計算
Niagara Module においてはわりとよくあることかと思いますが、主要な計算はHLSL コードの部分で行われます。
以下がその部分を拡大したものです。
ですので補助線として変数の意味を幾つか書いておきます:
Num:パーティクル数
LocalTarget:ピクセル(仮)のローカル座標(スプライト中心を基準とした平面上の座標)
Projected:スプライト上に投影された座標(ワールド)
LocalPos:それをローカルに変換したもの
TmpPower:そのパーティクルにより生じる"濃度"
内容としては、全てのパーティクル(ここではボーンですが)についてスプライト平面への投影を行いピクセル(仮)との距離から濃度を算出して足し込んでゆくようになっています。
遠近法も適用され、カメラの近いパーティクルほど大きく描かれることになります。
0/1 ではなく、パーティクルが投影される位置がピクセル(仮)に近いほど濃く塗るようにしてグラデーションを作ります。
いわゆる2Dメタボールと同じような考え方ですので、このワードで検索してみると理解が捗るかもしれません。
このようにして、下の画像の左側のようなマップが作成されます。
Mix
画像左のマップを少しずつずらしつつ薄めながら足していくことを繰り返して右のマップを得ます。
CopyToRenderTarget
ここで ScalarFieldGrid から、統合後のマップを RenderTarget へコピーします。
右下がコピー元(統合されたマップ)、左上が結果の RenderTarget です。
もののついでに周辺部をフェードアウトさせる処理を行っています。まとめ
Anime Aura VFX には色々な見た目のエフェクトが含まれていますが実はここまでの部分は殆ど共通しており、多少パラメータが異なるくらいです。
出来上がった濃度マップを用いてどのように処理するかによって様々な外観を作り出すことが可能となっています。
次回はそちらについて解説する予定です。