皆さん、こんにちは!
今週のAKAIRI Tech Blogは、DX Solution事業本部 Devグループの小山が担当します。
本記事では vtk.wasm を使って、サーバーを一切介さずブラウザだけで3Dデータを可視化する方法を解説します。
- はじめに
- なぜブラウザでVTKの3D可視化を完結させたいのか
- vtk.wasm とは
- ビルドと配布のしくみ
- 最小サンプル:ブラウザだけで球体をレンダリング
- pyvista-wasm:Python ユーザー向けの応用
- まとめ
- We're Hiring!
はじめに
ビルドと配布のしくみから HTML+JS の最小サンプル、そして Python ユーザー向けの応用(pyvista-wasm)まで順を追って紹介します。本記事は vtk.wasm を初めて触る方を対象としており、JavaScript の基本的な知識があれば動かせるサンプルから、Python ユーザー向けのノートブック環境まで段階的に紹介します。まず動く状態を確認してから細部を理解したい方も、ビルドの仕組みから把握したい方も、それぞれの目的に合わせて読み進めていただければ幸いです。
なぜブラウザでVTKの3D可視化を完結させたいのか
Three.js はブラウザで3Dを扱う定番ライブラリとして一般的に広く利用されていますが、建設・製造業で実施した物理シミュレーション結果を直接可視化する機能はありません。サーバーサイドレンダリング(SSR)で補う方法もありますが、可視化専用サーバーの構築・運用コストがかかり、機密性の高いシミュレーションデータをサーバーへ送信するセキュリティリスクも生じます。
Wasm 構成ではサーバーへのデータ送信が不要となり、全処理をブラウザ内で完結させることができます。
物理シミュレーション可視化プロジェクトを検討しており、「解析済みメッシュをそのままブラウザにドロップして見せたい」という要求が vtk.wasm 調査の直接の動機になりました。専用インフラなしで実現できれば、導入・維持コストを大幅に圧縮できます。
vtk.wasm とは
VTK の位置づけ
VTK(Visualization Toolkit) は Kitware が開発・メンテナンスする C++ 製の科学技術可視化ライブラリです。1993年の初版から30年以上の蓄積があり、医用画像処理・CAE・地球科学など幅広い分野で使われています。点群・メッシュ・ボリュームデータを扱う数百のフィルターと OpenGL/Vulkan 対応レンダラーを持ちます。VTK を Python からラップした PyVista や医用画像向けの ITK など、周辺エコシステムも充実しています。C++ ライブラリとしての VTK は NumPy や SciPy などの科学計算スタックと親和性が高く、医療・製造・気象など多くの分野でデファクトスタンダードとして使われています。Wasm 化によってその機能をサーバーなしに提供できるようになったことは、特にフィールドやクライアント先での即席デモが必要な場面で大きな意義があります。
Wasm ビルドの歴史と現状
VTK の WebAssembly 対応は 2018年ごろ、Emscripten を用いた実験的ビルドとして始まりました。2021年には公式ビルドパイプラインに統合され、vtk.js(JavaScript 実装の別プロジェクト)とは独立した vtk.wasm として npm パッケージが公開されています。
2023〜2024年にかけては WebGPU バックエンド のサポートが進み、従来の WebGL ベースよりも高いレンダリング性能と GPU コンピュート能力が期待できます。現在のパッケージは WebGL と WebGPU を実行時に切り替えられる構造になっており、ブラウザの対応状況に合わせて自動フォールバックする設計が進んでいます。
できること・現状の制限
現時点での vtk.wasm の主な機能と制限を整理します。
できること
- VTK フィルターパイプラインの実行
- VTP/VTU/STL 等のメッシュ読み込み
- インタラクティブなカメラ操作
- Python(PyVista)との連携
現状の制限
- モジュールが 30〜50 MB(gzip 後でも 10〜15 MB)と重い
- マルチスレッド処理には COOP/COEP ヘッダが必須
- WebGPU は一部ブラウザで実験的フラグが必要な場合あり
- 初回ロードに数秒〜十数秒かかる
大規模メッシュの処理には依然として制約がありますが、数十万要素程度であればインタラクティブな操作が十分実用的な速度で動きます。
ビルドと配布のしくみ
vtk.wasm は Emscripten で VTK の C++ コードをまるごと WebAssembly へコンパイルしたものです。ビルド自体は数時間かかる重い作業ですが、利用者は npm パッケージをインストールするだけで済みます。
JavaScript バインディングは @kitware/vtk-wasm で提供されます。
npm install @kitware/vtk-wasm
WASM バイナリ本体は別途 CDN 経由で実行時にロードします。createNamespace(url) に tarball の URL を渡すと VTK クラス群が非同期でロードされます。以下のサンプルでは jsDelivr 経由の @pyvista-wasm/vtk-wasm-binary を使用しています。jsDelivr は Cloudflare・Fastly・Bunny CDN を組み合わせたマルチ CDN 構成でエッジキャッシュによる高速配信が期待できるため、Kitware 公式の GitLab 直接配信と比べてアジアリージョンでの応答速度が大幅に向上します。
const WASM_URL = 'https://cdn.jsdelivr.net/npm/@pyvista-wasm/vtk-wasm-binary/vtk-wasm32-emscripten.tar.gz'; createNamespace(WASM_URL).then(async (vtk) => { /* ... */ });
初回ロード時のネットワーク転送量は gzip 配信でも 12〜15 MB 前後になります。スピナーや遅延ロード(Intersection Observer)との組み合わせを推奨します。Vite で使う場合は以下の設定を追加してください。
// vite.config.js export default { build: { target: 'esnext' }, optimizeDeps: { exclude: ['@kitware/vtk-wasm'] }, };
最小サンプル:ブラウザだけで球体をレンダリング
以下の埋め込みデモでは、vtkSphereSource で球体ジオメトリを生成し、vtkPolyDataMapper と vtkActor を経由して vtkRenderer に追加するまでの最小パイプラインを実装しています。StackBlitz 上でファイルを編集するとリアルタイムにプレビューが更新されるため、パラメータを変えながら動作を確認できます。
実装時に注意が必要な点を3つ紹介します。
createNamespace()は Promise を返すため、VTK オブジェクトの操作はすべてasync/awaitで記述する必要があります。awaitを忘れると WASM ロード前にオブジェクトを操作してしまいエラーになります。- 並列処理フィルターは
SharedArrayBufferが必要なため、サーバーがCross-Origin-Opener-Policy: same-originとCross-Origin-Embedder-Policy: require-corpを返す必要があります。Vite ではvite-plugin-cross-origin-isolationを使うと簡単に設定できます。 createNamespace(url)に渡す tarball URL は CORS が有効である必要があります。GitLab の直接 URL はアジアリージョンで遅延することがあるため、jsDelivr CDN 経由の@pyvista-wasm/vtk-wasm-binaryの利用を推奨します。
pyvista-wasm:Python ユーザー向けの応用
vtk.wasm の応用として、JupyterLite や marimo と組み合わせて Python のまま Wasm 環境で可視化するアプローチがあります。PyVista は VTK の Python ラッパーであり、Pyodide(CPython の Wasm 版)と組み合わせることで、ブラウザ上で Python コードを書きながら 3D メッシュを可視化できます。この取り組みは筆者が公開している GitHub - tkoyama010/pyvista-wasm: PyVista-like API for VTK.wasm — bring intuitive 3D visualization to the browser using WebAssembly. · GitHub リポジトリで継続的に整備しています。各環境のプレビュー画像はクリックするとライブデモに移動し、インストール不要でコードを実際に実行して3D可視化を体験できます。
JupyterLite での使用
JupyterLite はブラウザだけで動く Jupyter 環境です。pyvista-wasm を使うと、インストール不要でノートブック上に 3D メッシュをインタラクティブに表示できます。下の画像をクリックするとデモへ移動できます。pv.Sphere() や pv.read() を使ったノートブックがあらかじめ用意されており、セルを実行するだけで 3D ビューアーが起動します。ローカル環境のセットアップなしに vtk.wasm の描画品質を手軽に体験できる入口として最適です。JupyterLite は GitHub Pages などの静的ホスティングサービスに配置できるため、別途サーバーを用意する必要がありません。ノートブックを含む環境ごと URL で共有できるため、解析結果の再現環境をワンクリックで提供したいケースにも活用できます。
marimo での使用
marimo はリアクティブな Python ノートブック環境で、こちらもブラウザ完結で動作します。セルの値が変わると依存するセルが自動再実行されるため、パラメータを変えながら 3D メッシュをインタラクティブに探索するワークフローに向いています。下の画像をクリックするとデモへ移動できます。スライダーの値を動かすと即座に再描画が走り、メッシュの色や視点をリアルタイムに変更できます。Jupyter との違いは「再実行ボタンを押さなくてよい」点で、探索的な可視化作業の効率が上がります。
stlite での使用
stlite はブラウザ上で Streamlit を動かす環境です。スライダーやセレクトボックスなどのウィジェットと組み合わせることで、色や透明度といったパラメータを変えながら 3D メッシュをリアルタイムに操作できます。下の画像をクリックするとデモへ移動できます。Stanford Bunny の色を 8 色から選択し、透明度を 0〜1 の範囲でスライダー調整できます。Streamlit の宣言的な UI 記述と pyvista-wasm の 3D 描画を組み合わせることで、非エンジニアにも扱いやすい可視化ツールをサーバーレスで提供できます。JupyterLite や marimo がノートブック形式の探索的可視化に向いているのに対し、stlite はウィジェットを組み合わせた操作可能なアプリを公開したいときに最適な選択肢となります。スライダーやプルダウンを数行で追加でき、技術的な背景を持たないユーザーでも直感的に操作できる UI を素早く構築できます。
まとめ
vtk.wasm を使うと、サーバーなしで科学技術計算の3D可視化をブラウザ完結させることができます。
向く用途
- 物理シミュレーション結果の配布・共有
- ローカル解析ファイルの即席ビューアー
- サーバーレス静的サイトへの組み込み
向かない用途
- 数億要素規模のメッシュのリアルタイム処理
- 低スペック端末・低速回線
- WebGPU 非対応ブラウザでの高品質レンダリング
筆者自身は物理シミュレーション可視化ツールの PoC として vtk.wasm を評価し、専用サーバーなしで解析結果を共有できることを確認しました。初期ロードの重さは課題となりますが、一度ロードが完了すればインタラクティブな操作は十分実用的な速度で動作します。小規模チームで解析結果をレビューするユースケースには現時点でも十分な品質であり、今後の WebGPU 安定化によってさらに適用範囲が広がることが期待されます。また、pyvista-wasm との組み合わせで Python エコシステムとのシームレスな連携も着実に進んでいます。
今後の展望として、WebGPU バックエンドの安定化により GPU コンピュートもブラウザで完結できるようになること、そしてPyodide + PyVista の統合が成熟することで Python エコシステムとのシームレスな橋渡しが期待されます。30年の蓄積を持つ VTK がブラウザに降りてきたことで、科学技術可視化の裾野は着実に広がっています。
pyvista-wasm は現在も活発に開発が進んでいるオープンソースプロジェクトです。新しい VTK フィルターの追加、対応ファイル形式の拡充、パフォーマンス改善など、コントリビュートできる領域は多岐にわたります。興味のある方は GitHub リポジトリ の Issue や Pull Request からぜひ参加してください。小さなドキュメント修正や日本語翻訳の改善なども大歓迎です。
We're Hiring!
燈では、新しい技術の調査・導入に興味があるエンジニアを募集しております。本記事のように OSS の最前線をキャッチアップしながら、実際のプロダクトや社会課題の解決に活かしていきたい方はぜひご応募ください。詳細は採用ページをご覧ください。