WebGPU + Three.js 移行ガイド(2026年版)

ルカム・ジョスラン

ルカム・ジョスラン

代表取締役、Utsubo株式会社

更新日 ·25分で読めます
WebGPU + Three.js 移行ガイド(2026年版)

Table of Contents

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以降
FirefoxWindowsは141以降。Apple Silicon搭載Macは、macOS 26で145以降、すべてのmacOSで147以降。Intel Mac・Linux・Androidは安定版では未対応
SafarimacOS 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移行で特に影響の大きい最近の変更は次の通りです。

リリース変更内容対応
r181renderAsync()・computeAsync()など*Async系メソッドが非推奨にrender()・compute()を使い、setAnimationLoop()かawait renderer.init()で初期化する
r182レンダラーのオプションcolorBufferTypeが改名outputBufferTypeを使う
r183PostProcessingがRenderPipelineに改名、Clockが非推奨にRenderPipelineとTimerを使う
r183WebGLCubeRenderTargetがWebGPURendererで使えなくなったCubeRenderTargetを使う
r185WebGPURendererのプリマルチプライドアルファの扱いが変更ブレンドがおかしい場合は、不透明なscene.backgroundかクリアカラーを設定する
r185positionNode内のpositionLocalが、スキニングなどの内部変換を反映しなくなった変換前の頂点であるpositionGeometryを基準に組み立てる
r186WebGPURendererでPCFSoftShadowMapが廃止ソフトシャドウになったPCFShadowMapを使う
r186TSLの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」と表示されるか
FirefoxWindowsとApple Silicon MacではWebGPU、LinuxとAndroidではWebGL 2バックエンド
SafarimacOSと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専用
TSLWebGPURendererの両バックエンドで動き、組み合わせやすい習得に時間がかかる

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. ブロードフェーズ:空間ハッシュで衝突の候補を絞り込む
  2. ナローフェーズ:厳密な衝突判定を行う
  3. 衝突応答:衝突への反応を適用する
  4. 積分:速度から位置を更新する

各フェーズを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の棚卸しで作業量を見積もってください。

JR西日本、中小機構をはじめ、BMW、Louis Vuitton など国内外ブランドのWeb・インタラクティブ制作を手がける受賞歴のあるスタジオです。

JRSMRJLouis VuittonBMWWarnerKiaLeague of Legends

プロジェクトのご相談
はこちら

構想中のアイデアをお聞かせください。

1〜2営業日以内にご返信します。

このフィールドを入力してください。

このフィールドを入力してください。

このフィールドを入力してください。

またはこちらから打ち合わせを予約

送信できませんでした。お手数ですが、時間をおいて再度お試しください。

送信が完了しました。1〜2営業日以内にご返信いたします。

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

ストーリー×先端技術で惹きつけ、成果につながる導線まで一貫して設計します。

詳しく見る