📖 目次
- WebGPUとは?何ができるの?
- 事前準備:ブラウザと開発環境を整えよう
- Hello WebGPU:Canvasをクリアしてみよう
- Compute Shader入門:GPUでデータを扱う基礎
- 3D描画の基本:点をつないで三角形を描画
- 粒子システム応用:たくさんの点を動かしてみる
- 機械学習推論応用:TensorFlow.js × WebGPU
- 性能チューニング:速くするコツと注意点
- 実際のフレームワークとPolyfill
- まとめ:どこから学び、次に何をする?
1️⃣ WebGPUとは?何ができるの?
WebGLとの違い
- WebGL: 古いAPI、主に3D描画向け。Compute Shaderは無し
- WebGPU: 描画も計算もできる。最新の“低レベル”GPU制御
具体例
- 3Dゲーム:より複雑なライティングやエフェクト
- 機械学習:ブラウザで画像認識などを高速に実行
- 物理シミュレーション:流体や剛体計算をリアルタイム
🔍 ポイント:WebGPUは“ブラウザ向けのVulkan/DirectX12”と覚えよう
2️⃣ 事前準備:ブラウザと開発環境を整えよう
2.1 Chrome Canaryで試す
- Chrome Canaryをダウンロード
- アドレスバーに
chrome://flags/#enable-unsafe-webgpu
と入力 - 「Enabled」に切り替えて再起動
🎯 なぜCanary?WebGPUはまだ実験段階なので、安定版には入っていないため
2.2 Node.jsでローカル開発(Optional)
# 新規フォルダを作成
mkdir webgpu-demo && cd webgpu-demo
npm init -y
npm install @webgpu/types wgpu-native
@webgpu/types
→ TypeScriptで補完を効かせるwgpu-native
→ Node上でWebGPUを動かす実験用
3️⃣ Hello WebGPU:Canvasをクリアしてみよう
- HTMLに
<canvas>
タグを準備 - JavaScriptでGPUアダプタとデバイスを取得
- クリアカラーでCanvasを塗りつぶす
HTML
<!-- index.html -->
<canvas id="gpu-canvas" width="640" height="360"></canvas>
<script type="module" src="main.js"></script>
main.js
async function init() {
// 1. Canvas要素を取得
const canvas = document.getElementById('gpu-canvas');
// 2. GPUアダプタ(物理GPU情報)をリクエスト
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) return alert('GPUアダプタが見つかりません');
// 3. アダプタから論理デバイスを取得
const device = await adapter.requestDevice();
// 4. CanvasコンテキストをWebGPUに設定
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
// 5. コマンドバッファを作成
const encoder = device.createCommandEncoder();
// 6. 現在のテクスチャ(キャンバス)を取得
const view = context.getCurrentTexture().createView();
// 7. レンダーパス(描画処理)の設定
const pass = encoder.beginRenderPass({
colorAttachments: [{
view,
clearValue: { r: 0.1, g: 0.2, b: 0.3, a: 1.0 }, // 背景色
loadOp: 'clear', storeOp: 'store'
}]
});
pass.end(); // 描画コマンドを終了
// 8. GPUキューに命令を送信
device.queue.submit([encoder.finish()]);
}
// ページ読み込み後に実行
init();
解説(初心者向け)
- adapter: コンピューター内のGPU性能を扱う「窓口」
- device: GPUに描画や計算を依頼する「電話機」
- context.configure: CanvasをWebGPU用に初期化
- CommandEncoder: やることリスト(レンダリング命令)を蓄積する箱
- RenderPass: クリアや描画の具体的な手順をラッピング
- queue.submit: リストをGPUに渡して実行
🔑 完全に「Canvasを好きな色で塗りつぶす」だけの最小構成です
4️⃣ Compute Shader入門:GPUでデータを扱う基礎
GPUはピクセルだけでなく、数値配列を並列処理できます。
4.1 JavaScript側:バッファを作る
// 1. 倍にしたいデータの例
const array = new Float32Array([1, 2, 3, 4]);
// 2. GPUに置くバッファを作成
const buffer = device.createBuffer({
size: array.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
});
// 3. CPU上のデータをGPUバッファにコピー
device.queue.writeBuffer(buffer, 0, array.buffer);
4.2 WGSL(シェーダー言語)
// data[0..3] を2倍にするシェーダー
@group(0) @binding(0) var<storage, read_write> data : array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id : vec3<u32>) {
let i = id.x; // GPU内の「仕事番号」
data[i] = data[i] * 2.0; // 各要素を処理
}
4.3 JSで実行パイプラインを組む
// 1. シェーダーモジュールを生成
const module = device.createShaderModule({ code: csCode });
// 2. ComputePipelineを作成
const pipeline = device.createComputePipeline({
compute: { module, entryPoint: 'main' }
});
// 3. バッファをbindGroupでシェーダーに渡す
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: { buffer } }]
});
// 4. コマンドバッファに処理を記録
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(Math.ceil(array.length / 64));
pass.end();
// 5. 実行
device.queue.submit([encoder.finish()]);
解説(初心者向け)
- ShaderModule: GPUで動くプログラムを登録する
- ComputePipeline: 計算手順をまとめた設計図
- BindGroup: パイプラインにデータ(バッファ)を紐付け
- dispatchWorkgroups: GPUに「64並列で何周すればいい?」と伝える
- 最後にsubmitで実行完了!
💡 GPUは一度に大量の数値を処理するのが得意。画像処理や機械学習の基盤になります。
5️⃣ 3D描画の基本:点をつないで三角形を描画
WebGPUで最も基本的な描画は“三角形を1つ画面に描く”ことです。初心者向けにステップバイステップで解説します。
5.1 頂点データの準備
// main.js の初めに追加
// 1. 三角形の頂点座標 (x, y, z)
const vertices = new Float32Array([
-0.5, -0.5, 0.0, // 左下
0.5, -0.5, 0.0, // 右下
0.0, 0.5, 0.0 // 上
]);
// 2. GPU バッファ作成: VERTEX と COPY_DST の用途宣言
const vertexBuffer = device.createBuffer({
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
});
// 3. CPU 配列を GPU バッファに書き込む
device.queue.writeBuffer(vertexBuffer, 0, vertices.buffer);
解説:
Float32Array
は JavaScript 上で扱う数値配列GPUBufferUsage.VERTEX
は「頂点データ用」COPY_DST
は「CPU→GPU コピー許可」
5.2 WGSL シェーダーの記述
vertex.wgsl
@vertex
fn vs_main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
// 画面座標に変換して返却
return vec4<f32>(pos, 1.0);
}
fragment.wgsl
@fragment
fn fs_main() -> @location(0) vec4<f32> {
// 赤色で塗る
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
解説:
@vertex
/@fragment
はそれぞれ頂点/断片シェーダーを示すアノテーション@location(0)
はシェーダー間の入出力スロット番号を指定@builtin(position)
はクリップ空間座標を意味する
5.3 レンダーパイプラインの構築
// ShaderModule 作成
const vsModule = device.createShaderModule({ code: await fetch('vertex.wgsl').then(r=>r.text()) });
const fsModule = device.createShaderModule({ code: await fetch('fragment.wgsl').then(r=>r.text()) });
// パイプライン生成
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {
module: vsModule,
entryPoint: 'vs_main',
buffers: [{
arrayStride: 3 * 4, // vec3<f32> = 4バイト×3
attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }]
}]
},
fragment: {
module: fsModule,
entryPoint: 'fs_main',
targets: [{ format }]
},
primitive: { topology: 'triangle-list', cullMode: 'back' }
});
解説:
layout: 'auto'
で自動バインディングレイアウトbuffers
で頂点バッファのレイアウトを指定triangle-list
は三角形描画モード
5.4 描画コマンドの発行とループ
function draw() {
const encoder = device.createCommandEncoder();
const view = context.getCurrentTexture().createView();
const pass = encoder.beginRenderPass({
colorAttachments: [{ view, clearValue: {r:0,g:0,b:0,a:1}, loadOp:'clear', storeOp:'store' }]
});
pass.setPipeline(pipeline);
pass.setVertexBuffer(0, vertexBuffer);
pass.draw(3, 1); // 頂点数=3, インスタンス数=1
pass.end();
device.queue.submit([encoder.finish()]);
requestAnimationFrame(draw);
}
// 初回呼び出し
draw();
解説:
- CommandEncoder: 描画命令をためる箱
- beginRenderPass: 描画範囲の指定・クリア処理
- setPipeline / setVertexBuffer: シェーダー&頂点データ指定
- draw: 指定頂点数で三角形描画
- submit: GPUへ命令を送信
- requestAnimationFrame: 連続描画 (ループ)
🎉 これで画面に赤い三角形が表示されるはずです!
6️⃣ 粒子システム応用:たくさんの点を動かしてみる
この章では、多数の粒子(点)をGPUだけで高速に動かし描画する方法を学びます。粒子システムはCGやゲームに欠かせない技術ですが、CPUでは重い処理もGPUならリアルタイムで実現できます。
6.1 粒子データの初期化
まずは JavaScript で粒子の位置データを作成し、GPUバッファに転送します。
// 粒子数
const numParticles = 100000;
// 2D 座標 x,y の配列 (float32)
const positions = new Float32Array(numParticles * 2);
for (let i = 0; i < numParticles; i++) {
// ランダムに [-1,1] の範囲で初期配置
positions[2 * i] = Math.random() * 2 - 1; // x
positions[2 * i + 1] = Math.random() * 2 - 1; // y
}
// GPU用バッファを作成
const posBuffer = device.createBuffer({
size: positions.byteLength,
usage: GPUBufferUsage.STORAGE // Computeで read/write
| GPUBufferUsage.VERTEX // VertexShaderで利用
| GPUBufferUsage.COPY_DST // CPU→GPU コピー
});
// データを書き込む
device.queue.writeBuffer(posBuffer, 0, positions);
解説:
numParticles
は描画する点の数positions
配列は[x0, y0, x1, y1, ...]
の形式- バッファは STORAGE (計算用) と VERTEX (描画用) を両方指定
6.2 Compute Shader で位置を更新
次に、Compute Shader(WGSL)を使って各粒子に動きを加えます。ここではノイズを利用した揺らぎを与えます。
update.wgsl
@group(0) @binding(0) var<storage, read_write> pos : array<vec2<f32>>;
// シンプルなノイズ関数
fn rand(v: vec2<f32>) -> f32 {
let dotv = dot(v, vec2<f32>(12.9898, 78.233));
return fract(sin(dotv) * 43758.5453);
}
@compute @workgroup_size(256)
fn cs_main(@builtin(global_invocation_id) gid : vec3<u32>) {
let i = gid.x;
if (i >= arrayLength(&pos)) { return; }
var p = pos[i];
// ノイズ量を計算
let n = rand(p) * 2.0 - 1.0;
// y方向に少しずつ動かす
p.y += n * 0.002;
// 端を超えたら反対側へループ
if (p.y > 1.1) { p.y = -1.1; }
pos[i] = p;
}
解説:
@builtin(global_invocation_id)
は各スレッドのIDworkgroup_size(256)
は256粒子ずつ並列処理rand
関数で擬似ノイズを生成pos[i]
のy
値を更新し、範囲外はループさせる
6.3 描画用シェーダー
粒子を点として可視化するためのシンプルな Vertex/Fragmentシェーダーです。
particle_vertex.wgsl
struct VSOut { @builtin(position) position : vec4<f32>; @location(0) color : vec4<f32>; };
@vertex
fn vs_main(@location(0) p : vec2<f32>) -> VSOut {
var out : VSOut;
// vec2 -> vec4 へ変換 (x,y,0,1)
out.position = vec4<f32>(p, 0.0, 1.0);
// 位置に応じて色を変化 (例: y でグラデーション)
out.color = vec4<f32>(0.5 + p.y * 0.5, 0.8, 1.0 - p.y * 0.5, 1.0);
return out;
}
particle_fragment.wgsl
@fragment
fn fs_main(@location(0) color : vec4<f32>) -> @location(0) vec4<f32> {
return color;
}
解説:
- Vertex で座標
p
をクリップ空間に変換 @location(0) color
で色データを渡す- Fragment はそのまま色を出力
6.4 GPU パイプラインとループ処理
// Compute パイプライン
const csModule = device.createShaderModule({ code: await fetch('update.wgsl').then(r=>r.text()) });
const csPipeline = device.createComputePipeline({ compute: { module: csModule, entryPoint: 'cs_main' } });
const csBindGroup = device.createBindGroup({ layout: csPipeline.getBindGroupLayout(0), entries: [{ binding:0, resource:{ buffer: posBuffer } }] });
// Render パイプライン
const vsModule = device.createShaderModule({ code: await fetch('particle_vertex.wgsl').then(r=>r.text()) });
const fsModule = device.createShaderModule({ code: await fetch('particle_fragment.wgsl').then(r=>r.text()) });
const renderPipeline = device.createRenderPipeline({
layout:'auto',
vertex:{ module:vsModule, entryPoint:'vs_main', buffers:[{ arrayStride:2*4, attributes:[{ shaderLocation:0, offset:0, format:'float32x2' }] }] },
fragment:{ module:fsModule, entryPoint:'fs_main', targets:[{ format }] },
primitive:{ topology:'point-list' }
});
// 描画ループ
function frame() {
const commandEncoder = device.createCommandEncoder();
// ① Compute Pass: 位置更新
const computePass = commandEncoder.beginComputePass();
computePass.setPipeline(csPipeline);
computePass.setBindGroup(0, csBindGroup);
computePass.dispatchWorkgroups(Math.ceil(numParticles / 256));
computePass.end();
// ② Render Pass: 点描画
const view = context.getCurrentTexture().createView();
const renderPass = commandEncoder.beginRenderPass({ colorAttachments:[{ view, loadOp:'clear', clearValue:{r:0,g:0,b:0,a:1}, storeOp:'store' }] });
renderPass.setPipeline(renderPipeline);
renderPass.setVertexBuffer(0, posBuffer);
renderPass.draw(numParticles, 1);
renderPass.end();
// GPU に送信
device.queue.submit([commandEncoder.finish()]);
// 次のフレームを予約
requestAnimationFrame(frame);
}
frame();
解説:
- Compute Pass で粒子位置を更新
- Render Pass で更新された位置を点として描画
dispatchWorkgroups
で並列数を指定、draw(numParticles)
で全粒子描画requestAnimationFrame
でループ実行
🚀 GPUだけで 10万粒子のアニメーションがリアルタイム表示可能に!
これで粒子システムの基本が完成です。次は「7️⃣ 機械学習推論応用:TensorFlow.js × WebGPU」に進みます。
7️⃣ 機械学習推論応用:TensorFlow.js × WebGPU
ブラウザ上で機械学習モデルを動かす際、CPU処理だけでは遅いことがあります。ここでは TensorFlow.js の WebGPU バックエンドを利用し、GPUの並列処理を活かした推論を行います。
7.1 環境セットアップ
npm install @tensorflow/tfjs @tensorflow/tfjs-backend-webgpu
HTML にスクリプトを読み込み:
<script type="module">
import '@tensorflow/tfjs-backend-webgpu';
import * as tf from '@tensorflow/tfjs';
// 以下 7.2 以降のコードをここに記述
</script>
7.2 WebGPU バックエンドの有効化
// どのバックエンドを使うか設定
await tf.setBackend('webgpu');
await tf.ready();
console.log('Backend:', tf.getBackend()); // 'webgpu' と表示されればOK
解説:
setBackend('webgpu')
で GPU 実行モードに切替await tf.ready()
で内部の WebGPU 初期化完了を待機
7.3 モデルのロード
今回は事前学習済み MobileNetV2(小型画像分類モデル)を使用します。
const MODEL_URL = 'https://tfhub.dev/google/tfjs-model/imagenet/mobilenet_v2_100_224/classification/3/default/1';
const model = await tf.loadGraphModel(MODEL_URL, { fromTFHub: true });
console.log('Model loaded');
解説:
loadGraphModel
で標準化されたTFHubモデルを取得- WebGPU へ自動的に最適化されたグラフが内部生成される
7.4 画像前処理
Canvas や画像要素から Tensor を作成し、リサイズ・正規化します。
// 例: <img id="input-img" src="cat.jpg" /> がある場合
const img = document.getElementById('input-img');
let tensor = tf.browser.fromPixels(img)
.resizeNearestNeighbor([224, 224]) // モデル入力サイズ
.toFloat()
.div(255.0) // 0-1に正規化
.expandDims(); // バッチ次元を追加
解説:
fromPixels
で HTML の画像データを取得resizeNearestNeighbor
で指定サイズに変更div(255)
で 0〜255 のピクセル値を 0〜1 にマップexpandDims
で[height, width, channels]
→[1, h, w, c]
7.5 推論実行 & 結果表示
// 推論開始
const predictions = await model.predict(tensor).data();
// 結果上位5件を取得
const top5 = Array.from(predictions)
.map((p, i) => ({ probability: p, className: IMAGENET_CLASSES[i] }))
.sort((a, b) => b.probability - a.probability)
.slice(0, 5);
console.log('Top-5 predictions:');
top5.forEach((p, i) => console.log(`${i+1}. ${p.className}: ${ (p.probability*100).toFixed(2) }%`));
解説:
model.predict
は内部で GPU コンピュートパスを構築.data()
で結果配列を取得- クラスラベル (
IMAGENET_CLASSES
) は標準リストを参照
7.6 実装まとめとUIサンプル
<input type="file" id="file-input" accept="image/*" />
<img id="input-img" style="max-width:200px;" />
<button id="run-btn">推論実行</button>
<pre id="result"></pre>
<script type="module">
import '@tensorflow/tfjs-backend-webgpu';
import * as tf from '@tensorflow/tfjs';
await tf.setBackend('webgpu'); await tf.ready();
const model = await tf.loadGraphModel(MODEL_URL, { fromTFHub: true });
document.getElementById('file-input').onchange = e => {
const file = e.target.files[0];
const url = URL.createObjectURL(file);
document.getElementById('input-img').src = url;
};
document.getElementById('run-btn').onclick = async () => {
const imgEl = document.getElementById('input-img');
const tensor = tf.browser.fromPixels(imgEl).resizeNearestNeighbor([224,224]).toFloat().div(255).expandDims();
const preds = await model.predict(tensor).data();
const top5 = Array.from(preds).map((p,i)=>({p,i}))
.sort((a,b)=>b.p-a.p).slice(0,5);
document.getElementById('result').textContent = top5.map((x,idx)=>
`${idx+1}. ${IMAGENET_CLASSES[x.i]}: ${(x.p*100).toFixed(2)}%`).join('
');
};
</script>
解説: ユーザーが画像を選択し、ボタンクリックで 即時 GPU 推論 結果を表示する UI。初心者でも組み合わせ例としてコピペOK!
8️⃣ 性能チューニング:速くするコツと注意点
WebGPUを使うと高速処理が可能ですが、より速く・安定して動かすにはいくつか注意点があります。本章では代表的なチューニング手法を初心者向けに解説します。
8.1 バッファのマッピングとメモリ同期
問題:CPUとGPU間のデータコピーがボトルネックに
// 悪い例:毎フレームreadBufferで結果を戻すと遅い
const readBuffer = device.createBuffer({
size: dataSize,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
});
// ... computePass 終了後
device.queue.copyBufferToBuffer(resultBuffer, 0, readBuffer, 0, dataSize);
await readBuffer.mapAsync(GPUMapMode.READ);
const array = new Float32Array(readBuffer.getMappedRange());
- mapAsync はGPU同期を誘発し、数ミリ秒〜数十ミリ秒かかることも
対策:SharedArrayBuffer を使わないケースは最小限に
- 必要なときだけ mapAsync を呼ぶ
- GPU結果はなるべく画面描画で完結させ、CPUに戻さない設計にする
- 例:粒子位置は次のComputeで再利用し、画面にのみ反映する
8.2 ワークグループサイズの最適化
デフォルト256では足りない?多すぎる?
@compute @workgroup_size(256)
fn cs_main(@builtin(global_invocation_id) gid : vec3<u32>) { /* ... */ }
- ワークグループはGPUの並列単位
- 小さいとGPUリソースを持て余し、大きいと割り当て不足
対策:ベンチマークで適切な値を探す
[64,128,256,512]
などで時間計測- 最速かつ使用メモリが少ない設定を採用
for (const size of [64,128,256,512]) {
// 再コンパイル、再測定コード...
}
8.3 メモリアラインメントとバイトサイズ
256バイト境界に注意
- WebGPUではバインドグループのオフセットが256バイト単位でアラインされる必要がある
// NG: サイズが250バイト
const badBuffer = device.createBuffer({ size:250, usage:GPUBufferUsage.UNIFORM });
// OK: 256の倍数
const goodBuffer = device.createBuffer({ size:256, usage:GPUBufferUsage.UNIFORM });
- アラインメント違反すると実行時エラーになることも
8.4 リソースの再利用
毎フレームcreateではなく再利用を
// NG: フレームごとにバッファを作る
function draw() {
const buf = device.createBuffer({ /* ... */ });
// 描画処理...
}
// OK: 外で一度だけ作る
const buf = device.createBuffer({ /* ... */ });
function draw() {
// 更新のみ + 描画処理
}
- オブジェクト生成コストを削減し、GC影響も防ぐ
8.5 プロファイリングツールの活用
- Chrome DevTools → Performance タブ → GPU スレッドを見る
timestampQuery
機能で GPU 処理時間を取得
const querySet = device.createQuerySet({ type: 'timestamp', count: 2 });
encoder.writeTimestamp(querySet, 0);
// compute / render pass
encoder.writeTimestamp(querySet, 1);
device.queue.submit([encoder.finish()]);
// 結果読み取りは mapAsync で同期
- 経過時間を詳細可視化し、どのパスが重いか特定する
8.6 まとめ:速く動かすためのチェックリスト
- mapAsync や readBuffer は最小限に
- ワークグループサイズをベンチマークで調整
- バッファサイズは256バイト境界に揃え、再利用
- プロファイリングでボトルネックを可視化
9️⃣ 実際のフレームワークとPolyfill
WebGPUは低レベルAPIのため、高レベルのラッパーライブラリや互換性を補うPolyfillを活用すると開発がスムーズです。
9.1 wgpu-rs (Rust → WASM)
- 概要:Rust製のWebGPU実装「WGPU」をWASMでブラウザにバインド
- 導入手順:
# Rustツールチェインをインストール curl https://sh.rustup.rs -sSf | sh rustup target add wasm32-unknown-unknown # Cargo.tomlに追記
[dependencies]
wgpu = “0.14” wasm-bindgen = “0.2” # WASMビルド wasm-pack build –target web メリット:型安全・自動メモリ管理・Rustエコシステムと親和性
9.2 Babylon.js の WebGPU レンダラー
概要:Babylon.js v5 以降に実験的WebGPUバックエンドをサポート
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const engine = new BABYLON.Engine(canvas, true, { adaptToDeviceRatio: true });
engine.enableWebGPU(); // WebGPU を有効化
const scene = new BABYLON.Scene(engine);
engine.runRenderLoop(() => scene.render());
</script>
9.3 Three.js の WebGPURenderer
概要:Three.js r134 以降に実験的WebGPUレンダラーが追加
import { WebGPURenderer } from 'three/examples/jsm/renderers/WebGPURenderer.js';
const renderer = new WebGPURenderer({ canvas, antialias: true });
await renderer.initAdapter();
function animate() { renderer.render(scene, camera); requestAnimationFrame(animate); }
animate();
9.4 Polyfill: @shaderfrog/webgpu-polyfill
- 概要:WebGPU未対応環境でWebGL2を代替動作させるPolyfill
- インストール:
npm install @shaderfrog/webgpu-polyfill
利用例:
import { polyfill } from '@shaderfrog/webgpu-polyfill';
await polyfill();
if (!navigator.gpu) { console.warn('WebGPU非対応、WebGL2へフォールバックします');
}
initWebGPU();
🔟 まとめ:どこから学び、次に何をする?
本記事では以下を解説しました:
- Hello WebGPU:Canvasクリアの最小構成
- Compute Shader:GPUで数値を並列計算
- 3D描画:頂点→フラグメントパイプライン
- 粒子システム:10万点をリアルタイム更新
- 機械学習推論:TensorFlow.js × WebGPU
- 性能チューニング:メモリ同期・ワークグループ・バッファ再利用
- ライブラリ/Polyfill:wgpu-rs, Babylon.js, Three.js, Polyfill
次に学ぶべきテーマ:
- WebXR × WebGPU:VR/ARコンテンツ制作
- NeRF実装:ブラウザでNeural Radiance Fields
- サーバーサイドGPU:Node.jsでバッチ計算&レンダリング