Three.jsのWebGPU移行とは、WebGLRendererをthree/webgpuのWebGPURendererに置き換え、GLSLシェーダーをTSLに書き直し、ポストプロセスをRenderPipelineに移すことです。WebGPUが使えない環境では、レンダラーが自動的にWebGL 2へフォールバックするため、1つのコードベースで両方に対応できます。本記事のコードはすべてthree.js r186(2026年9月)で確認しています。
移行の判断基準、ステップごとの手順、WebGL 2フォールバックの仕組み、React Three Fiberでの設定、コンピュートシェーダー、キオスク運用、そしてチームでそのまま使える34項目のチェックリストまでをまとめました。
この記事の対象者: WebGPU移行を計画しているThree.js開発者、移行工数を見積もる技術リード、React Three FiberにWebGPU対応を加えたいチーム。
要点まとめ
- レンダラーの置き換えは1行です。工数の大半は
ShaderMaterial・RawShaderMaterial・onBeforeCompileのTSLへの移植にかかります。WebGPURendererはどちらのバックエンドでもこれらをサポートしていません。 - WebGL 2へのフォールバックは自動です。用意するレンダラーは1つだけ。どちらで動いているかは、初期化後に
renderer.backend.isWebGPUBackendで確認します。renderer.isWebGPURendererはどちらのバックエンドでもtrueです。 setAnimationLoop()が初期化を代行します。await renderer.init()が必要なのは、ループ開始前に処理を行う場合だけです。r186では、未初期化のままrender()を呼ぶとエラーになります。- ポストプロセスは
RenderPipelineへ。r183まではPostProcessingという名前でした。EffectComposerとpmndrs/postprocessingはWebGPURendererでは動きません。 - React Three Fiber 9では非同期の
glファクトリーを使います。引数にはデフォルトのレンダラー設定が渡されます。ノードマテリアルをJSXで使うには、three/webgpuをextend(THREE)で登録します。 - コンピュートは
instancedArrayとrenderer.compute()で書きます。アニメーションループ内で呼び出します。computeAsync()などの*Async系メソッドはr181で非推奨になりました。
1. あなたのプロジェクトはWebGPUに移行すべきか?
すべてのプロジェクトが今すぐWebGPUを必要としているわけではありません。判断の目安を整理します。
1-1. 移行判断マトリクス
| シナリオ | 推奨 |
|---|---|
| 新規プロジェクトで、既存コードの制約がない | WebGPURendererで始める |
| ドローコールでCPUが詰まっている、またはJavaScriptから大量のパーティクルを毎フレーム更新している | 移行する |
| コンピュートシェーダーが必要(シミュレーション、GPUカリング、GPGPU) | 移行する |
| 現状で問題なく動作し、新機能の予定もない | WebGLRendererのまま |
カスタムGLSLやonBeforeCompileのパッチが多い | 先にTSL移植の工数を見積もる |
| WebGL専用ライブラリ(pmndrs/postprocessing、troikaのテキストなど)に依存している | TSLの代替ができるまで待つ |
| ハードウェアを固定できるキオスク・インスタレーション | 移行する(GPUとドライバーを事前に検証できる) |
WebGLRendererはレガシーではありません。公式マニュアルは今もWebGLRendererを「純粋なWebGL 2アプリケーションには推奨の選択肢」としており、WebGPURendererについては「まだ実験的な段階」で、シーンによっては機能が足りなかったりWebGLRendererの方が速かったりすると明記しています(three.js公式マニュアル:WebGPURenderer(英語))。エンジン自体の選定から見直す場合は、Three.js vs Babylon.js vs PlayCanvas比較も参考にしてください。
1-2. ブラウザ対応状況(2026年9月時点)
| ブラウザ | WebGPUがデフォルトで有効になったバージョン |
|---|---|
| Chrome / Edge(デスクトップ) | Windows・macOS・ChromeOSは113以降。Linuxは144以降(Intel Gen12以降のGPU)、147以降(Wayland上のNVIDIA) |
| Chrome(Android) | Android 12以降、ARM・Qualcomm・IntelのGPUで121以降 |
| Firefox | Windowsは141以降。Apple Silicon搭載Macは、macOS 26で145以降、すべてのmacOSで147以降。Intel Mac・Linux・Androidは安定版では未対応 |
| Safari | macOS 26・iOS 26・iPadOS 26・visionOS 26のSafari 26以降 |
caniuseによる全世界の対応率は約87%です(完全対応84%+部分対応3%、2026年8月時点のデータ)。WebGPUが使えない環境では、自動的にWebGL 2バックエンドで動作します(4章)。国内向けの案件では、iOS 26にアップデートできないiPhoneやiPadがWebGL 2で表示されることになるため、その確認も欠かせません。(出典:gpuweb Implementation Status(英語)、caniuse.com/webgpu(英語))
Three.js全体の変化についてはThree.js 2026年:何が変わったのか?で解説しています。
1-3. WebGPUで効果が出る場面
WebGPUはあらゆる場面で速いわけではありません。効果が出やすいのは次のようなケースです。
- ドローコールが多いシーン:ChromeチームはWebGPUの利点として「同じ描画に対するJavaScriptの負荷が大幅に減る」ことを挙げています(Chrome for Developers(英語))。
- 計算量の多い処理:パーティクル、物理演算、シミュレーションなど、データを毎フレームJavaScriptから転送せず、GPU上に置いたまま処理できるもの。
- ポストプロセスのチェーン:ノードベースのパイプラインは可能な範囲でエフェクトを統合し、レンダーパスの数を減らします(three.js公式マニュアル:ポストプロセス(英語))。
- GPU駆動のレンダリング:コンピュートパスで間接描画の引数を書き込めます(
geometry.setIndirect()、WebGPUバックエンドのみ)。
ボトルネックがテクスチャの転送、アセットの容量、シェーダーのコンパイル時間にある場合、WebGPUにしても改善しないことがあります。three.jsフォーラムではWebGPURendererの方がWebGLRendererより遅いという報告もあります(該当スレッド(英語))。速度だけを理由に移行する場合は、まず自分のシーンで計測してください。
2. 移行チェックリスト:WebGLからWebGPUへ
ステップごとの手順です。所要時間は、カスタムシェーダーとポストプロセスのコード量でほぼ決まります。その量はステップ1で把握できます。
2-1. ステップ1:現状を棚卸しする
コードに手を入れる前に、WebGPURendererで動かない箇所を洗い出します。
# three.jsのバージョン(2つ表示されたら、バンドルに2つのコピーが入っています)
npm ls three
# カスタムシェーダー:WebGPURendererではどちらのバックエンドでも非対応
grep -rnE "ShaderMaterial|onBeforeCompile" src/
# WebGL専用のポストプロセス
grep -rnE "EffectComposer|from 'postprocessing'|@react-three/postprocessing" src/
# WebGLレンダラーやそのコンテキストに依存するコード
grep -rnE "WebGLRenderer|WebGLCubeRenderTarget|getContext\(\)" src/
確認ポイント:
- three.jsのバージョン:本記事はr186が前提です。ここで使うエントリーポイントの構成(共通のコアを持つ
three/webgpuとthree/tsl)はr171からのものです - カスタムGLSL(
ShaderMaterial、RawShaderMaterial、onBeforeCompile):1つずつTSLへの移植が必要です EffectComposerやpmndrs/postprocessingで組んだポストプロセス:パスごとにTSLノードへ置き換えます- シェーダーにパッチを当てる、またはWebGL用のレンダーターゲットを作るサードパーティライブラリ:WebGPU対応状況を確認します
2-2. ステップ2:Three.jsをr186に更新する
npm install three@0.186.0
古いプロジェクトは、10リリース程度ずつ段階的に更新するのがthree.js公式の推奨です。非推奨の警告が10リリースの間だけ残るためです(three.js Migration Guide(英語))。WebGPU移行で特に影響の大きい最近の変更は次の通りです。
| リリース | 変更内容 | 対応 |
|---|---|---|
| r181 | renderAsync()・computeAsync()など*Async系メソッドが非推奨に | render()・compute()を使い、setAnimationLoop()かawait renderer.init()で初期化する |
| r182 | レンダラーのオプションcolorBufferTypeが改名 | outputBufferTypeを使う |
| r183 | PostProcessingがRenderPipelineに改名、Clockが非推奨に | RenderPipelineとTimerを使う |
| r183 | WebGLCubeRenderTargetがWebGPURendererで使えなくなった | CubeRenderTargetを使う |
| r185 | WebGPURendererのプリマルチプライドアルファの扱いが変更 | ブレンドがおかしい場合は、不透明なscene.backgroundかクリアカラーを設定する |
| r185 | positionNode内のpositionLocalが、スキニングなどの内部変換を反映しなくなった | 変換前の頂点であるpositionGeometryを基準に組み立てる |
| r186 | WebGPURendererでPCFSoftShadowMapが廃止 | ソフトシャドウになったPCFShadowMapを使う |
| r186 | TSLのviewportResolutionが削除 | screenSizeを使う |
リリースごとの全変更はMigration Guideとthree.jsのリリースノート(英語)で確認できます。大きな流れはThree.js 2026年:何が変わったのか?にまとめています。
2-3. ステップ3:レンダラーのインポートを置き換える
移行の中心となる変更です。
// 変更前(WebGL)
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
// 変更後(WebGPU、WebGL 2への自動フォールバック付き)
import * as THREE from 'three/webgpu';
const renderer = new THREE.WebGPURenderer({ antialias: true });
three/webgpuは、コア全体(シーングラフ、ジオメトリ、標準マテリアル、ライト)に加えて、WebGPURenderer、ノードマテリアル、RenderPipelineをエクスポートしています。TSLの関数はthree/tslからインポートします。MeshStandardMaterialなどの標準マテリアルは、レンダラーがノードマテリアルに対応付けるのでそのまま動きます。なお、three/webgpuはWebGLRendererをエクスポートしていません。
2-4. ステップ4:非同期の初期化に対応する
WebGPUはGPUデバイスを非同期で作成します。いちばん簡単なのはsetAnimationLoop()から描画する方法で、最初のフレームの前にrenderer.init()を待ってくれます。
import * as THREE from 'three/webgpu';
const renderer = new THREE.WebGPURenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// setAnimationLoop()が最初のフレームの前にレンダラーを初期化する
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
ループ開始前に描画・コンピュート・機能チェックを行う場合(オンデマンド描画、サムネイル生成、事前計算など)は、先に初期化します。
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init();
renderer.render(scene, camera); // ループなしで1フレームだけ描画
よくあるミス:init()もsetAnimationLoop()も使わずにrender()を呼ぶこと。r186ではTHREE.Renderer: .render() called before the backend is initialized. Use "await renderer.init();" before rendering.というエラーになります。また、renderAsync()はr181で非推奨になり、警告が出るので使わないでください。
2-5. ステップ5:ポストプロセスを置き換える
EffectComposerとそのパスはWebGPURendererでは動きません。pmndrs/postprocessingと、それをラップした@react-three/postprocessingも同様で、どちらもWebGLRenderer向けです。置き換え先はRenderPipelineで、各エフェクトをTSLのノードとして組み合わせます。
import * as THREE from 'three/webgpu';
import { pass } from 'three/tsl';
import { bloom } from 'three/addons/tsl/display/BloomNode.js';
const renderPipeline = new THREE.RenderPipeline(renderer);
const scenePass = pass(scene, camera);
const scenePassColor = scenePass.getTextureNode('output');
// bloom(入力, strength, radius, threshold)
const bloomPass = bloom(scenePassColor, 1.5, 0.4, 0.8);
renderPipeline.outputNode = scenePassColor.add(bloomPass);
renderer.setAnimationLoop(() => {
renderPipeline.render(); // renderer.render(scene, camera)の代わり
});
つまずきやすい点が2つあります。
bloomはthree/tslからはエクスポートされていません。エフェクトはthree/addons/tsl/display/にあります(FXAANode.js、SMAANode.js、TRAANode.js、GTAONode.js、SSRNode.js、DepthOfFieldNode.js、OutlineNode.jsなど)。- このクラスはr183まで
PostProcessingという名前でした。r186でも旧名は動きますが、非推奨の警告が出ます。
トーンマッピングと色空間の変換は、パイプラインの最後に自動で適用されます。FXAAのように、その後に実行すべきエフェクトがある場合は、renderPipeline.outputColorTransform = falseにしてrenderOutput()を自分で適用します(公式マニュアル(英語))。
2-6. ステップ6:カスタムシェーダーをTSLに移植する
ShaderMaterial、RawShaderMaterial、onBeforeCompileによるパッチは、WebGPURendererでは使えません。WebGPUバックエンドでも、WebGL 2のフォールバックでも同じです。ノードマテリアルとTSL(Three Shader Language)に移植します。TSLはWebGPUではWGSLに、WebGL 2ではGLSLにコンパイルされます。
// 変更前:ShaderMaterialのGLSL(WebGLRendererのみ)
const material = new THREE.ShaderMaterial({
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
varying vec2 vUv;
void main() {
gl_FragColor = vec4(vUv, 0.5, 1.0);
}
`
});
// 変更後:TSLを使ったノードマテリアル(WebGPURendererの両バックエンドで動作)
import * as THREE from 'three/webgpu';
import { uv, vec4 } from 'three/tsl';
const material = new THREE.MeshBasicNodeMaterial();
material.colorNode = vec4(uv(), 0.5, 1.0);
頂点シェーダーは不要になります。投影変換はノードマテリアルが行い、必要なときだけpositionNodeで上書きします。
移植後は色を見比べてください。ShaderMaterialはgl_FragColorの値をそのまま画面に書き込みますが、ノードマテリアルはcolorNodeをリニアな値として扱い、最後に出力色空間へ変換します。同じ数値でも、移植後の方が明るく見えることがあります。
GLSLを残す抜け道はありません。renderer.isWebGPURenderer ? tslMaterial : glslMaterialのような分岐を書いても、GLSL側はWebGL 2バックエンドでも動かないため意味がありません。どちらのバックエンドでも、コンソールにTHREE.NodeBuilder: Material "ShaderMaterial" is not compatible.と表示され、メッシュは描画されません。すぐに移植できないシェーダーがある場合は、そのページだけWebGLRendererのまま残してください。移植の出発点には、公式のGLSL→TSLトランスパイラー(英語)が使えます。APIの詳細はTSLのWiki(英語)にまとまっています。
2-7. ステップ7:バックエンドを検出する
フォールバックを自作する必要はありません。WebGPURendererが自動で行います。必要なのは、ログ・分析・画質調整のために、どちらのバックエンドで動いているかを知ることです。
import * as THREE from 'three/webgpu';
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init();
// isWebGPURendererは両バックエンドでtrueなので、バックエンドに問い合わせる
const backendName = renderer.backend.isWebGPUBackend ? 'WebGPU' : 'WebGL 2';
console.log(`Rendering with ${backendName}`);
確認はinit()の完了後か、アニメーションループの中で行います。それより前のrenderer.backendは、フォールバックする環境でもWebGPUバックエンドのオブジェクトのままです。
WebGPU対応のマシンでWebGL 2の動作を確認したいときは、強制的に切り替えます。URLパラメーターで切り替えられるようにしておくと便利です。
const forceWebGL = new URLSearchParams(location.search).has('webgl');
const renderer = new THREE.WebGPURenderer({ antialias: true, forceWebGL });
フォールバックの詳細は4章で解説します。
2-8. ステップ8:クロスブラウザテスト
| 対象 | 確認すること |
|---|---|
| Chrome / Edge | 基準となる環境。chrome://gpuに「WebGPU: Hardware accelerated」と表示されるか |
| Firefox | WindowsとApple Silicon MacではWebGPU、LinuxとAndroidではWebGL 2バックエンド |
| Safari | macOSとiOSを別々に。バージョン26未満の端末はWebGL 2バックエンドで動く |
?webgl付きの任意のブラウザ | 強制したWebGL 2バックエンドでの色、影、ポストプロセス、コンピュートの結果 |
あわせて確認すること:
- オプションのGPU機能は、初期化後に
renderer.hasFeature()で確認する(例:'timestamp-query')。ブラウザが対応している前提で書かない - iOSとAndroidでのタッチ操作
- HTTPのステージング環境:
navigator.gpuはセキュアコンテキスト(HTTPSまたはlocalhost)にしか存在しないため、http://のステージングURLでは必ずフォールバックします
3. React Three Fiber + WebGPU統合
React Three Fiber(R3F)はWebGPUに対応していますが、設定はglプロップの書き方で決まります。
3-1. R3FのWebGPU対応状況
2026年9月時点の安定版はR3F 9系(2026年9月22日リリースの9.8.0)で、バージョン10はアルファ版です。R3F 9では次のようになっています。
glプロップに関数を渡すと、キャンバスを含むデフォルトのレンダラー設定が引数として渡され、Promiseを返すこともできます。WebGPURendererの非同期初期化にはこれが必要です(R3F v9移行ガイド(英語))three/webgpuをextend(THREE)で登録すると、ノードマテリアルをJSX要素として使えます- シェーダーにパッチを当てるコンポーネントや、WebGL用のレンダーターゲットを作るコンポーネントは置き換えが必要です(3-3)
3-2. R3FでWebGPURendererを設定する
R3FのCanvasドキュメント(英語)に沿った書き方です。
import * as THREE from 'three/webgpu';
import { Canvas, extend } from '@react-three/fiber';
// ノードマテリアルを含む、three/webgpuの全クラスをJSX要素として登録する
extend(THREE);
export default function App() {
return (
<Canvas
gl={async (props) => {
const renderer = new THREE.WebGPURenderer(props);
await renderer.init();
return renderer;
}}
>
<ambientLight intensity={0.5} />
<directionalLight position={[2, 2, 2]} />
<mesh>
<boxGeometry />
<meshStandardNodeMaterial color="orange" />
</mesh>
</Canvas>
);
}
propsにはR3Fのデフォルト設定(canvas、antialias、alpha、powerPreference: 'high-performance')が入っているため、レンダラーはCanvas要素に描画されます。TypeScriptの場合、R3FのドキュメントではThreeElementsインターフェースをThreeToJSXElements<typeof THREE>で拡張し、ノードマテリアルの要素にも型が付くようにしています。
R3F 9.8.0とr186の組み合わせでは、コンソールに警告が2つ出ます。THREE.Clock: This module has been deprecatedはR3Fが内部でClockを使っているためで、無視して構いません。PCFSoftShadowMap has been removedは、R3FがデフォルトでPCFSoftShadowMapを選ぶために出ます。<Canvas>にshadows="percentage"を渡せば、最初からPCFShadowMapが使われます。
3-3. Dreiコンポーネントの互換性
オブジェクト、ローダー、DOMオーバーレイだけを扱うDreiのコンポーネントは、レンダラーの種類に依存しません。一方、シェーダーにパッチを当てるものや、WebGL用のレンダーターゲットを作るものは影響を受けます。Drei 10.7.8、R3F 9.8.0、three.js r186の組み合わせで、両方のバックエンドを確認した結果です。
| コンポーネント | WebGPURendererでの状況 |
|---|---|
OrbitControls、Html | 私たちのテストでは両バックエンドで動作 |
useGLTF | レンダラーに依存しないローダーのため、動作する見込み |
presetかfilesを指定したEnvironment | 私たちのテストでは両バックエンドで動作(presetで確認) |
子要素を持つEnvironment(キューブマップに描画) | WebGPUバックエンドのみ。内部でWebGLCubeRenderTargetを作成しますが、three.jsのMigration Guideによればr183以降のWebGPURendererでは使えません。テストでもWebGL 2バックエンドでは映り込みが描画されませんでした |
Text | 非対応。troika-three-textがonBeforeCompileでシェーダーにパッチを当てるためです。テストではWebGPUのレンダーパスがエラーで止まり、WebGL 2では何も描画されませんでした |
Text3D | 通常のジオメトリを生成するため、onBeforeCompileの問題はありません(未テスト) |
EffectComposer(@react-three/postprocessing) | 非対応。WebGLRenderer向けのpmndrs/postprocessingをラップしているため |
WebGPUで動くコンポーネントでも、WebGL 2のフォールバックでは失敗することがあります。実際のシーンで両方のバックエンドを確認してください。
3-4. R3F + WebGPUでよくある落とし穴
落とし穴1:初期化していないレンダラーを返す
R3Fは独自のフレームループからgl.render()を呼ぶため、最初のフレームまでにレンダラーの初期化が終わっている必要があります。r186では、未初期化のWebGPURendererで描画するとエラーになります。
// 間違い:R3F 8の書き方で、しかもレンダラーが初期化されない
gl={(canvas) => new THREE.WebGPURenderer({ canvas })}
// 正解:R3F 9はデフォルト設定を渡してくる。返す前にinit()をawaitする
gl={async (props) => {
const renderer = new THREE.WebGPURenderer(props);
await renderer.init();
return renderer;
}}
落とし穴2:glでWebGLRenderer専用のAPIを使う
const gl = useThree((state) => state.gl);
// gl.capabilitiesのようなWebGLRenderer専用のプロパティは、WebGPURendererにはありません。
// バックエンドで分岐したいときは、バックエンドに直接問い合わせます:
const usingWebGPU = gl.backend.isWebGPUBackend === true;
落とし穴3:インポート元の混在
自分で書くコンポーネントでは、three.jsのクラスをthree/webgpuからインポートします。threeからインポートするライブラリ(Drei、three-stdlib、R3F自体)とも問題なく連携できます。r171以降は両方のエントリーポイントが同じコアモジュールを共有しているので、threeのMeshとthree/webgpuのMeshは同じクラスです。避けるべきなのは、WebGPUのアプリにWebGLRendererを持ち込むことです。r186とesbuildで私たちが試したところ、three/webgpuに加えてthreeからWebGLRendererをインポートするだけで、minify後のバンドルが792 KBから1,155 KB(gzip後は220 KBから307 KB)に増えました。
コンソールに「Multiple instances of Three.js being imported」と表示された場合は、three.jsのコピーが2つ読み込まれています。多くはnode_modules内のバージョン違い(npm ls threeで確認できます)か、CDNとローカルのURLの混在が原因です。
4. WebGL 2フォールバックの仕組み
WebGPURendererはWebGPUとWebGL 2の2つのバックエンドを持っています。アプリは1つだけ書けばよく、どちらを使うかは初期化時にレンダラーが決めます。この章では、フォールバックが起きる条件、バックエンドの検出と強制、WebGL 2側で変わる点を説明します。内容はr186のソースコードとWebGPURendererの公式マニュアル(英語)に基づいています。
4-1. フォールバックが起きる条件
init()(setAnimationLoop()が代わりに呼びます)の中で、レンダラーはWebGPUデバイスの作成を試みます。失敗するとWebGL 2バックエンドに切り替え、次の警告を出します。
THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.
主な原因は次の通りです。
- ブラウザがWebGPUに対応していない(
navigator.gpuがundefined):古いブラウザ、Linux版Firefox、iOS 26未満の端末など - ページがセキュアコンテキストではない:WebGPUにはHTTPSか
localhostが必要です navigator.gpu.requestAdapter()がnullを返す:GPUやドライバーがブロックリストに入っている、ハードウェアアクセラレーションが無効、GPUが古すぎる、など(ChromeのWebGPUトラブルシューティング(英語))- GPUデバイスの作成に失敗した
切り替えは初期化時の1回だけです。その後にバックエンドが変わることはありません。
4-2. バックエンドの強制と検出
// WebGL 2バックエンドを強制する(フォールバックのテストなどに)
const renderer = new THREE.WebGPURenderer({ forceWebGL: true });
await renderer.init();
console.log(renderer.backend.isWebGLBackend === true); // true:WebGL 2バックエンド
console.log(renderer.backend.isWebGPUBackend === true); // false
renderer.backend.isWebGPUBackendはWebGPUバックエンドのときだけ、renderer.backend.isWebGLBackendはWebGL 2バックエンドのときだけtrueになります。renderer.isWebGPURendererはレンダラーのクラスを示すもので、どちらのバックエンドでもtrueなので、判定には使えません。また、init()の完了前に判定しないでください。完了するまでのrenderer.backendは、フォールバックする環境でもWebGPUバックエンドのオブジェクトです。
4-3. WebGPUバックエンドとWebGL 2バックエンドの違い
| 機能 | WebGPUバックエンド | WebGL 2バックエンド |
|---|---|---|
| 標準マテリアル、ノードマテリアル、TSL | ○(TSLはWGSLにコンパイル) | ○(TSLはGLSLにコンパイル) |
RenderPipelineによるポストプロセス | ○ | ○ |
ShaderMaterial、RawShaderMaterial、onBeforeCompile | × | × |
renderer.compute()とinstancedArrayによるコンピュート | ○ | ○(トランスフォームフィードバックで代替実行。ディスパッチ数は単一の数値のみ) |
ワークグループ共有メモリ、ストレージテクスチャ(textureStore()) | ○ | × |
間接ディスパッチと間接描画(geometry.setIndirect()) | ○ | × |
| GPUタイムスタンプ計測 | timestamp-query機能があれば可 | EXT_disjoint_timer_query_webgl2拡張があれば可 |
4-4. WebGL 2も使えない場合
どちらのバックエンドも起動できないと、init()はrejectされます(setAnimationLoop()が返すPromiseも同様です)。これを捕捉して、静的な代替表示をページに残します。
async function startScene(poster) {
const renderer = new THREE.WebGPURenderer({ antialias: true });
try {
await renderer.init();
} catch (error) {
// WebGPUもWebGL 2も使えない:ポスター画像を表示したままにする
console.warn('3D disabled:', error);
return null;
}
poster.replaceWith(renderer.domElement);
return renderer;
}
ポスター画像と、キャンバスの周りに置く実際のHTMLテキストは、検索エンジンのクローラーや低スペック端末にも有効です。詳しくはWebGL・Three.jsサイトのSEO完全ガイドをご覧ください。
4-5. ユーザーへの見せ方
どちらのバックエンドで動いているかを、訪問者に伝える必要はありません。WebGL 2バックエンドはエラーではなく正式な動作モードです。画質の調整は目立たない形で行い、メッセージは3Dがまったく起動できないとき(4-4)だけにします。
// 悪い例
alert('お使いのブラウザはWebGPUに対応していません!');
// 良い例:同じシーンのまま、WebGL 2バックエンドでは設定を軽くする
await renderer.init();
if (renderer.backend.isWebGLBackend) {
renderer.setPixelRatio(1);
}
5. TSL(Three Shader Language)の基礎
TSLは、WebGPURenderer向けのシェーダーを書くための仕組みです。
5-1. なぜ生のWGSLではなくTSLなのか
| アプローチ | メリット | デメリット |
|---|---|---|
| 生のWGSL | 細部まで制御できる | WebGPU専用で、記述量が多い |
| 生のGLSL | 書き慣れた構文 | WebGLRenderer専用 |
| TSL | WebGPURendererの両バックエンドで動き、組み合わせやすい | 習得に時間がかかる |
TSLはWebGPUバックエンドではWGSLに、WebGL 2バックエンドではGLSLにコンパイルされるため、1つのシェーダーで両方に対応できます。
5-2. TSLの基本構文
TSLはJavaScriptそのものです。シェーダーの文字列を書く代わりに、ノードに対して数学的なメソッドをつなげていきます。
import * as THREE from 'three/webgpu';
import { Fn, normalLocal, positionLocal, sin, time, uv, vec4 } from 'three/tsl';
// 再利用できる関数:UV座標から色を作る
const uvColor = Fn(() => {
const coords = uv();
return vec4(coords.x, coords.y, 0.5, 1.0);
});
// 再利用できる関数:法線方向にアニメーションする変位
const wobble = Fn(() => {
const t = time.mul(2.0);
const displacement = sin(positionLocal.x.mul(10.0).add(t)).mul(0.1);
return positionLocal.add(normalLocal.mul(displacement));
});
const material = new THREE.MeshBasicNodeMaterial();
material.colorNode = uvColor();
material.positionNode = wobble();
timeはレンダラーが毎フレーム更新する組み込みのuniformです。Fnで作った関数は複数のマテリアルで使い回せます。
5-3. GLSLからTSLへの書き換えパターン
フレネル効果:
// GLSL
float fresnel = pow(1.0 - dot(viewDirection, normal), 3.0);
// TSL
import { Fn, color, float, normalView, positionViewDirection } from 'three/tsl';
const fresnel = Fn(() => {
const nDotV = normalView.dot(positionViewDirection).saturate();
return float(1.0).sub(nDotV).pow(3.0);
});
// MeshStandardNodeMaterialの輪郭を光らせる
material.emissiveNode = fresnel().mul(color(0x66ccff));
positionViewDirectionはビュー空間における表面からカメラへの方向なので、組み合わせるのはnormalLocalではなくnormalViewです。TSLにviewDirectionというエクスポートはありません。
ノイズによる変位:
import { mx_noise_float, normalLocal, positionLocal, time } from 'three/tsl';
const noiseInput = positionLocal.add(time.mul(0.5));
const n = mx_noise_float(noiseInput); // MaterialXのパーリンノイズ
material.positionNode = positionLocal.add(normalLocal.mul(n.mul(0.2)));
TSLにはMaterialXのノイズ関数(mx_noise_float、mx_noise_vec3、mx_fractal_noise_floatなど)が用意されています。noise3Dという関数はありません。ほかのパターンや最適化のコツはThree.jsベストプラクティス100選で紹介しています。
6. コンピュートシェーダーのパターン
コンピュートシェーダーは、汎用的な計算をGPUで実行する仕組みです。WebGPURendererではTSLで記述します。
6-1. コンピュートシェーダーを使うべき場面
要素ごとの処理をJavaScriptで行い、毎フレームGPUへデータを送っているなら、コンピュートシェーダーに移す候補です。
- パーティクルや群れのシミュレーション
- 物理演算や流体シミュレーション
- プロシージャルなジオメトリや地形の生成
- 間接描画につなげるGPU側のカリング(WebGPUバックエンドのみ)
効果の源は、データをGPU上に置いたままにできることです。公式のコンピュートパーティクルのサンプル(英語)は、この方法で20万個のパーティクルをシミュレーションしています。WebGL 2バックエンドでは、three.jsがトランスフォームフィードバックでコンピュートを代替実行します。下のようなバッファの更新は動きますが、WebGPU専用の機能は使えません(4-3)。
6-2. GPUで動かすパーティクルシステム
import * as THREE from 'three/webgpu';
import { Fn, If, hash, instancedArray, instanceIndex, uniform, vec3 } from 'three/tsl';
const count = 200000;
const positions = instancedArray(count, 'vec3'); // フレームをまたいで保持されるGPUバッファ
const velocities = instancedArray(count, 'vec3');
const delta = uniform(0);
// 1回だけ実行:パーティクルをばらまく
const initParticles = Fn(() => {
const position = positions.element(instanceIndex);
position.x = hash(instanceIndex).sub(0.5).mul(20);
position.y = hash(instanceIndex.add(1)).mul(10);
position.z = hash(instanceIndex.add(2)).sub(0.5).mul(20);
})().compute(count);
// 毎フレーム実行:重力と、跳ね返る床
const updateParticles = Fn(() => {
const position = positions.element(instanceIndex);
const velocity = velocities.element(instanceIndex);
velocity.addAssign(vec3(0, -9.8, 0).mul(delta));
position.addAssign(velocity.mul(delta));
If(position.y.lessThan(0), () => {
position.y = 0;
velocity.y = velocity.y.negate().mul(0.8);
});
})().compute(count);
// シミュレーション結果をGPUバッファから直接描画する
const material = new THREE.SpriteNodeMaterial();
material.positionNode = positions.toAttribute();
material.scaleNode = uniform(0.05);
const particles = new THREE.Sprite(material);
particles.count = count;
particles.frustumCulled = false;
scene.add(particles);
// ループ前に1回だけコンピュートを実行する:ここでawait renderer.init()が必要
await renderer.init();
renderer.compute(initParticles);
const timer = new THREE.Timer();
timer.connect(document); // タブが非表示の間は止まり、復帰時に巨大なdeltaが出ない
renderer.setAnimationLoop((timestamp) => {
timer.update(timestamp);
delta.value = timer.getDelta();
renderer.compute(updateParticles); // 結果を読むレンダーパスより先に実行される
renderer.render(scene, camera);
});
古いサンプルからの変更点は3つです。
Fnは、呼び出して.compute(count)を付けたときに初めてコンピュートノードになります。await renderer.computeAsync()の代わりに、setAnimationLoop()の中でrenderer.compute()を呼びます。computeAsync()はr181で非推奨になりました。- フレーム時間はr179でコアに入った
Timerから取得します。Clockはr183で非推奨になりました。
6-3. 物理シミュレーション
複雑な物理演算は、処理をいくつかのコンピュートパスに分けます。
- ブロードフェーズ:空間ハッシュで衝突の候補を絞り込む
- ナローフェーズ:厳密な衝突判定を行う
- 衝突応答:衝突への反応を適用する
- 積分:速度から位置を更新する
各フェーズを1つのコンピュートノードにし、renderer.compute([broadPhase, narrowPhase, resolve, integrate])のように配列で渡すと、1回の呼び出しで順番に実行されます。空間ハッシュではアトミック演算やワークグループメモリを使うことが多いため、WebGPUバックエンドを前提に設計し、WebGL 2バックエンドで何が動くかをテストしてください。
7. パフォーマンスプロファイリング
最適化の前に計測を。しかも両方のバックエンドで計測します。
7-1. stats-glの導入
stats-glは、WebGLRendererとWebGPURendererの両方で、FPS、CPU時間、GPU時間を表示できます。
import Stats from 'stats-gl';
const stats = new Stats({ trackGPU: true, trackCPT: true }); // CPT:コンピュートパスの計測
document.body.appendChild(stats.dom);
await stats.init(renderer);
renderer.setAnimationLoop(() => {
renderer.compute(updateParticles);
renderer.render(scene, camera);
stats.update();
});
GPU時間の計測は、ブラウザとGPUがタイムスタンプに対応しているかどうかで決まります。FPSとCPUのパネルはどの環境でも使えます。
7-2. three.jsのInspectorとGPUデバッグ
r181以降、three.jsにはWebGPURenderer向けのInspectorが付属しており、パフォーマンス、メモリ、タイムラインのパネルを表示できます。
import { Inspector } from 'three/addons/inspector/Inspector.js';
renderer.inspector = new Inspector();
WebGPUのAPIレベルでキャプチャしたい場合は、Brendan Duncan氏の拡張機能WebGPU Inspectorを追加します。Chromeではchrome://gpuでそのマシンのWebGPUがハードウェアアクセラレーションされているかを確認でき、DevToolsのPerformanceパネルで長いフレームやガベージコレクションの停止を確認できます。
7-3. よくあるボトルネック
| 症状 | 主な原因 | 対処 |
|---|---|---|
| オブジェクトが最初に表示されるときにカクつく | シェーダーとパイプラインのコンパイル | ローディング画面の間にawait renderer.compileAsync(scene, camera)を実行 |
| メモリが増え続ける | ジオメトリ、マテリアル、テクスチャ、レンダーターゲットの解放漏れ | 削除するものすべてでdispose()を呼ぶ |
| 特定のマシンだけ遅い | WebGL 2バックエンドやソフトウェアアダプターで動いている | renderer.backend.isWebGPUBackendをログに出し、chrome://gpuを確認 |
| 小さなコンピュートのディスパッチが多い | ノードごとにcompute()を呼んでいる | 配列でまとめて渡す:renderer.compute([a, b, c]) |
8. インスタレーション・キオスクでの注意点
専用ハードウェアなら、ブラウザ、GPU、ドライバーを自分で管理できるため、フォールバックの不確定要素をほとんどなくせます。
8-1. Electronの設定
ElectronのwebPreferencesにwebgpuというオプションはありません。WebGPUが使えるかどうかは、Electronに組み込まれたChromiumのバージョンで決まります。ElectronでのWebGPU対応を求めるIssueでも、Electronのコントリビューターが「Chromiumで動くか動かないか、それだけ」と説明しています(electron/electron #26944(英語))。Electron 25以降はChromium 114以降を搭載しており、WindowsとmacOSではWebGPUがデフォルトで有効です(Electronのリリース一覧(英語))。
// main.js(Electronのメインプロセス)
const { app, BrowserWindow } = require('electron');
// Electronの公式スイッチ:GPUが2つあるマシンで外部GPUを使う
app.commandLine.appendSwitch('force_high_performance_gpu');
app.whenReady().then(() => {
const win = new BrowserWindow({ kiosk: true, frame: false });
win.loadFile('index.html');
});
スイッチはアプリのreadyイベントより前に追加します(Electronのコマンドラインスイッチ(英語))。ページ側では起動時にrenderer.backend.isWebGPUBackendをログに出しておくと、WebGL 2にフォールバックしたキオスクをログから見つけられます。
8-2. WebGPU向けのChromiumフラグ
WindowsとmacOSではフラグは不要です。LinuxのChromeでWebGPUがデフォルトで有効なのは、Intel Gen12以降のGPU(144以降)と、Wayland上のNVIDIA GPU(147以降)だけです。それ以外のLinux GPUについて、gpuwebの実装状況ページは次のフラグを挙げています。
chromium --enable-unsafe-webgpu --ozone-platform=x11 \
--use-angle=vulkan --enable-features=Vulkan,VulkanFromANGLE
--enable-unsafe-webgpuはChromeのWebGPUアダプターのブロックリストを無効にするため、GPUとドライバーを検証済みのマシンでだけ使ってください。起動後はchrome://gpuで「WebGPU: Hardware accelerated」と表示されることを確認します。
8-3. WebGPU向けのハードウェア選定
GPUはスペック表ではなく、実際のシーンを動かして計測したうえで選びます。
- 導入する機種とドライバーそのもので検証する。Linuxの場合は、ChromeのWebGPUデフォルト対応に含まれるGPUかも確認します(8-2)。
- 重いコンピュートやポストプロセスには外部GPUを選ぶ。軽めのシーンなら内蔵GPUでも対応できます。
- テストを通ったらドライバーのバージョンを固定する。ドライバーとOSの自動更新も止めておきます。
- 起動時にバックエンドをログに出す。WebGL 2へのフォールバックに気づけるようにします。
大阪・関西万博2025の北斎インスタレーションでは、最大約100万個のパーティクルをWebGPUでリアルタイムにシミュレーションしました。
9. 移行時のトラブルシューティング
9-1. シェーダーのコンパイルエラー
症状:コンソールにWGSLやGLSLのエラーが出る、またはオブジェクトが真っ黒に描画される。
主な原因と対処:
ShaderMaterialやonBeforeCompileのパッチがシーンに残っている:ShaderMaterialはMaterial "ShaderMaterial" is not compatibleと表示され、何も描画されません。TSLに移植します(ステップ6)。- 存在しないものをインポートしている:TSLの関数は
three/tslから、エフェクトはthree/addons/tsl/display/からインポートします。three/tslからbloom、viewDirection、noise3Dなどをインポートすると、ビルド時にエラーになるか(esbuildでは「No matching export」)、undefinedになります。 - TSLの型の不一致:
float()、vec3()、.toFloat()で明示的に変換します。
生成されたシェーダーコードを読みたいときは、await renderer.debug.getShaderAsync(scene, camera, mesh)を呼ぶと、そのメッシュのWGSLまたはGLSLを取得できます。
9-2. Safari特有の問題
症状:Chromeでは動くのに、Safariではエラーになる、またはフォールバックする。
確認すること:
- OSのバージョン:WebGPUにはmacOS 26、iOS 26、iPadOS 26、visionOS 26が必要です。それより古い端末はWebGL 2バックエンドで動きます。
- オプション機能:対応している前提で書かず、
renderer.hasFeature()で確認します。 - Webインスペクタのコンソールに出るWebGPUの検証メッセージ。
対処:早い段階から実機のApple製品で、両方のバックエンド(?webgl)をテストします。
9-3. メモリ管理
WebGPURendererでも、GPUメモリの解放方法はWebGLRendererと同じくdispose()です。
// 削除するものはすべてdisposeする
mesh.geometry.dispose();
mesh.material.dispose();
texture.dispose();
renderTarget.dispose();
// コンピュートノード:dispose()でパイプラインとバインディングが解放される
updateParticles.dispose();
コンテンツの追加と削除を繰り返しながらrenderer.info.memoryを確認し、数値が元の水準に戻ることを確かめます。
10. Utsuboについて
Utsuboは、Three.js、WebGPU、インタラクティブ・インスタレーションを専門とする大阪のクリエイティブ・テクノロジースタジオです。three.jsのWebGPUレンダラーには、その開発初期から取り組んできました。
これまでに手がけたWebGPUプロジェクトの例です。
- 大阪・関西万博2025「Waves of Connection」:来場者の動きに反応する、最大約100万個のパーティクルによるWebGPUシミュレーション
- Vectr:リアルタイムのWebGPU 3Dヒーロー、WebGLフォールバック、Web Workerでのメインスレッド外描画を組み合わせたマーケティングサイト
- Segments.ai:LiDAR点群のラベリングプラットフォームを、WebGLからWebGPUへ移行する支援を行いました
WebGPU移行やパフォーマンス診断は、専門サービスのWebGPU Expertsでもお受けしています。
11. ご相談ください
Three.jsプロジェクトのWebGPU移行をご検討中ですか?私たちはインタラクティブ体験、プロダクトコンフィギュレーター、没入型ブランドプロジェクトでチームと協業しています。
パートナーシップをご検討中なら、プロジェクトについてお話しましょう:
- 何を構築しているか、どのような制約があるか
- 目標に対してどの技術アプローチが適切か
- 私たちが実行をお手伝いするのに適したパートナーかどうか
移行チェックリスト
作業で出てくる順に並べた34項目です。
棚卸し(5項目)
- three.jsのバージョンを記録し(
npm ls three)、コピーが1つだけであることを確認する ShaderMaterialとRawShaderMaterialをすべて洗い出す- サードパーティライブラリ内も含め、
onBeforeCompileのパッチをすべて洗い出す EffectComposer、pmndrs/postprocessing、@react-three/postprocessingで組んだポストプロセスを洗い出す- WebGL専用のAPI(
renderer.getContext()の呼び出し、WebGLCubeRenderTarget、renderer.capabilities)を洗い出す
レンダラー(5項目)
- r186に更新する(古いプロジェクトは10リリース程度ずつ)
three/webgpuからインポートし、WebGPURendererを作成するsetAnimationLoop()から描画する。ループ外で描画やコンピュートを行う前にはawait renderer.init()を呼ぶrenderAsync()とcomputeAsync()をrender()とcompute()に置き換えるClockをTimerに置き換え、timer.connect(document)を呼ぶ
シェーダー(4項目)
ShaderMaterialとRawShaderMaterialを、TSLを使ったノードマテリアルに移植するonBeforeCompileのパッチを、ノードのプロパティ(colorNode、positionNode、normalNodeなど)に置き換える- 移植のたびに色を見比べる(ノードマテリアルには出力の色変換がかかる)
three/tslからなくなった名前を置き換える。例:viewportResolutionはscreenSize、rangeFog()はfog(color, rangeFogFactor(near, far))
ポストプロセス(3項目)
EffectComposerをRenderPipeline(r183までの名前はPostProcessing)に置き換えるbloomなどのエフェクトはthree/addons/tsl/display/からインポートする- トーンマッピングの後に実行すべきエフェクト(FXAA、LUTなど)がある場合は、
outputColorTransform = falseにしてrenderOutput()を追加する
コンピュート(3項目)
- 毎フレームのCPUでのバッファ更新を、
instancedArrayとFn(...)().compute(count)に移す renderer.compute()はsetAnimationLoop()の中で、そのデータを読む描画より先に呼ぶ- WebGPU専用のコンピュート機能(ワークグループメモリ、ストレージテクスチャ、間接ディスパッチ)は、バックエンドの判定の内側に置く
シャドウ(2項目)
PCFSoftShadowMapを、ソフトシャドウになったPCFShadowMapに置き換える(WebGPURendererではr186で廃止。R3Fではshadows="percentage"を指定)- シャドウのバイアスを再調整する(WebGPUのシャドウはr183で変更)。広い屋外シーンでは、r186で追加された
SunLight(2段のカスケードシャドウマップ)も検討する
フォールバック(3項目)
- バックエンドの判定は、初期化後に
renderer.backend.isWebGPUBackendで行う(renderer.isWebGPURendererは使わない) - WebGL 2バックエンドをどのマシンでもテストできるよう、
forceWebGLの切り替え(例:?webgl)を用意する init()のrejectを捕捉し、WebGPUもWebGL 2も使えない場合は静的なポスターを表示したままにする
React Three Fiber(3項目)
- R3F 9の非同期
glファクトリーを使う:new WebGPURenderer(props)の後にawait renderer.init() - ノードマテリアルをJSXで使うため、
three/webgpuをextend(THREE)で登録する - Dreiの
Text、子要素を持つEnvironment、@react-three/postprocessingを置き換える
テストとパフォーマンス(4項目)
- Chrome、Edge、Firefox、Safari(macOSとiOS)でテストする
- すべての対象環境で、WebGL 2バックエンドをテストする(強制した場合と、WebGPU非対応の端末の両方)
- WebGPUにはセキュアコンテキストが必要なため、ステージング環境もHTTPSで配信する
- 両方のバックエンドをstats-glかInspectorで計測し、
compileAsync()で事前コンパイルする
キオスク(2項目)
- 導入するハードウェア、ドライバー、Electronのバージョンそのもので、
chrome://gpuに「WebGPU: Hardware accelerated」と表示されることを確認する - 起動時に使用中のバックエンドをログに出し、承認後はドライバーとElectronのバージョンを固定する
まとめ
2026年のThree.jsのWebGPU移行は、描画処理の作り直しというより移植作業です。レンダラーの置き換えはインポート1行で、非同期の初期化はsetAnimationLoop()が引き受け、WebGL 2へのフォールバックも自動で行われます。工数がかかるのは、カスタムGLSL(ShaderMaterial、RawShaderMaterial、onBeforeCompile)、EffectComposerによるポストプロセス、WebGL専用ライブラリの3つで、いずれもTSLでの置き換えが必要です。置き換えたコードは両方のバックエンドで動きます。すべての対象環境で両方のバックエンドをテストし、renderer.backend.isWebGPUBackendでバックエンドを判定し、WebGPUもWebGL 2も使えない端末には静的なポスターを用意しておきましょう。以下では、よくいただく質問にお答えします。
よくある質問
Three.jsはWebGPUをサポートしていますか?
はい。r171(2024年11月29日)以降、追加のビルド設定なしでWebGPUを使えます。import * as THREE from 'three/webgpu'でWebGPURendererを読み込めば、WebGPUが使える環境ではWebGPUで、使えない環境では自動的にWebGL 2で描画されます。最新版はr186(2026年9月8日)です。公式マニュアルではまだ実験的な段階とされているため、実際のシーンを両方のバックエンドでテストしてください。
React Three FiberはWebGPUをサポートしていますか?
はい。R3F 9では、glプロップにデフォルトのレンダラー設定を受け取る非同期関数を渡せます。new THREE.WebGPURenderer(props)でレンダラーを作成し、await renderer.init()を呼んでから返します。ノードマテリアルをJSX要素として使うには、three/webgpuの名前空間をextend(THREE)で登録します。Textのようにシェーダーにパッチを当てるDreiのコンポーネントや、@react-three/postprocessingはWebGPURendererでは動きません。
WebGPUが使えない環境ではどうなりますか?
WebGPURendererは初期化時にWebGL 2バックエンドへ切り替え、「WebGPU is not available, running under WebGL2 backend.」という警告を出します。シーン、ノードマテリアル、TSLシェーダー、RenderPipelineのエフェクトはそのまま動きますが、間接描画、ワークグループメモリ、ストレージテクスチャといったWebGPU専用の機能は使えません。どちらで動いているかは、初期化後にrenderer.backend.isWebGPUBackendで確認できます。WebGL 2も使えない場合はinit()がrejectされるので、静的な代替表示を出してください。
ブラウザがWebGPUに対応しているか確認するには?
Three.jsを使う場合は、レンダラーを作成してawait renderer.init()を呼び、renderer.backend.isWebGPUBackendを確認します。WebGPUで動いているときだけtrueになります。Three.jsを使わない場合は、navigator.gpuが存在し、navigator.gpu.requestAdapter()がアダプターを返すかを確認します。renderer.isWebGPURendererはどちらのバックエンドでもtrueになるため、判定には使えません。
WebGLとWebGPUの違いは何ですか?
WebGPUは、GPUによる描画と計算のための新しいブラウザAPIです。WebGLと比べて、汎用的なGPU計算のためのコンピュートシェーダーが加わり、Chromeチームは同じ描画に対するJavaScriptの負荷が大幅に減るとしています。ただし、すべてのシーンで速くなるわけではなく、WebGLRendererの方が速いthree.jsのシーンもあります。速度を理由に移行する場合は、事前に計測してください。
iOSのSafariはWebGPUをサポートしていますか?
はい。Safari 26(2025年9月)以降、iOS 26、iPadOS 26、macOS 26、visionOS 26で対応しています。バージョン26にアップデートできない端末ではWebGPUを使えないため、Three.jsはWebGL 2バックエンドで描画します。Linux版とAndroid版のFirefoxも安定版ではまだWebGPUに対応していません。主要なブラウザエンジンはすべてWebGPUを搭載しましたが、フォールバックを前提に設計してください。
GLSLシェーダーをWebGPUに対応させるには?
Three.jsのノードベースのシェーダーシステムであるTSL(Three Shader Language)に移植します。TSLはJavaScriptで記述し、WebGPUバックエンドではWGSLに、WebGL 2バックエンドではGLSLにコンパイルされるため、1つのコードで両方に対応できます。ShaderMaterial、RawShaderMaterial、onBeforeCompileのパッチはWebGPURendererではまったく動かないので、カスタムシェーダーはすべて移植が必要です。公式のGLSL→TSLトランスパイラーのサンプルが出発点になります。
WebGPU移行にはどのくらい時間がかかりますか?
レンダラーの置き換えではなく、カスタムコードの量で決まります。標準マテリアルだけを使っているプロジェクトなら、主な作業はインポートと初期化の変更で、あとは両方のバックエンドでのテストです。ShaderMaterial、onBeforeCompileのパッチ、EffectComposerのパスは1つずつTSLで書き直す必要があり、時間の大半はここにかかります。スケジュールを決める前に、ステップ1の棚卸しで作業量を見積もってください。

大阪・心斎橋発。記憶に残るWeb体験を。


