Contents
WebGPU導入前の環境確認と基本設定
WebGPUを活用するには、開発環境の準備が不可欠です。特にセキュリティ上の制限により、COOP/COEPヘッダの正しく設定がないと実行できない場合があります。また2023年のブラウザ対応状況も確認しておく必要があります。
COOP/COEPヘッダの設定手順
WebGPUは安全性を確保するため、Cross-Origin-Opener-Policy (COOP) と Cross-Origin-Embedder-Policy (COEP) のヘッダが必要です。これらを正しく設定しないと、セキュリティ制限によりWebGPUが動かなくなる可能性があります。
以下に設定方法を記載します:
- サーバーコンフィギュレーションで
Cross-Origin-Opener-Policy: same-originを指定 Cross-Origin-Embedder-Policy: require-corpを追加- ブラウザ側で
Permissions-Policy: webgpu=(self)を有効化
注意:COOP/COEPの設定は、ローカル開発環境でも必要です。
http-serverやlive-serverなどのツールではデフォルトで対応していないため、手動でヘッダを設定してください。
最新ブラウザ対応状況チェック
2023年の現時点では、以下が主なWebGPU対応ブラウザです:
| ブラウザ | 対応状況 | 特記事項 |
|---|---|---|
| Chrome 125+ | 完全対応 | WebGPU APIの最新仕様をサポート |
| Firefox 119+ | 完全対応 | Rust系のWebGPU実装が安定化 |
| Safari 16.4+ | ベータ版 | Apple Silicon向けに最適化中 |
| Edge 120+ | 完全対応 | DirectX12との連携を強化 |
テスト環境は、ChromeかEdgeが最も安定しています。Safariではまだ一部のシェーダー機能が未実装のため、開発初期段階には避けたほうが良い場合もあります。
Vite+TypeScript環境でWebGPUプロジェクトを構築
ViteとTypeScriptを使ってWebGPUプロジェクトを作成するには、以下のような手順が必要です。特にTypeScript宣言ファイルの導入が重要です。
vite.config.tsの設定例
vite.config.tsに以下の内容を記述します:
|
1 2 3 4 5 6 7 8 9 10 |
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], optimizeDeps: { include: ['@types/webgpu'] } }) |
また、package.jsonに以下の依存関係を追加します:
|
1 2 3 4 |
"dependencies": { "webgpu:latest": "^1.0.0" } |
TypeScript宣言ファイルの準備
TypeScriptでWebGPUを使用するには、型定義ファイルを準備する必要があります。以下のようなwebgpu.d.tsを作成してください:
|
1 2 3 4 5 6 7 8 |
declare namespace WebGPUPolyfill { export interface GPUAdapter { // 実装省略 } } // 実際に必要なインターフェースは`@types/webgpu`からインポート |
npm経由で導入する場合、以下を実行:
|
1 2 |
npm install --save-dev @types/webgpu |
このファイルをプロジェクトルートに配置することで、IDEが型情報を認識できるようになります。
WebGPU APIのライフサイクルと基本構造
WebGPUのAPIは、Adapter → Device → CommandEncoder → RenderPipelineという流れで動作します。それぞれのステップでエラー処理を行うことが重要です。
AdapterとDeviceの取得フロー
-
AdapterFactoryからAdapterを取得:
ts
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) throw new Error('WebGPU not supported'); -
Deviceの生成:
ts
const device = await adapter.requestDevice(); -
CommandEncoderを作成:
ts
const commandEncoder = device.createCommandEncoder();
CommandEncoderの使い方
CommandEncoderは、描画コマンドを収集するためのオブジェクトです。以下のように使用します:
-
RenderPassEncoderの作成:
ts
const passEncoder = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
loadOp: 'clear',
clearValue: { r: 0, g: 0, b: 0, a: 1 },
storeOp: 'store'
}]
}); -
頂点バッファの作成と描画:
ts
passEncoder.setVertexBuffer(0, vertexBuffer);
passEncoder.draw(3, 1, 0, 0); -
コマンドを実行:
ts
device.queue.submit([commandEncoder.finish()]);
ポイント:CommandEncoderは一度に複数の描画コマンドをバッチ処理できるため、パフォーマンス向上に寄与します。
シェーダーの書き方と実際の描画処理
WebGPUで使用するシェーダー言語はWGSL(WebGPU Shading Language)です。基本構文を理解し、三角形描画サンプルを作成してみましょう。
WGSLの基本構文
WGSLはC++やGLSLに近い構文を持ちます。以下の例は頂点シェーダーとフラグメントシェーダーです:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 頂点シェーダー struct VertexOutput { @builtin(position) Position: vec4<f32>, }; @vertex fn vs_main(@location(0) position: vec2<f32>) -> VertexOutput { var output: VertexOutput; output.Position = vec4<f32>(position, 0.0, 1.0); return output; } // フラグメントシェーダー @fragment fn fs_main() -> @location(0) vec4<f32> { return vec4<f32>(1.0, 0.0, 0.0, 1.0); // 赤色を出力 } |
キャンバスへの描画手順
以下は、三角形を描画するための全体的なフローです:
-
頂点データを初期化:
ts
const vertexData = new Float32Array([
0, 0,
-1, 1,
1, 1
]); -
バッファの作成とアタッチメント設定:
ts
const vertexBuffer = device.createBuffer({
size: vertexData.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(vertexBuffer, 0, vertexData.buffer, 0, vertexData.byteLength); -
描画パイプラインの作成と実行:
ts
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {
module: device.createShaderModule({ code: vsCode }),
entryPoint: 'vs_main',
buffers: [{
arrayStride: 2 * 4,
attributes: [{
shaderLocation: 0,
offset: 0,
format: 'float32x2'
}]
}]
},
fragment: {
module: device.createShaderModule({ code: fsCode }),
entryPoint: 'fs_main',
targets: [{ format: context.format }]
}
});
Three.jsとWebGPUの連携実装例
Three.jsで作成したシーンをWebGPUに対応させるには、RendererとMaterialの置き換えが鍵となります。
既存プロジェクトへのWebGPU移行
Three.jsのWebGLRendererはWebGPU対応していないため、以下のように置き換えます:
-
WebGPU Rendererの導入:
ts
import { WebGLRenderer } from 'three';
// ⇒
import { WebGPURenderer } from '@threedotjs/webgpu-renderer'; // 仮想パッケージとして記載(現状では非公式) -
Materialタイプの変更:
ShaderMaterialやMeshStandardMaterialはWebGPU対応版に置き換える必要があります。
シーン描画のカスタマイズ方法
Three.jsのSceneをWebGPUで描画するには、以下の手順が必要です:
-
WebGPURendererの初期化:
ts
const renderer = new WebGPURenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement); -
MaterialのWebGPU版に変更:
ts
const material = new WebGPUMeshStandardMaterial({ color: 0xff0000 }); -
描画ループの実装:
ts
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
即時実践!サンプルコードの確認と実行
以下は、記事内で紹介したすべてのコードを含む実行可能なプロジェクトです。
コピー&ペースト可能なコードブロック
以下のコードをindex.htmlに貼り付け、ブラウザで開いてください:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>WebGPUサンプル</title> <script type="module"> const canvas = document.createElement('canvas'); document.body.appendChild(canvas); const context = canvas.getContext('webgpu'); const adapter = await navigator.gpu.requestAdapter(); const device = await adapter.requestDevice(); const commandEncoder = device.createCommandEncoder(); const passEncoder = commandEncoder.beginRenderPass({ colorAttachments: [{ view: context.getCurrentTexture().createView(), loadOp: 'clear', clearValue: { r: 0, g: 0, b: 0, a: 1 }, storeOp: 'store' }] }); // 頂点バッファの作成 const vertexData = new Float32Array([ 0, 0, -1, 1, 1, 1 ]); const vertexBuffer = device.createBuffer({ size: vertexData.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST }); device.queue.writeBuffer(vertexBuffer, 0, vertexData.buffer, 0, vertexData.byteLength); // シェーダーのロードとパイプライン構築 const shaderModule = device.createShaderModule({ code: ` @vertex fn vs_main(@location(0) position: vec2<f32>) -> @builtin(position) vec4<f32> { return vec4<f32>(position, 0.0, 1.0); } @fragment fn fs_main() -> @location(0) vec4<f32> { return vec4<f32>(1.0, 0.0, 0.0, 1.0); } ` }); const pipeline = device.createRenderPipeline({ layout: 'auto', vertex: { module: shaderModule, entryPoint: 'vs_main', buffers: [{ arrayStride: 2 * 4, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x2' }] }] }, fragment: { module: shaderModule, entryPoint: 'fs_main', targets: [{ format: context.format }] } }); passEncoder.setVertexBuffer(0, vertexBuffer); passEncoder.draw(3, 1, 0, 0); device.queue.submit([commandEncoder.finish()]); </script> </head> <body></body> </html> |
ブラウザでの動作確認チェックリスト
| 検証項目 | 結果 |
|---|---|
COOP/COEPヘッダ設定 |
OK |
| WebGPUが有効化されているか | Chrome 125+でOK |
| シェーダーが正しく読み込まれたか | ✅ |
| レンダリングが行われているか | 赤い三角形表示 |
よくあるエラー例:
navigator.gpu is not definedは、ブラウザのWebGPUサポートがない場合に発生します。対応ブラウザで再実行してください。