WebGPU 開発ガイド
本ガイドでは、プロジェクトで WebGPU を使用して 3DGS シーンをレンダリングする方法と、WebGL での統合との違いについて説明します。
エンジンサポート
WebGPU パイプラインは Three.js エンジンのみをサポートします。 CesiumJS は WebGPU レンダリングをサポートしていません。
バージョン要件
SDK バージョン:SDK v0.6.4+
データ形式の制限
WebGPU パイプラインは現在 .lcc2 形式のみをサポートしています。.lcc 形式はまだ WebGPU レンダリングに対応しておらず、今後のリリースで対応予定です。
.lcc データのパスが渡された場合は、WebGL レンダラーにフォールバックする必要があります。サンプルコードでは forceWebGL パラメータでこの処理を実装しています:
const forceWebGL = new URL(dataPath, location.origin).pathname.endsWith('.lcc');
const renderer = await createRenderer(canvas, forceWebGL);
WebXR の制限
現在、SDK は WebGL パイプラインでのみ WebXR をサポートしています。WebGPU パイプラインは WebXR をサポートしていません。
モバイルの制限
モバイルデバイスでの WebGPU の使用は推奨しません。現在、モバイルでは SDK の WebGL パイプラインの方が優れたパフォーマンスを発揮します。
Three.js のレンダリングパス
Three.js には 3 つのレンダリングパスがあります。SDK を正しく統合するには、それぞれの違いを理解しておくことが重要です。
パス 1:従来の WebGLRenderer(広く使用されている)
WebGLRenderer は Three.js の誕生以来のコアレンダラーであり、現在も最も広く使われています。WebGL 2 API の上に直接構築されており、マテリアルシステムには GLSL シェーダーを使用します。
インポート:
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer();
SDK はこのパスをサポートしています。.lcc と .lcc2 の両方の形式に対応しています。
パス 2:新アーキテクチャ WebGPURenderer + WebGPU バックエンド
WebGPURenderer は Three.js の次世代レンダラーで、新しい抽象バックエンドアーキテクチャを採用しています。ノードベースのマテリアルシステム(Node Material)と TSL(Three.js Shading Language)が導入されており、TSL で記述したシェーダーはバックエンドに応じて WGSL または GLSL に自動コンパイルされます。ブラウザが WebGPU をサポートしている場合、WebGPURenderer はネイティブの WebGPU バックエンドを使用します。
インポート:
import * as THREE from 'three';
import * as THREE_WEBGPU from 'three/webgpu';
import * as THREE_TSL from 'three/tsl';
const renderer = new THREE_WEBGPU.WebGPURenderer({ canvas });
await renderer.init();
SDK はこのパスをサポートしています。対応形式は .lcc2 のみです。
パス 3:新アーキテクチャ WebGPURenderer + WebGL 2 バックエンド
WebGPURenderer にはフォールバック用の WebGL 2 バックエンドが組み込まれています。ブラウザが WebGPU をサポートしていない場合、WebGPURenderer は自動的に WebGL 2 バックエンドに切り替わります。WebGL 2 を使用しているものの、マテリアルシステムとシェーダーパイプラインはパス 2 と同じ(Node Material + TSL)で、最終的なコンパイル先が GLSL になります。
SDK はこのパスをサポートしていません。
パスの比較
| パス | レンダラー | グラフィックス API | マテリアル / シェーダーシステム | SDK サポート | 対応形式 |
|---|---|---|---|---|---|
| 1. 従来の WebGL | WebGLRenderer | WebGL 2 | GLSL (ShaderMaterial) | ✅ | .lcc .lcc2 |
| 2. 新アーキテクチャ WebGPU | WebGPURenderer | WebGPU | Node Material / TSL / WGSL | ✅ | .lcc2 |
| 3. 新アーキテクチャ WebGL フォールバック | WebGPURenderer | WebGL 2(バックエンドのフォールバック) | Node Material / TSL / GLSL | ❌ | - |
WebGPU と WebGL の統合の違い
WebGL での統合と比べ、WebGPU での変更点は以下の項目に集約されます。その他のビジネスコード(カメラ操作、パフォーマンスパラメータ、レンダリングループなど)はすべて同じです。
1. 追加のインポート:three/webgpu と three/tsl
WebGL では three のみが必要ですが、WebGPU ではさらに 2 つのモジュールが必要です:
<!-- importmap -->
<script type="importmap">
{
"imports": {
"three": "./engine/three/three.module.js",
"three/webgpu": "./engine/three/three.webgpu.js",
"three/tsl": "./engine/three/three.tsl.js",
"three/addons/": "./engine/three/jsm/"
}
}
</script>
import * as THREE from 'three';
import * as THREE_WEBGPU from 'three/webgpu';
import * as THREE_TSL from 'three/tsl';
2. レンダラーの非同期作成
WebGL レンダラーは同期的に作成されますが、WebGPU レンダラーは非同期で初期化する必要があります:
// WebGL(同期)
const renderer = new THREE.WebGLRenderer({ canvas, antialias: false });
// WebGPU(非同期)
const renderer = new THREE_WEBGPU.WebGPURenderer({ canvas, antialias: false });
await renderer.init();
SDK のサンプルに含まれるユーティリティ関数 createRenderer の使用を推奨します。この関数は以下の完全なフォールバックチェーンを実装しています:
- ブラウザが
navigator.gpuをサポートしていない →WebGLRendererにフォールバック - GPU アダプターを取得できない →
WebGLRendererにフォールバック WebGPURendererが初期化後に WebGL 2 バックエンドへ暗黙的にフォールバックした(GPUDeviceがない)→ 破棄してWebGLRendererにフォールバック- すべてのチェックに合格 → 本物の WebGPU レンダラーを返す
import { createRenderer } from './engine/three/util.js';
const renderer = await createRenderer(canvas, forceWebGL);
const isWebGPU = renderer.isWebGPURenderer === true;
3. sRGB 出力とトーンマッピングの無効化
WebGPU モードでは、Three.js のデフォルトの sRGB 出力変換とトーンマッピングを無効にする必要があります。デフォルトの sRGB 出力では linear → sRGB の変換パスが 1 回余分に追加され、3DGS の乗算済みアルファブレンディングと競合して色ずれが発生します:
if (isWebGPU) {
renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
renderer.toneMapping = THREE.NoToneMapping;
}
WebGL モードではこの設定は不要です。
4. LCCRender.load のパラメータ
WebGPU では、追加で renderLibWebgpu と renderLibTSL パラメータが必要です:
// WebGL
LCCRender.load({
camera, scene, renderer,
dataPath,
renderLib: THREE,
canvas: renderer.domElement,
// ...
});
// WebGPU
LCCRender.load({
camera, scene, renderer,
dataPath,
renderLib: THREE,
renderLibWebgpu: THREE_WEBGPU, // 追加
renderLibTSL: THREE_TSL, // 追加
canvas: renderer.domElement,
// ...
});
GPU デバイスの制限値の設定
WebGPURenderer を作成する際は、GPU アダプターの実際の制限値を取得して requiredLimits に渡し、デバイスの性能を最大限に活用することを推奨します:
const adapter = await navigator.gpu.requestAdapter();
const requiredLimits = {
maxBufferSize: adapter.limits.maxBufferSize,
maxStorageBufferBindingSize: adapter.limits.maxStorageBufferBindingSize,
maxTextureDimension2D: adapter.limits.maxTextureDimension2D
};
const renderer = new THREE_WEBGPU.WebGPURenderer({
canvas,
antialias: false,
requiredLimits
});
await renderer.init();
WebGPU の完全なサンプル
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LCC Three.js WebGPU Demo</title>
<style>
html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "./engine/three/three.module.js",
"three/webgpu": "./engine/three/three.webgpu.js",
"three/tsl": "./engine/three/three.tsl.js",
"three/addons/": "./engine/three/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import * as THREE_WEBGPU from 'three/webgpu';
import * as THREE_TSL from 'three/tsl';
import { createRenderer } from './engine/three/util.js';
import { LCCRender } from '../sdk/lcc-sdk-three.js';
const dataPath = 'https://your-server.com/assets/scene/meta.lcc2';
// WebGPU は .lcc2 のみ対応。.lcc データの場合は WebGL を強制使用
const forceWebGL = new URL(dataPath, location.origin).pathname.endsWith('.lcc');
const scene = new THREE.Scene();
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
// レンダラーを作成(WebGPU → WebGL の自動フォールバック付き)
const renderer = await createRenderer(canvas, forceWebGL);
const isWebGPU = renderer.isWebGPURenderer === true;
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0x000000);
// WebGPU では sRGB 出力を無効化し、3DGS との色空間の競合を回避
if (isWebGPU) {
renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
renderer.toneMapping = THREE.NoToneMapping;
}
const camera = new THREE.PerspectiveCamera(
45, window.innerWidth / window.innerHeight, 0.1, 150000
);
camera.position.set(0, 2, 0);
// 3DGS シーンを読み込む
const lccObj = LCCRender.load({
camera, scene, renderer,
dataPath,
renderLib: THREE,
renderLibWebgpu: THREE_WEBGPU,
renderLibTSL: THREE_TSL,
canvas: renderer.domElement,
useEnv: true,
useIndexDB: true,
useLoadingEffect: true,
appKey: null // ご自身のキーに置き換えてください
},
(mesh) => { console.log('Loaded', mesh); },
(percent) => { console.log('Loading ' + (percent * 100).toFixed(1) + '%'); },
() => { console.log('Loading failed'); }
);
// パフォーマンスパラメータを設定
lccObj.setStartLod(0);
lccObj.setMaxSplats(8000000);
lccObj.setMaxNodeSplats(4000000);
lccObj.setMaxDistance(200);
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
renderer.setAnimationLoop(() => {
LCCRender.update();
renderer.render(scene, camera);
});
</script>
</body>
</html>