SuperSplatをローカルに持ってきて、Splatを処理し、WebXRで可視化する妄想(Kaleido連携も視野に)

ここでは、PlayCanvasの SuperSplat Editor をローカルで動かし、必要に応じて
SplatTransform CLI で変換・圧縮・間引き・衝突データ生成を行い、
SuperSplat Viewer またはエディタ書き出しHTMLを使ってWebXR対応ビューアとして公開するまでを妄想する。
作成日: 2026-05-27 / 想定環境: Ubuntu 24.04 または Windows + Node.js 18以上 / 公開先: Nginx, Flask, GitHub Pages, 社内サーバー
1. 全体像:最短構成と実運用構成
まず結論。SuperSplat単体を「処理エンジン」と考えるより、Editor・CLI・Viewerを分けるのが正解に近い。
Editorは視覚的な削除・調整に強く、CLIは大量処理・変換・間引き・衝突データ生成に強い。
ViewerはWebページとして配信し、WebXR対応端末ならAR/VR表示に進める。
SuperSplat Editorを起動 → PLYを読み込み →
File > Export > Viewer App… →ZIPで出力 →
python -m http.server で開く。これで通常ブラウザ表示は試せる。WebXRまで行くなら、端末からアクセスできるHTTPS配信がほぼ必須。
2. 使うものの役割
SuperSplat Editor
3D Gaussian Splatの読み込み、確認、編集、最適化、公開・書き出しを行うブラウザベースのエディタ。
視覚編集トリミングViewer書き出し
SplatTransform
CLIまたはライブラリとして使える変換・処理ツール。PLY、SOG、SPZ、SPLAT、KSPLATなどを扱い、SOG化、間引き、回転、スケール、衝突用Voxel生成などに使う。
CLI処理SOG圧縮衝突データ
SuperSplat Viewer
自前Webサイトに組み込む表示ランタイム。Splatファイルとsettings.jsonを読み、注釈、アニメーション、WebXR対応表示を行う。
Web表示WebXR自前配信
| やりたいこと | 使うもの | 理由 |
|---|---|---|
| PLYを手で見ながら不要部分を消す | SuperSplat Editor | 視覚的に編集できるため。現場データの掃除に向く。 |
| 大量ファイルを一括で圧縮・変換する | SplatTransform | CLI化できるため。案件DBやバッチ処理に載せやすい。 |
| WebページにSplatを埋め込む | SuperSplat Viewer | 静的Webアプリとして配信でき、URLパラメータやsettings.jsonで制御できる。 |
| QuestやAndroidでAR/VR表示する | SuperSplat Viewer + HTTPS | WebXRは対応ブラウザ・対応端末・安全なコンテキストが必要。 |
3. SuperSplat Editorをローカルに持ってくる
公式READMEでは、Node.js 18以上を前提に、GitHubからクローンして npm install、npm run develop で
http://localhost:3000 を開く流れになっている。
Ubuntu / WSL / macOS
# Node.js 18以上を確認
node -v
npm -v
# リポジトリ取得
git clone https://github.com/playcanvas/supersplat.git
cd supersplat
# 依存関係インストール
npm install
# 開発サーバー起動
npm run develop
# ブラウザで開く
# http://localhost:3000
Windows PowerShell
git clone https://github.com/playcanvas/supersplat.git
cd supersplat
npm install
npm run develop
SuperSplatはWebアプリなので、Service Workerやブラウザキャッシュが残ることがある。
表示が古い、変更が反映されない、ロードがおかしい場合は、Chrome DevToolsのApplication → Service Workersで
“Update on reload” や “Bypass for network” を有効化し、キャッシュを消す。
読み込むファイル
代表的には .ply を読み込む。ほかの形式から来たデータは、先にSplatTransformでPLYやSOGへ変換しておくと扱いやすい。
4. SplatTransformでSplatを処理する
実運用では、Editorで全部やろうとしない方がよい。
案件単位・現場単位で処理を自動化するなら、SplatTransformを入れてCLI処理に回す。
インストール
npm install -g @playcanvas/splat-transform
# 動作確認
splat-transform --version
splat-transform --help
基本変換
# PLY → compressed PLY
splat-transform input.ply output.compressed.ply
# PLY → SOG。Web配信向けの圧縮形式として扱いやすい
splat-transform input.ply output.sog
# compressed PLY → 通常PLYへ戻す
splat-transform input.compressed.ply output.ply
# PLY → 単体HTML Viewer
splat-transform input.ply output.html
# PLY → 分離型HTML Viewer。CSS/JS/SOGを別ファイルにする
splat-transform -U input.ply output.html
軽量化・掃除
# NaNやInfを含む壊れたGaussianを除去
splat-transform input.ply --filter-nan clean.ply
# 25%だけ残して軽量化
splat-transform input.ply -F 25% decimated.ply
# 50,000個に間引く
splat-transform input.ply --decimate 50000 decimated_50k.ply
# 透明度が低いものを落とす例
splat-transform input.ply -V opacity,gt,0.5 opacity_filtered.ply
# 球面調和関数の高次成分を落として軽くする
splat-transform input.ply --filter-harmonics 2 harmonics2.ply
座標変換・統合
# スケール調整
splat-transform input.ply -s 0.5 scaled.ply
# 平行移動
splat-transform input.ply -t 0,0,10 translated.ply
# Y軸まわりに90度回転
splat-transform input.ply -r 0,90,0 rotated.ply
# 複数Splatを統合
splat-transform sceneA.ply sceneB.ply merged.ply
歩行モード用の衝突データを作る
WebXRや一人称ウォークを考えるなら、見た目のSplatとは別に衝突データが必要になる。
SplatTransformは .voxel.json や衝突メッシュの生成に使える。
# 屋内シーン例
splat-transform room.ply \
--filter-cluster --seed-pos 0,1,0 \
--voxel-external-fill --voxel-carve \
-K room.voxel.json
# 屋外・地形シーン例
splat-transform terrain.ply \
--filter-cluster --seed-pos 0,0,0 \
--voxel-floor-fill \
-K terrain.voxel.json
--seed-pos は「ここが歩ける・中心にしたい」という点を指定する。現場空間の場合は、入口付近や通路中央など、確実に空間内部にある座標を選ぶ。
ここを外すと、必要なクラスタまで消える。便利だが、切れ味のよすぎる包丁。
5. Viewerとして書き出す
A. Editorから書き出す
SuperSplat Editorで編集後、以下の操作でビューアを書き出す。
Fileを開くExportサブメニューを開くViewer App…を選ぶ- HTML単体またはZIP Packageを選択する
| 形式 | 特徴 | 向いている用途 |
|---|---|---|
| HTML単体 | SplatがBase64でHTML内に埋め込まれる。ダブルクリックで開きやすいが、Base64化でサイズが増える。 | 小さなデモ、メール添付、USB渡し |
| ZIP Package | HTMLと .compressed.ply などを分離。軽く、ロードしやすいがHTTPサーバー配信が必要。 |
Web公開、Nginx配信、Flask組み込み、実運用 |
B. CLIからHTML Viewerを書き出す
# 単体HTML
splat-transform input.ply output.html
# 分離型HTML
splat-transform -U input.ply output.html
# settings.jsonを使ってビューア設定込みで出す
splat-transform -E settings.json input.ply output.html
C. supersplat-viewerをnpmで組み込む
自前Webアプリに組み込む場合は、@playcanvas/supersplat-viewer を使う。
パッケージはViewerの index.html、index.css、index.js を文字列として取り出せる。
npm install @playcanvas/supersplat-viewer
import { html, css, js } from '@playcanvas/supersplat-viewer';
console.log(html);
console.log(css);
console.log(js);
settings.jsonの最小例
ViewerはSplat本体とは別に、カメラ、背景、注釈、アニメーション、開始モードなどを settings.json で制御できる。
{
"version": 2,
"tonemapping": "linear",
"highPrecisionRendering": false,
"background": {
"color": [0, 0, 0]
},
"postEffectSettings": {
"sharpness": { "enabled": false, "amount": 0 },
"bloom": { "enabled": false, "intensity": 0.1, "blurLevel": 2 },
"grading": { "enabled": false, "brightness": 1, "contrast": 1, "saturation": 1, "tint": [1, 1, 1] },
"vignette": { "enabled": false, "intensity": 0.5, "inner": 0.3, "outer": 0.75, "curvature": 1 },
"fringing": { "enabled": false, "intensity": 0.5 }
},
"cameras": [
{
"initial": {
"position": [0, 1, -1],
"target": [0, 0, 0],
"fov": 75
}
}
],
"animTracks": [],
"annotations": [],
"startMode": "default"
}
URLパラメータ例
# Viewerのindex.htmlに対して、読み込むSplatとsettingsを指定
https://example.com/splat-viewer/index.html?content=./scene.sog&settings=./settings.json
# UIを消す
https://example.com/splat-viewer/index.html?content=./scene.sog&settings=./settings.json&noui
# 統計表示
https://example.com/splat-viewer/index.html?content=./scene.sog&settings=./settings.json&ministats
# WebGPUを使う指定。対応ブラウザ・端末のみ
https://example.com/splat-viewer/index.html?content=./scene.sog&settings=./settings.json&webgpu
6. WebXRで可視化する
SuperSplat Viewerは、対応端末ではWebXRによるAR/VR表示に進める。
ただし、WebXRは「表示HTMLを開けば必ず出る」ものではない。
WebXR対応ブラウザ、WebXR対応端末、安全なコンテキスト、十分なGPU性能が必要になる。
WebXR表示に必要な条件
| 条件 | 内容 | 注意 |
|---|---|---|
| 対応端末 | Meta Quest系、AndroidのWebXR対応ブラウザなど | iOS SafariはWebXRの扱いが制限されやすい。検証端末は分ける。 |
| 対応ブラウザ | Quest Browser、Chrome系など | 端末・OS・ブラウザの組み合わせで挙動が変わる。 |
| HTTPS | 本番・LAN端末からはHTTPS配信が基本 | localhost は例外的に許されるが、QuestからPCのlocalhostは見えない。 |
| 軽量データ | SOG化、間引き、不要領域削除 | 重いPLYをそのままVRに投げるとだいたい死ぬ。VR酔いより先にGPUが酔う。 |
| 開始視点 | settings.jsonまたはStudioで開始カメラを調整 | 初期位置が悪いと、ユーザーは壁の中や虚無からスタートする。 |
ローカル検証の段階
- PCブラウザで通常表示できるか確認
- スマホ・Questから同じURLにアクセスできるか確認
- HTTPS化する
- WebXRボタンが出るか確認
- VR/ARに入った瞬間の視点・スケール・重さを確認
HTTPSローカル配信例:mkcert + http-server
LAN内のQuestやAndroidから試す場合、自己署名証明書ではブラウザが嫌がることがある。開発用には mkcert が便利。
# Ubuntu例
sudo apt update
sudo apt install -y libnss3-tools
# mkcertの導入方法は環境により異なるため、GitHub releases等から取得
mkcert -install
# 自分のPCのLAN IPを確認
ip addr
# 例: 192.168.1.50 の証明書を作る
mkcert 192.168.1.50 localhost 127.0.0.1
# http-serverを使う
npm install -g http-server
# Viewerファイルを置いたディレクトリで起動
http-server . -S -C ./192.168.1.50+2.pem -K ./192.168.1.50+2-key.pem -p 8443
# Quest/Android側
# https://192.168.1.50:8443/
スマホやQuest側にmkcertのルート証明書を入れないと、HTTPSでも警告が出る。
実務では、手間を考えると公開ドメイン + Let’s Encrypt + Nginx の方が安定する。
7. Nginx / Flaskに組み込む
推奨ディレクトリ構成
/var/www/supersplat-sites/
cases/
case_0001/
index.html
scene.sog
settings.json
poster.webp
room.voxel.json
room.voxel.bin
case_0002/
index.html
scene.sog
settings.json
viewer/
index.html
index.css
index.js
Nginxで静的配信する例
server {
listen 443 ssl http2;
server_name splat.example.com;
root /var/www/supersplat-sites;
index index.html;
ssl_certificate /etc/letsencrypt/live/splat.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/splat.example.com/privkey.pem;
location / {
try_files $uri $uri/ =404;
}
# 大きめのSplatファイルを扱うなら必要に応じて調整
client_max_body_size 1024M;
# 別ドメインのアプリから読み込む場合だけCORSを検討
# add_header Access-Control-Allow-Origin "https://your-app.example.com" always;
}
Flaskからiframeで表示する例
一番簡単なのは、Viewerを静的ファイルとして置き、Flask側は案件IDに応じてiframeのURLを組み立てる方式。
# app.py
from flask import Flask, render_template, abort
from pathlib import Path
app = Flask(__name__)
BASE = Path("/var/www/supersplat-sites/cases")
@app.route("/cases/<case_id>/splat")
def case_splat(case_id):
case_dir = BASE / case_id
if not case_dir.exists():
abort(404)
viewer_url = f"/static/supersplat-viewer/index.html?content=/splat-data/{case_id}/scene.sog&settings=/splat-data/{case_id}/settings.json"
return render_template("case_splat.html", viewer_url=viewer_url, case_id=case_id)
<!-- templates/case_splat.html -->
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Splat Viewer - {{ case_id }}</title>
<style>
html, body { margin:0; height:100%; }
iframe { width:100%; height:100vh; border:0; }
</style>
</head>
<body>
<iframe src="{{ viewer_url }}" allow="xr-spatial-tracking; fullscreen" allowfullscreen></iframe>
</body>
</html>
DBには
case_id、Splatファイルパス、settings.jsonパス、サムネイル、公開状態、権限、撮影日、現場位置情報を持たせるとよい。Kaleido系の現場記録に入れるなら、Splatは「添付ファイル」ではなく「空間証跡」として扱う方が設計がきれい。
FlaskでSplatファイルを保護配信する例
公開URLに直接ファイルを置くと、URLを知っている人が見られる。業務データでは認証付き配信にする。
from flask import send_from_directory, abort
from pathlib import Path
@app.route("/secure-splat/<case_id>/<path:filename>")
def secure_splat(case_id, filename):
# ここでログイン・権限チェックを必ず行う
# if not current_user.can_view(case_id): abort(403)
base = Path("/var/www/private-splats") / case_id
if not base.exists():
abort(404)
return send_from_directory(base, filename)
8. 現場データでの品質調整
| 症状 | 原因候補 | 対処 |
|---|---|---|
| 表示が重い | PLYが大きすぎる、不要部分が多い、透明度の低いGaussianが多い | SOG化、間引き、不要領域削除、--filter-nan、-F 25% など |
| VRで酔いやすい | 初期位置・スケール・FOV・フレームレートが悪い | 開始カメラを調整、軽量化、FOVを見直す |
| 壁の中から始まる | settings.jsonの初期カメラが不適切 | Studioまたはsettings.jsonで cameras.initial を修正 |
| 歩行できない/突き抜ける | 衝突データがない、Voxel生成が不適切 | .voxel.json / .voxel.bin / collision GLBを生成し、Viewerに指定 |
| QuestでXRボタンが出ない | HTTP配信、非対応ブラウザ、iframe権限不足 | HTTPS化、Quest Browserで確認、iframeに allow="xr-spatial-tracking" を付与 |
9. よくあるトラブルと直し方
npm installで失敗する
# Node.jsのバージョン確認
node -v
# 18未満なら更新
# Ubuntu例: nvmを使うのが楽
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
source ~/.bashrc
nvm install 20
nvm use 20
# 再実行
npm install
localhost:3000が開かない
# 3000番を使っているプロセスを確認
sudo lsof -i :3000
# 必要なら停止
kill -9 <PID>
LANのQuest/Androidから見えない
- PCのファイアウォールでポートが開いているか確認
localhostではなくPCのLAN IPでアクセスする- 同じWi-Fiにいるか確認
- WebXR検証ならHTTPS化する
ファイルサイズが大きすぎる
# SOG化
splat-transform input.ply output.sog
# 25%に間引き
splat-transform input.ply -F 25% output_25pct.ply
# 間引いてからSOG化
splat-transform input.ply -F 25% output_25pct.sog
10. おすすめの実装フロー
PoC
- サンプルPLYを用意
- SuperSplat Editorをローカル起動
- 読み込み、不要部分を削除
- Viewer AppをZIPで書き出し
python -m http.serverでPCブラウザ確認- NginxのHTTPS配信に置く
- Quest/AndroidでWebXR確認
業務システム化
- アップロードされたPLYを案件IDで保存
- SplatTransformで
clean.ply、scene.sog、settings.jsonを生成 - 必要に応じて
voxel/ collision GLBを生成 - Flaskの案件画面からViewerをiframe表示
- 公開範囲、権限、ログ、削除、バックアップを管理
- 重要現場データはPlayCanvas公開URLではなく、自前サーバー配信にする
SuperSplat / WebXRを単体の3Dビューアとして使うだけでなく、Kaleido側の案件管理、写真管理、GIS、ステータス管理、PDF出力、AI検知結果と接続すると、
「見られる3D」から「測れる・記録できる・報告できる現場空間」に発展させられる。
Kaleido × Gaussian Splat の基本発想
Gaussian Splatを現場の背景空間として扱い、その上にKaleidoの業務レイヤーを重ねる。
つまり、Splatは単なる添付ファイルではなく、案件ごとの空間証跡になる。
そこへ採寸、空間タグ、写真、PDF、AI検知結果、コメント、対応ステータスをひも付ける。
| レイヤー | 内容 | 業務上の価値 |
|---|---|---|
| 3D背景レイヤー | Gaussian Splat、SOG、PLY、Viewer設定 | 現場全体を遠隔で確認できる。写真だけでは分からない位置関係を残せる。 |
| 採寸レイヤー | 2点間距離、折れ線長、面積、高さ、幅、勾配のメモ | 擁壁、ブロック塀、設備、道路損傷などの寸法を現場空間上に保存できる。 |
| 空間タグ / 空気タグ | 3D空間に浮かぶ注釈、写真、動画、PDF、図面、コメント、ステータス | 「このひび割れ」「この設備」「この危険箇所」を座標付きで共有できる。 |
| AI検知レイヤー | YOLO / ONNX / OpenVINO等の検知結果、信頼度、クラス名、補正履歴 | AIが見つけた候補を人が修正し、後から再学習データとして回収できる。 |
| 業務管理レイヤー | 案件ID、物件ID、相談者、担当者、状態、更新履歴、PDF帳票 | ビューアで終わらず、受付・確認・対応・完了まで業務フローに乗せられる。 |
採寸機能の考え方
採寸は、最初から測量級の精度を狙うより、段階を分ける方が現実的。
まずは参考採寸として2点間距離や高さメモを付け、LiDAR、ARCore、既知寸法のスケール板、図面寸法などでスケール補正できる場合だけ精度表示を上げる。
Gaussian Splatは見た目の再現性が高い一方、元データや復元条件によってスケール誤差が出るので、報告書には「参考値」「校正済み」「測量値」などの区分を持たせるべき。
measurements
- id
- case_id
- scene_id
- type # distance / height / area / slope / memo
- points_json # [{x,y,z}, {x,y,z}, ...]
- value
- unit
- accuracy_level # reference / calibrated / survey
- note
- created_by
- created_at
空間タグ / 空気タグの設計
空間タグは、Splat上の座標に直接置く「現場メモ」であり、Kaleidoらしく言えば空間に浮かぶ業務カードになる。
タグにはテキストだけでなく、写真、点検項目、AI検知結果、是正前後の比較、PDF図面、担当者コメント、ステータスを持たせる。
WebXRでは、タグが空間内に浮いて見えるため、現場にいるような感覚で確認できる。
spatial_tags
- id
- case_id
- scene_id
- tag_type # crack / warning / photo / pdf / ai_result / task
- position_json # {x,y,z}
- rotation_json # {x,y,z,w} または viewer向き
- title
- body
- attachment_ids_json
- status
- severity
- created_by
- updated_at
実装すると強い画面構成
- 案件詳細画面にSplat Viewerを埋め込む
- 右側に「写真・採寸・タグ・AI候補・履歴」のパネルを置く
- Viewer内でクリックした位置に空間タグを追加する
- 2点クリックで距離、3点以上で面積や範囲を記録する
- タグと採寸をPDF帳票へ自動反映する
- 同じ現場の時系列Splatを切り替え、劣化・補修前後を比較する
Gaussian Splatの採寸は、元データに正しいスケールが入っているかで価値が大きく変わる。
業務利用では、撮影時にスケール板を置く、LiDAR由来の座標を使う、既知寸法で校正する、という運用ルールをセットにする。
ここを曖昧にすると、見た目は未来、数値はファンタジーになる。
最終形のイメージ
最終的には、Kaleido基盤上で「現場空間を見る」「採寸する」「タグを置く」「AI候補を確認する」「担当者が修正する」「帳票を出す」「履歴を比較する」までを一つの画面で扱える。
これは、360パノラマビューアの延長ではなく、空間DB付きの現場業務OSに近い。
擁壁・ブロック塀相談、道路保全、電力設備点検、文化財記録、災害現場記録のどれにも転用しやすい。
現場・インフラ・施設内部・住民相談データは、URLを知っていれば見られる公開形式にしない。
Splatは写真より情報量が多い。構造・導線・設備配置まで見えてしまうので、公開事故の破壊力は写真数枚より強い。
参考資料
