Unity の VFX Graph で 3DGS シーンにエフェクトをつけて遊ぶ (SplatVFX)
はじめに
こちらは、xRギルド Advent Calendar 2024 22日目の記事です!(ちょっと遅れた!)
同アドカレ内にて zawazawa さんが 3D Gaussian Splatting (以下、3DGS) の記事を書いていたのに触発されて。少し前に遊んでみた「3DGS をベースにしたビジュアルエフェクト」について書きます。
概要
Unity における 3DGS のレンダリング手法といえば UnityGaussianSplatting が人気ですが、3DGS 表現を自由にカスタマイズしたい場合は Keijiro Takahashi 氏が公開してくださっている SplatVFX を使うと楽しいよ! というお話です。 本記事では、SplatVFX の使い方の説明をしたうえで、Visual Effect Graph (以下、VFX Graph) を編集して Luma 3D Capture のロード画面っぽい表現を目コピ した結果を紹介します。
今回自作した Luma 3D Capture 風のエフェクト
SplatVFX
SplatVFX は、Keijiro Takahashi 氏によって提供される、VFX Graph を用いた 3DGS レンダリングの実験的な実装 です。
README では以下のような注意書きがなされていて、 あくまでこの実装は実験に過ぎず完璧ではない ということらしいですが、
Is it ready for use?
No. I made many compromises to implement it with VFX Graph. I recommend trying other solutions like UnityGaussianSplatting.
(使用可能ですか?
いいえ。VFX Graph で実装するために多くの妥協をしました。UnityGaussianSplatting などの他のソリューションを試してみることをお勧めします。)
The Gaussian projection algorithm used in the VFX Graph is far from perfect. It causes many artifacts, including sudden pops with camera motion.
(VFX Graph で使用されるガウシアン投影アルゴリズムは完璧とは程遠く、カメラの動きによる突然のポップなど、多くのアーティファクトを引き起こします。)
Xなどでは、SplatVFX をもとにした 「リアルオブジェクト × VFX」の表現 がいくつか投稿されていて、大変 COOL です。触ってみる価値、大アリ!
サンプルを動かす
ということでひとまずサンプルプロジェクトを動かしてみましょう。
プロジェクトの起動
リポジトリをクローンします。リポジトリの中には、「HDRP」「URP」「VFX」の3つのプロジェクトが含まれていますが、ここでは 「VFX」プロジェクトを起動 します。
Assets/VFX.unity
シーンを開きます。しかし、このままでは実行しても何も表示されません。Hierarchy 上にある VFX
ゲームオブジェクトに .splat
ファイルを設定する 必要があります。
bicycle.splat
ファイルを設定して再生
SplatVFX リポジトリ内で案内されている bicycle.splat ファイルをダウンロードしてプロジェクトに追加してください。その後、VFX
ゲームオブジェクトの VFX Property Binder
コンポーネント内の Splat Data
の項目をクリックし、出てきた Splat Data
のフィールドに先ほどインポートした bicycle
を設定します。
そして、VFX
ゲームオブジェクトの有効無効を切り替えると、ビューに 3DGS シーンが適用されます。
そのまま実行ボタンを押すと、サンプルエフェクトが再生されます👏
.splat
ファイルを用意して再生
任意の bicycle.splat
以外の 3DGS シーンも表示してみましょう。
.splat
は WebGL Gaussian Splat Viewer 用の特殊なファイル形式ですが、.ply
形式の 3DGS 用データから比較的簡単に変換することができます。
.ply
→ .splat
の変換は、SuperSplat という Web ツールが便利なのでおすすめです。.ply
形式の Splat を削減・編集したのち .splat
形式でエクスポートできます。
変換元となる .ply
ファイルは、 Scaniverse や Luma 3D Capture などのスキャンアプリから出力できます。3DGS のリポジトリ(オリジナル) 内から Pre-trained Models (14GB) をダウンロードして使用してもよいでしょう。
変換した .splat
ファイルは、前節と同様の手順でプロジェクトに追加し、Splat Data
として設定してください。VFX
ゲームオブジェクトの有効無効を切り替えて Splat の表示を見てみると、変な位置にあることがわかりますが、これは VFX
ゲームオブジェクト自体の Transform が bicycle.splat
用に設定されているからです。
自前の 3DGS シーンに合わせて、位置を調整しましょう。(リアルタイムに位置が更新されないので、有効無効を切り替えて確認する必要があります。)
実行ボタンを押すと、自前の 3DGS シーンをベースにエフェクトが再生されます👏
エフェクトを作ってみる
最後に、自分でも VFX Graph をいじってエフェクトを作ってみます。
3DGS のカッチョイイ表現といえば、Luma 3D Capture のロード時のエフェクト。
Luma 3D Capture アプリ内のロードエフェクト
こちらを、SplatVFX を使って目コピ(雑) してみました。
SplatVFX を用いて再現したエフェクト
以下に実装の概要を示します。(そのうちプロジェクトごと公開するかも)
カメラの動き
回転運動や追従の動きを手早く実装するには、これまた Keijiro Takahashi 氏の ProceduralMotion が便利です。こちらを使用させていただきました。
VFX Graph の設定
Splat 表示用に独自の VFX Graph を作成するには、Packages/Splat VFX/VFX/Splat.vfx
ファイルをコピーして使用します。
今回の実装における、独自グラフ内の各ブロックの内容は以下のとおりです。
Initialize Particle
Initialize ブロックは、TargetSize
カスタムアトリビュートにサイズを保存するように追記したのみです。
Update Particle
プレーンな Splat.vfx
ファイルには Update ブロックが存在しないので、追加します。
Update ブロックでは、PointCloudProgress
SplatProgress
プロパティの値を受け、各パーティクルの中心からの距離に応じて PointCloudVisibility
アトリビュートと SplatVisibility
アトリビュートをアップデートします。(後者は、さらに SplatVisibilitySolid
SplatVisibilityFade
の2つに分け、あとで使いやすいように保持します。)
全体像
解像度が下がって詳細が見にくいので小分けにして載せます。
詳細: 左上グループ
詳細: 中央グループ
詳細: 左下グループ
詳細: アトリビュートの保持
これにより、PointCloudProgress
SplatProgress
プロパティの変化から各パーティクルの表示状態を決定し、見た目を切り替えられるようになります。
Output Particle
Output ブロックでは、各パーティクルの AxisX
AxisY
Size
Color
アトリビュートを設定して出力しています。
全体像
こちらも詳細が見にくいので小分けにして載せていきます。
AxisX
AxisY
SplatVFX では、AxisX
AxisY
アトリビュートを使ってパーティクルを引き伸ばしているようなので、PointCloudとして表示するタイミングではこれらの値をリセットし、かつカメラの方向を向ける必要があります。(Splat との軸合わせで VFX 本体にかけた回転も考慮する必要があり少々横長になりましたが、もう少し賢いやり方はあるのかも…。)
詳細: 上部グループ
Size
遠くのパーティクルが見えなくなってしまわないよう、距離に応じてサイズを調整するようにしたかったけれど、ひとまず割愛。
詳細: 中央部グループ
Color
境界部分に 1 以上の値を乗算してぼんやり明るくなるようにしています。(左の方でごちゃごちゃやっているのは見た目の調整。)
境界の判定には SplatVisibilitySolid
SplatVisibilityFade
カスタムアトリビュートの値を使用。
詳細: 下部グループ
完成!
あとは TimeLine でアニメーションのキーフレームを打てば、完成!
おわりに
VFX Graph × 3DGS の表現、まだまだいろいろ試せそうですよね!
モバイルARでも動くようなので、チャレンジしたい気持ち。何か知見が溜まったらまた記事にしようと思います。では👋
ボクセルっぽい表現も実験中
Discussion