はじめに
3D Gaussian Splatting(3DGS)をWebで表示する方法はいくつかありますが、Three.jsを使う場合はSparkというライブラリが広く使われています。
そのSparkのv2.0 Preview で、LoD(Level of Detail)機能が導入されました。点群数の多い重いデータでも、デバイスの性能や視点に応じて適切な粒度で表示できるようになり、大幅な軽量化を実現できます。
公式のデモで動作を体験できます。
大規模点群表示サンプル
ビューワー(自前の点群データがある場合)
本記事では、私が実際に試したSpark v2のLoD機能を活用する2つのアプローチを紹介します。
- 自動LoD作成 - データ読み込み時にその場でLoDを生成
- 事前ビルド方式 - rad形式で事前にLoDを含むデータを作成し、段階的ストリーミング
公式ドキュメント
本記事は、Sparkライブラリを使ったビューワーの構築については書いていません。SparkV2でのLoD機能の効果や使い方についてしぼって書いています。
方法① 自動LoD作成(簡単だが初回表示は遅い)
データ読み込み時にlod: trueフラグを指定するだけで、バックグラウンドWebWorkerで自動的にLoDバージョンを生成してくれます。
// lod: true を指定してLoD機能を有効化
const splats = new SplatMesh({ url: "./my-splats.spz", lod: true });
scene.add(splats);
バックグラウンドWebWorkerで処理されるため、ページがフリーズすることなく、裏で並行してLoD生成が進みます。
PLY、SOG、SPZなど主要な形式に対応していて、デバイスの性能に応じて点群数を自動調整してくれます。カメラに近い部分は高密度、遠い部分は低密度で表示する距離ベースのLoDも効いているので、SuperSplatなどの他のビューワーでは視点回転が重かった大規模点群データでも軽快に表示できました。
最大約3000万点群まで対応しています。それ以上の大規模データはメモリ不足やタイムアウトのリスクがあるため、方法②を推奨します。処理時間の目安は100万点群あたり1~3秒です(公式目安)。
ただし、LoDデータの生成に時間がかかるため初回表示が遅いのがデメリットです。バックグラウンド処理なのでページ操作は可能ですが、完全表示までは待たされます。
ユーザーがアップロードしたデータをその場で表示したい場合に向いています。
方法② rad形式の事前ビルド&段階的ストリーミング(推奨)
本番環境で固定のデータセットを使う場合は、rad形式で事前にLoDを含むデータを作成しておくと、高速な初回表示と段階的なストリーミングが可能になります!
rad形式は、複数のLoD(詳細レベル)を1つのファイルに内包したSparkの独自フォーマットです。低解像度から高解像度までの点群データが階層的に格納されていて、段階的な読み込みができます。
radデータの作り方
1. ビルドツールの入手
Sparkリポジトリのbuild-lodツール(Rust製)を使います。
2. radファイルの生成
# sogやplyをインプットとして変換処理
npm run build-lod -- my-splats.ply --quality
生成中はコンソールに進捗が表示されます。段階的にLoDデータを作っていることが分かります。
私の環境では500万点群で約5分程度かかりました。
3. Sparkビューワーでの読み込み
生成したradファイルを読み込みます。paged: trueフラグを追加すると、段階的に読み込まれます。
// paged: true で段階的ストリーミング
const splats = new SplatMesh({ url: "./my-splats-lod.rad", paged: true });
scene.add(splats);
最初はぼやけた低解像度から始まり、徐々に高解像度のデータが追加されていきます。
https://sparkjs.dev/2.0.0-preview/examples/#streaming-lod より
メリットとデメリット
メリットは、低解像度データから順次表示されるので初回表示が高速です(500万点群で約5秒)。最初はぼやけた表示から徐々に鮮明になっていきます。
デメリットとしては、データ更新のたびにradファイルを再生成する必要があることと、ストレージ容量です。
元データに加えて複数のLoDを含むため、ファイルサイズが大幅に増加します。
例:元の.sogファイル 58MB → 生成された.radファイル 263MB(約4.5倍)
サイト側で事前に用意した固定データを表示する場合や、初回表示速度を最優先したい場合に向いています。
詳細度のカスタマイズ(オプション)
デフォルトの表示点群数
LoD機能では、すべての点群を常に表示するのではなく、デバイスの性能に応じた「予算」内で最適な点群を選択して表示します。
設定しない場合、プラットフォームごとに自動設定されます。
| デバイス | 表示点群数 |
|---|---|
| デスクトップ | 250万 |
| iOS | 150万 |
| Android | 100万 |
| Vision Pro | 75万 |
| Oculus | 50万 |
例えば、500万点群のデータをデスクトップで表示する場合、実際に表示されるのは250万点群分です。残りは距離や視点に応じて適切に間引かれます。
おそらく、ノートPCも「デスクトップ」として扱われます。低スペックノートPCも、ハイエンドGPU搭載デスクトップPCも、デフォルトでは同じ250万点群が設定されます。
詳細度の調整
lodSplatScaleパラメータで、表示点群数の倍率を調整できます。
// デフォルト(1.0) - デスクトップで250万点群
renderer.lodSplatScale = 1.0;
// より詳細に(2.5) - デスクトップで625万点群(重くなる)
renderer.lodSplatScale = 2.5;
// より軽量に(0.5) - デスクトップで125万点群(軽い)
renderer.lodSplatScale = 0.5;
ユーザーに調整させる
公式のサンプルでは、lodSplatScaleを0.01~2.5の範囲でスライダー調整ができるようになっています。
また、起動時に品質を選択させるUIを提供しているビューワーもあります(例:SplatStroll Avatar)
このような選択肢で、低スペックPCでも快適に動作するようにすると親切かなと思います。
まとめ
Spark v2.0のLoD機能で、大規模な3DGSデータをWebで軽快に表示できるようになりました。
初回表示までの時間(500万点群での測定)
| 方法 | 表示開始までの時間 |
|---|---|
| rad形式(方法②) | 約5秒 ⚡ |
| SOG直接表示 | 約30秒 |
| SOG自動LoD作成(方法①) | 約60秒 |
※方法①の内訳:ファイル読み込み・パース(約30秒)+ WebWorkerでのLoD生成(約20~30秒)
表示のスムーズさ(視点操作時)
筆者のGPU搭載ノートPCでテストした結果、400万点群程度から顕著な差が現れました。
- Spark v2 - 視点回転・移動がスムーズ、カクつきなし
- SuperSplat - 視点操作時にフレームレートが低下、カクつきが発生




