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






SuperSplatをローカル構築してGaussian Splatを処理し、WebXRで可視化する流れ


Gaussian Splatting / SuperSplat / WebXR 実装メモ

ここでは、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表示に進める。

撮影・生成Polycam / Postshot / COLMAP / Nerfstudio等でPLYやSplat系データを作る
編集SuperSplat Editorで不要部分削除、向き調整、見栄え確認
CLI処理SplatTransformでSOG化、間引き、NaN除去、座標変換、衝突データ生成
設定settings.jsonでカメラ、注釈、背景、アニメーションを定義
ViewerHTML Exportまたはsupersplat-viewerで表示
HTTPS配信Nginx / Flask / GitHub Pages等で公開
WebXRQuest / Android等の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 installnpm 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の考え方:
--seed-pos は「ここが歩ける・中心にしたい」という点を指定する。
現場空間の場合は、入口付近や通路中央など、確実に空間内部にある座標を選ぶ。
ここを外すと、必要なクラスタまで消える。便利だが、切れ味のよすぎる包丁。

5. Viewerとして書き出す

A. Editorから書き出す

SuperSplat Editorで編集後、以下の操作でビューアを書き出す。

  1. File を開く
  2. Export サブメニューを開く
  3. Viewer App… を選ぶ
  4. 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.htmlindex.cssindex.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で開始カメラを調整 初期位置が悪いと、ユーザーは壁の中や虚無からスタートする。

ローカル検証の段階

  1. PCブラウザで通常表示できるか確認
  2. スマホ・Questから同じURLにアクセスできるか確認
  3. HTTPS化する
  4. WebXRボタンが出るか確認
  5. 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

参考資料

まとめ:編集はSuperSplat Editor、処理はSplatTransform、公開・WebXRはSuperSplat Viewer
この分業にすると、PoCから業務システムまで拡張しやすい気がする。©株式会社ビー・ナレッジ・デザイン


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA