記事一覧へ
3DBabylon.jsWebGPUPerformanceMobile

駐車場デジタルツインの3D描画とモバイル実装

精細な園区モデルと全画面の没入感を維持し、車両インスタンス、保守的LOD、描画解像度の予算、必要時だけ開く情報パネルを実装した記録。

2026-10-03 更新:精細な全画面シーンを維持し、三台の自動走行、四輪の回転、固定距離の追従、元の回路アニメーションを追加しました。

駐車場デジタルツインでは、園区を自由に回転・拡大し、エリアや車両へ移動する体験が中心になります。統計やグラフは常設するのではなく、必要なときに開く設計にしました。

PC版 · モバイル版 · GitHubソース

精細な全画面園区

見た目を制約条件にした最適化

元の Angular 18 / Babylon.js 7 プロジェクトには約616 MBのリソースがあり、標準園区 GLB は164,807,820バイトでした。大きな二つのコンポーネントにモデル、カメラ、チャート、イベント、タイマーが混在していました。

最初の軽量化では、テクスチャ削除と箱型モバイルモデルによって細部を失いました。そこで元の建築、窓、道路標示、駐車面、車両材質を維持し、重複する幾何から削減する方針へ変更しました。

リソースPCモバイル
園区 GLB18,953,916バイト16,444,988バイト
車両テンプレート GLB1,420,956バイト1,350,928バイト
園区の画像テクスチャ1818
車両の画像テクスチャ77
駐車車両インスタンス126126

園区と車両の合計は約20.37 MB / 17.80 MBで、元の標準園区ファイルに対して約87.6% / 89.2%削減しました。端末は該当する一組の LOD だけを読み込みます。モバイルでも同じ建物と材質の層を維持します。

精細車両の共有と静的メッシュの集約

元モデルの重複車両から位置と向きを抽出し、一つの精細車両テンプレートで置き換えました。七種類の材質を保持し、四輪とホイールを独立させた各部品へ126台分の変換行列を thin instances として渡します。

const matrices = new Float32Array(placements.matrices.flatMap(matrix =>
  Array.from(partTransform.multiply(Matrix.FromArray(matrix)).asArray())));
mesh.thinInstanceSetBuffer('matrix', matrices, 16, true);
mesh.thinInstanceEnablePicking = true;

クリックした車両のインスタンスを識別し、その位置へ滑らかに移動できます。走行デモは元アニメーションから採取した道路軌跡を使い、カメラ追従と一時停止に対応します。

静的な園区は材質ごとに集約し、重複除去・頂点結合・保守的な減面・テクスチャサイズ調整を行います。不変の行列と材質を固定し、カメラと走行車両だけを動的に更新します。三台の走行車と独立した四輪を含む現在のシーンは121メッシュです。

車両の詳細表示

車両の向きと固定距離の追従

元の車両は -Y が前、-Z が上で、幾何にも傾きがあります。四輪の位置から基底を作り、+Z 前方・+Y 上方へ正規化し、駐車行列には逆変換を適用します。タイヤとホイールは独立ノードのまま、移動距離を半径で割った角度で回転します。三つの元軌跡は開始時刻と速度をずらし、一時停止時には位置と回転を同時に止めます。

追従カメラは毎フレーム車両の向きに対する後方の固定距離・固定高さを再計算します。追従中は慣性入力を解除し、終了すると手動操作に戻ります。元の回路アニメーションは名称を匿名化して1080pへ圧縮し、読み込み中のループ、完了後の終了、スキップと動画失敗時の表示を用意しました。

全画面を維持する情報レイヤー

キャンバスは常にブラウザー全体を使います。下部の丸いメニューから、状況、エリア、記録、通知、視点、設定のパネルを開きます。初期状態はすべて非表示で、パネルを開いてもキャンバスの寸法は変わりません。

エリアのピン、通知の位置、駐車先の推薦は共通のカメラ補間を利用します。全景・真上・自動周回・車両詳細を切り替えられ、クリーンモードは情報レイヤーを隠します。復元ボタンと Esc で操作画面へ戻れます。

業務状態と描画は分離しています。signals の共通データから空き数や推薦先を算出し、模擬記録を五秒ごとに更新します。3000回のテストで容量の境界と一台単位の保存則を確認しました。統計の300台はデモ用の論理容量で、126台のモデルとリアルタイムに一対一対応するものではありません。

解像度の予算とモバイルの品質

モデルが精細でも、内部描画サイズが CSS サイズを下回ると画面はぼやけます。標準では CSS ピクセルの二倍で描画し、モバイル400万・PC800万ピクセルの予算を設定しました。1600×900のPC画面は3200×1800、844×390のモバイル画面は1688×780で描画します。

const ratio = Math.max(1, Math.min(desiredRatio,
  Math.sqrt(pixelBudget / Math.max(1, width * height))));
engine.setHardwareScalingLevel(1 / ratio);

低フレームレートが続く場合は、追加の発光効果や描画頻度を先に減らし、ネイティブ解像度以下へ自動的に下げません。FPS は実際の render 呼び出しから計測します。測定値は試験環境の観測であり、すべての実機に共通する保証値ではありません。

モバイルは保守的な LOD を使い、建物と車両のテクスチャを維持します。一本指で回転、二本指でズームし、下部ボタンは44ピクセルです。縦向きではシーンを横方向へ回転させ、入力座標も逆変換します。

横向きモバイルの精細園区

全画面ボタンはシステムの横向き固定を試みます。方向固定に対応しないブラウザーでも CSS の横向き表示を利用します。標準は WebGL2、?renderer=webgpu で能力検査済みの WebGPU を明示的に選択できます。

匿名化と配信の検証

匿名化では画面上の名称だけでなく、立体看板、建物に焼き込まれた文字、水印、ナンバープレート、メタデータを確認しました。元の看板と二か所の文字を除去し、両側から読める汎用看板を生成します。そのほかのテクスチャは保持し、旧監視映像や固定機器アドレスは公開しません。

場面クラスがエンジン、ResizeObserver、入力と終了処理を所有します。非表示タブでは描画と模擬更新を止め、ルート変更時にエンジン・監視・イベント・タイマーを解放します。読み込みが途切れた場合は精細モデルの再試行を表示します。

/smartParking/ と /smartParking/mobile を Nginx の静的サイトとして配信し、深いURLから直接更新できます。時刻付き release と設定バックアップを用意してリンクを原子的に切り替え、検証失敗時は旧バージョンへ戻します。

型検査、八つのデータ・運動テスト、四つの GLB と車輪・軌跡の契約、走行・固定追従・低速読み込み・縦横タッチ操作を含む四十六のローカルブラウザー検証を実施しました。配信後には HTTPS 入口を別途確認します。保持したい体験を先に決め、重複処理や不要な常設情報を削減することが、品質と性能の両立につながりました。

参考資料

稼働中のプロジェクトを見る