【Unity】VRゴーグルにGaussianSplattingデータを出す【slapsplat】

# はじめに
ここ最近、GaussianSplattingが急激に話題になっています。  
NianticがリリースしているScaniverseでもSplatでのスキャンを前面に押し出しており、  
撮影環境やスキャン速度、結像精度などがどんどん向上しています。  

しかし、GaussianSplattingで撮影したデータは実は行き先があまり揃っておらず  
スキャンしてもデータを持て余すことが多々あります。  
（スキャンしてないから持て余してない？そうね、、、）  

そんな中、GaussianSplattingをVRChatで表示できるShader`slapsplat`が登場しました。  

https://github.com/cnlohr/slapsplat 

今回は`slapsplat`をカスタマイズして、VRChat内ではなくVRゴーグル単体アプリとして  
手軽にGaussianSplattingを表示できるようにしてみました。  

# TL;DR
手順書は↓こちらにもあります。

https://github.com/GONBEEEproject/slapsplat_G 


# slapsplatとは？
[cnlohr](https://github.com/cnlohr)氏が公開しているVRChatワールド制作向けのShaderで、  
AudioLinkやTexel Video Playerなど、VRChat向け機能との連携が強い「映えシェーダー」です。  
VRChatサンプルワールドはこちら↓  

https://vrchat.com/home/world/wrld_0ced80f6-29f7-4310-be6a-342eaf80c2ca

「VRChat向け機能との連携が強い」というのは逆に言うと、  
**VRChat以外だと使いにくい**という意味でもあります。  
そこで今回はVRChat向け機能を廃し、  
**ただUnityでGaussianSplattingを表示するためのShader**として
.cgincや.shaderの最適化を行いました。

## slapsplat_G
~~後ろにGをつけただけの安直なネーミング~~
ファイル構成の最適化を行った結果、Shaderの構成要素が2ファイルのみになりました。  
一応リポジトリ内にサンプルも入っているので、クローンすればいつでも見られます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241210/b60957b5-9c54-bbb7-668f-48951f2ff495.png" width=50%>


# 実装手順  
実際にUnity新規Projectにインポートし表示するまでの手順です。

## 0.UnityPackageインポート
[リリースページ](https://github.com/GONBEEEproject/slapsplat_G/releases)から最新の.unitypackageをダウンロードし、プロジェクトに展開します。  
サンプルデータ入りのため80MB近くと大きめですがご了承ください。  
Shaderのみのため、Unityのバージョン依存はありません。  

## 1.plyデータの変換
.plyファイルをUnityで描画する用の各種.assetに変換します。  
変換用ツールが`slapsplat_G/process/`下にありますので、  
リポジトリをCloneするか、Zipダウンロードしておいてください。

`process`ディレクトリに移動し、コマンドラインで`CreateSplatAssets.bat`を利用します。  
同じディレクトリ内にplyデータを配置し、以下のようにコマンドを叩きます。  
（以下sample.plyというファイル名だった場合のコマンド・出力結果です）
```
CreateSplatAssets.bat sample.ply
```
生成に成功すると`sample_result`フォルダ内に各種アセットが保存されます。  
このフォルダごとUnityにインポートしましょう。

## 2.UnityでMaterialを作る
Material作成後、Shader選択で`SlapSplat_G/SlapSplat_G`を選択し、  
`Geo Data` `Order Data`にそれぞれ  
出力データフォルダ下にある`sample_geo` `sample_order`を適用します。
<img src="https://github.com/user-attachments/assets/e795f819-0500-46c4-9f70-cac3766bcaf3" width=50%>


### 詳細パラメータについて
テクスチャを適用したら下にある各種パラメータを調整していきます。  
後述のシーン配置後に画面を見ながら調整しましょう。  

#### Custom Scale
GaussianSplattingの1カケラの大きさを調整できます。  
0.9～1.1くらいがちょうどいい気がします。（物による）  
（少なくともNerfStudio/SplatFactoからそのまま出力した車両GSデータとしては、  
　1.1くらいでちょうどよさそう）  

#### gamma
ガンマ値です。基本的に1で大丈夫です。

#### emission amount 
カケラ自体の発光度合いです。  
下記の`brightness`とセットで調整になりますが、  
**emissionをブチ上げてbrightnessを下げる**とplyの元データのライティングに近くなります。

#### brightness
全体の発光度合いです。  
こちらは0.1～0.3程度に抑えて、`emission amount`で調整すると意図した描画になりやすい気がします。


#### 余談：geoとorder
一応それぞれのテクスチャファイルの中身ですが、slapsplat元リポジトリによると  
`geometry`テクスチャがXYZ座標、XYZスケール、XYZ回転、色の情報を持っており、  
`order`テクスチャはレンダリングの最適化用で、奥行き方向の情報を早期に検出し、  
裏側に存在するGaussianSplattingを描画しないために使っている模様です。  
> because otherwise there would be far too much overdraw to be practical.
> そうしないとオーバードローが多すぎて使い物にならないためです。


## 3.シーンに配置する
`sample_result`フォルダ内にある`sample_mesh`をシーンにD&Dすると  
`MeshFilter`と`MeshRenderer`を持つオブジェクトが生成されます。  
そのままの状態では何もレンダリングされていませんが、  
`MeshRenderer`に上で作ったMaterialを与えるとシーンに描画されます。  

<img src="https://github.com/user-attachments/assets/5fe5ccce-2181-4384-9c62-a06dc1dda50e" width=80%>


## 4.各種パラメータ調整
あとはSceneビューに描画されているGaussianSplattingデータの明るさや、  
カケラの大きさなどを調整し、意図通りの描画になるようにMaterialを調整します。  
前述のemissionとbrightnessの関係に関しては恐らくケースバイケースなので、  
色々いじってみてください。


## 5.VRゴーグル（Meta Quest 3）で表示
シーンに表示さえ出来ればQuest3に持っていくのはそこまで難しくはありません。  
（OVRCameraRigを持ってくるまでは[他の記事を参照ください](https://tech.framesynthesis.co.jp/unity/metaquest/)）

VRゴーグルで扱う場合の唯一の注意点として、  
このShaderは**Single Pass Instancedに対応していません。**
上部メニュー/Edit/Project Settings/XR Plug-in Management/OpenXRから  
`Render Mode`を`Multi-pass`に変更してください。  
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241210/441a51e0-d433-7ab6-73ad-d3fc67d364a8.png" width=80%>

あとはよしなにビルドして、Quest3に展開したら  
いつでも家の中でGaussianSplattingモデルを眺め回せるアプリの完成です。  

# 完成！&おわりに

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">パススルーで家の中にGR86のGaussianSplattingモデル出せた～～～！！！<br>しかも軽～～～い！！<br>（実寸大でデカいので壁の向こう側に置いてる）<br><br>今Qiita記事書いてるんで、みんなやってみてね <a href="https://t.co/iuh8TlWl2p">pic.twitter.com/iuh8TlWl2p</a></p>&mdash; ごんびぃーᯅ@XR開発者集会 (@GONBEEE_project) <a href="https://twitter.com/GONBEEE_project/status/1848038442640572645?ref_src=twsrc%5Etfw">October 20, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

GaussianSplattingはまだ未発達の領域で、スキャン自体も難しい（？）し  
結像にはだいぶ強いGPUが必要ですし、結像できたとて出口の少ないデータ形式です。  
そんな中で手軽にUnityで表示できるようにしてくれたslapsplatはかなりの偉業だと思います。  

ただガウス分布を半透明ではなく全面レンダリングしてしまっているため、  
GaussianSplatting特有の「リアルな写真っぽい描写」にはまだ及ばないかなという状態です。  
この分野は発達の著しい領域なので、将来的にはVRゴーグルでも  
超キレイなGaussianSplattingモデルを見られる日が来るかもしれませんね。  
（半透明重すぎるから、何かブレイクスルーが無いとキツい気はする）  

最後まで読んでいただきありがとうございました。  
もし記事内で分からないことや間違っている部分がありましたら、  
コメント欄か[ごんびぃー](https://twitter.com/GONBEEE_project)までご連絡をいただければと思います。