Unity の VFX Graph で 3DGS シーンにエフェクトをつけて遊ぶ (SplatVFX)

2024/12/23に公開

はじめに

こちらは、xRギルド Advent Calendar 2024 22日目の記事です!(ちょっと遅れた!)
同アドカレ内にて zawazawa さんが 3D Gaussian Splatting (以下、3DGS) の記事を書いていたのに触発されて。少し前に遊んでみた「3DGS をベースにしたビジュアルエフェクト」について書きます。

概要

Unity における 3DGS のレンダリング手法といえば UnityGaussianSplatting が人気ですが、3DGS 表現を自由にカスタマイズしたい場合は Keijiro Takahashi 氏が公開してくださっている SplatVFX を使うと楽しいよ! というお話です。
https://x.com/_kzr/status/1714214841265856932
本記事では、SplatVFX の使い方の説明をしたうえで、Visual Effect Graph (以下、VFX Graph) を編集して Luma 3D Capture のロード画面っぽい表現を目コピ した結果を紹介します。


今回自作した Luma 3D Capture 風のエフェクト

SplatVFX

SplatVFX は、Keijiro Takahashi 氏によって提供される、VFX Graph を用いた 3DGS レンダリングの実験的な実装 です。

https://github.com/keijiro/SplatVFX

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 です。触ってみる価値、大アリ!

https://x.com/gradeeterna/status/1823098278654742561
https://x.com/KzoNag/status/1771864618077450511
https://x.com/smallfly/status/1724259332412317818

サンプルを動かす

ということでひとまずサンプルプロジェクトを動かしてみましょう。

プロジェクトの起動

リポジトリをクローンします。リポジトリの中には、「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 シーンも表示してみましょう。

.splatWebGL Gaussian Splat Viewer 用の特殊なファイル形式ですが、.ply 形式の 3DGS 用データから比較的簡単に変換することができます。

.ply.splat の変換は、SuperSplat という Web ツールが便利なのでおすすめです。.ply 形式の Splat を削減・編集したのち .splat 形式でエクスポートできます。

https://playcanvas.com/supersplat/editor/

変換元となる .ply ファイルは、 ScaniverseLuma 3D Capture などのスキャンアプリから出力できます。3DGS のリポジトリ(オリジナル) 内から Pre-trained Models (14GB) をダウンロードして使用してもよいでしょう。

https://github.com/graphdeco-inria/gaussian-splatting

変換した .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 が便利です。こちらを使用させていただきました。

https://github.com/keijiro/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でも動くようなので、チャレンジしたい気持ち。何か知見が溜まったらまた記事にしようと思います。では👋


ボクセルっぽい表現も実験中
https://x.com/by_BISON/status/1728252876731146396
https://x.com/by_BISON/status/1731236603396522238
https://x.com/by_BISON/status/1731237414109339958

Discussion