検索
ホームページウェブフロントエンドjsチュートリアルWebGPU チュートリアル: Web 上のコンピューティング、頂点、およびフラグメント シェーダー

WebGPU tutorial: compute, vertex, and fragment shaders on the web

WebGPU は、最先端の GPU コンピューティング機能を Web にもたらし、共有コード ベースを使用してすべての消費者プラットフォームに利益をもたらすことを約束するグローバル テクノロジーです。

その前身である WebGL は強力ですが、コンピューティング シェーダー機能が著しく不足しており、アプリケーションの範囲が制限されています。

WGSL (WebGPU Shader/Compute Language) は、Rust や GLSL などの分野のベスト プラクティスを活用しています。

WebGPU の使い方を学んでいると、ドキュメントにいくつかのギャップがあることに気づきました。計算シェーダーを使用して頂点シェーダーとフラグメント シェーダーのデータを計算するための簡単な出発点を見つけたいと思っていました。

このチュートリアルのすべてのコードの単一ファイル HTML は、https://www.php.cn/link/2e5281ee978b78d6f5728aad8f28fedb にあります。詳細な内訳については、以下をお読みください。

これは、私のドメインで実行されるこの HTML のシングルクリックのデモです: https://www.php.cn/link/bed827b4857bf056d05980661990ccdc Chrome や Edge などの WebGPU ベースのブラウザhttps://www.php.cn/link/bae00fb8b4115786ba5dbbb67b9b177a)。

詳細設定

これは粒子シミュレーションです。時間の経過とともにタイムステップで発生します。

時間は JS/CPU で追跡され、(float) 均一として GPU に渡されます。

パーティクル データは完全に GPU 上で管理されますが、CPU と対話し続けるため、メモリの割り当てと初期値の設定が可能になります。データを CPU に読み戻すことも可能ですが、このチュートリアルでは省略します。

このセットアップの魅力は、各パーティクルが他のすべてのパーティクルと並行して更新され、ブラウザでの驚異的な計算速度とレンダリング速度が可能になることです (並列化により GPU のコア数が最大化されます。パーティクルの数は次のように割ることができます)。コアごとの更新ステップごとの真のサイクル数を取得するには、コアの数を使用します)。

バインド

WebGPU が CPU と GPU 間のデータ交換に使用するメカニズムはバインドです。WebGPU バッファーを使用して、JS 配列 (Float32Array など) を WGSL のメモリ位置に「バインド」できます。 WGSL メモリの場所は、グループ番号とバインディング番号という 2 つの整数によって識別されます。

私たちのケースでは、コンピューティング シェーダーと頂点シェーダーの両方が、時間とパーティクルの位置という 2 つのデータ バインディングに依存しています。

時間 - 制服

コンピューティング シェーダー (https://www.php.cn/link/2e5281ee978b78d6f5728aad8f28fedb#L43) と頂点シェーダーには均一な定義が存在します。 (https://www.php.cn/link/2e5281ee978b78d6f5728aad8f28fedb#L69) 中 - シェーダー更新位置を計算し、頂点シェーダーは時間に基づいて色を更新します。

コンピューティング シェーダーから始めて、JS と WGSL のバインディング セットアップを見てみましょう。

<code>const computeBindGroup = device.createBindGroup({
  /*
    参见 computePipeline 定义,网址为
    https://www.php.cn/link/2e5281ee978b78d6f5728aad8f28fedb#L102

    它允许将 JS 字符串与 WGSL 代码链接到 WebGPU
  */
  layout: computePipeline.getBindGroupLayout(0), // 组号 0
  entries: [{
    // 时间绑定在绑定号 0
    binding: 0,
    resource: {
      /*
      作为参考,缓冲区声明为:

      const timeBuffer = device.createBuffer({
        size: Float32Array.BYTES_PER_ELEMENT,
        usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST})
      })

      https://www.php.cn/link/2e5281ee978b78d6f5728aad8f28fedb#L129
      */
      buffer: timeBuffer
    }
  },
  {
    // 粒子位置数据在绑定号 1(仍在组 0)
    binding: 1,
    resource: {
      buffer: particleBuffer
    }
  }]
});</code>

およびコンピューティング シェーダー内の対応する宣言

<code>// 来自计算着色器 - 顶点着色器中也有类似的声明
@group(0) @binding(0) var<uniform> t: f32;
@group(0) @binding(1) var<storage read_write=""> particles : array<particle>;
</particle></storage></uniform></code>

重要なのは、JS と WGSL のグループ番号とバインディング番号を一致させることによって、JS 側の timeBuffer を WGSL にバインドしていることです。

これにより、JS から変数の値を制御できるようになります:

<code>/* 数组中只需要 1 个元素,因为时间是单个浮点值 */
const timeJs = new Float32Array(1)
let t = 5.3
/* 纯 JS,只需设置值 */
timeJs.set([t], 0)
/* 将数据从 CPU/JS 传递到 GPU/WGSL */
device.queue.writeBuffer(timeBuffer, 0, timeJs);</code>

パーティクルの位置 - WGSL ストレージ

粒子の位置を GPU からアクセス可能なメモリに直接保存して更新することで、GPU の大規模なマルチコア アーキテクチャを利用して粒子の位置を並行して更新できるようになります。

並列化は、コンピューティング シェーダーで宣言されたワーク グループ サイズを使用して調整されます。

<code>@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
  // ...
}
</u32></code>

@builtin(global_invocation_id) global_id : vec3 値はスレッド識別子を提供します。

定義により、global_invocation_id = workgroup_id * workgroup_size local_invocation_id - これは、パーティクル インデックスとして使用できることを意味します。

たとえば、10,000 個のパーティクルがあり、workgroup_size が 64 の場合、Math.ceil(10000/64) ワークグループをスケジュールする必要があります。コンピューティング パスが JS からトリガーされるたびに、次の量の作業を実行するように GPU に明示的に指示します:

<code>computePass.dispatchWorkgroups(Math.ceil(PARTICLE_COUNT / WORKGROUP_SIZE));</code>

PARTICLE_COUNT == 10000 および WORKGROUP_SIZE == 64 の場合、157 個のワークグループ (10000/64 = 156.25) が開始され、各ワークグループの local_invocation_id の計算範囲は 0 ~ 63 になります (workgroup_id の範囲は 0 ~ 157 です)。 )。 157 * 64 = 1048 なので、最終的にはワークグループでもう少し多くの計算を行うことになります。冗長な呼び出しを破棄することでオーバーフローを処理します。

これらの要素を考慮したシェーダーの計算の最終結果は次のとおりです:

<code>@compute @workgroup_size(${WORKGROUP_SIZE})
fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
  let index = global_id.x;
  // 由于工作组网格未对齐,因此丢弃额外的计算
  if (index >= arrayLength(&particles)) {
    return;
  }
  /* 将整数索引转换为浮点数,以便我们可以根据索引(和时间)计算位置更新 */
  let fi = f32(index);
  particles[index].position = vec2<f32>(
    /* 公式背后没有宏伟的意图 - 只不过是用时间+索引的例子 */
    cos(fi * 0.11) * 0.8 + sin((t + fi)/100)/10,
    sin(fi * 0.11) * 0.8 + cos((t + fi)/100)/10
  );
}
</f32></u32></code>

パーティクルはストレージ変数として定義されているため、これらの値は計算パス全体で保持されます。

頂点シェーダーのコンピュートシェーダーでパーティクルの位置を読み取ります

コンピューティング シェーダーのみがストレージに書き込むことができるため、コンピューティング シェーダーから頂点シェーダー内のパーティクルの位置を読み取るには、読み取り専用ビューが必要です。

以下は WGSL からの声明です:

<code>@group(0) @binding(0) var<uniform> t: f32;
@group(0) @binding(1) var<storage> particles : array<vec2>>;
/*
或等效:

@group(0) @binding(1) var<storage read=""> particles : array<vec2>>;
*/
</vec2></storage></vec2></storage></uniform></code>

コンピューティング シェーダーで同じ read_write スタイルを再利用しようとすると、エラーが発生します:

<code>var with 'storage' address space and 'read_write' access mode cannot be used by vertex pipeline stage</code>

頂点シェーダーのバインディング番号は、コンピューティング シェーダーのバインディング番号と一致する必要はないことに注意してください。頂点シェーダーのバインディング グループ宣言と一致する必要があるだけです。

<code>const renderBindGroup = device.createBindGroup({
  layout: pipeline.getBindGroupLayout(0),
  entries: [{
    binding: 0,
    resource: {
      buffer: timeBuffer
    }
  },
  {
    binding: 1,
    resource: {
      buffer: particleBuffer
    }
  }]
});</code>

GitHub サンプル コードで binding:2 を選択しました https://www.php.cn/link/2e5281ee978b78d6f5728aad8f28fedb#L70 - WebGPU によって課される制約の境界を調べるためだけに

シミュレーションを段階的に実行します

すべての設定が完了すると、更新ループとレンダリング ループが JS で調整されます。

<code>/* 从 t = 0 开始模拟 */
let t = 0
function frame() {
  /*
    为简单起见,使用恒定整数时间步 - 无论帧速率如何,都会一致渲染。
  */
  t += 1
  timeJs.set([t], 0)
  device.queue.writeBuffer(timeBuffer, 0, timeJs);

  // 计算传递以更新粒子位置
  const computePassEncoder = device.createCommandEncoder();
  const computePass = computePassEncoder.beginComputePass();
  computePass.setPipeline(computePipeline);
  computePass.setBindGroup(0, computeBindGroup);
  // 重要的是要调度正确数量的工作组以处理所有粒子
  computePass.dispatchWorkgroups(Math.ceil(PARTICLE_COUNT / WORKGROUP_SIZE));
  computePass.end();
  device.queue.submit([computePassEncoder.finish()]);

  // 渲染传递
  const commandEncoder = device.createCommandEncoder();
  const passEncoder = commandEncoder.beginRenderPass({
    colorAttachments: [{
      view: context.getCurrentTexture().createView(),
      clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
      loadOp: 'clear',
      storeOp: 'store',
    }]
  });
  passEncoder.setPipeline(pipeline);
  passEncoder.setBindGroup(0, renderBindGroup);
  passEncoder.draw(PARTICLE_COUNT);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);

  requestAnimationFrame(frame);
}
frame();</code>

結論

WebGPU は、ブラウザ内で大規模並列 GPU コンピューティングのパワーを解放します。

パスで実行されます。各パスには、メモリ バインディング (CPU メモリと GPU メモリのブリッジ) を備えたパイプラインを通じて有効化されたローカル変数があります。

コンピューティングの配信により、ワークグループを通じて並列ワークロードを調整できます。

多少の重いセットアップが必要ですが、ローカル バインディング/状態スタイルは WebGL のグローバル状態モデルに比べて大幅に改善されていると思います。使いやすくなり、同時に GPU コンピューティングのパワーを最終的に Web にもたらします。

以上がWebGPU チュートリアル: Web 上のコンピューティング、頂点、およびフラグメント シェーダーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python vs. JavaScript:開発環境とツールPython vs. JavaScript:開発環境とツールApr 26, 2025 am 12:09 AM

開発環境におけるPythonとJavaScriptの両方の選択が重要です。 1)Pythonの開発環境には、Pycharm、Jupyternotebook、Anacondaが含まれます。これらは、データサイエンスと迅速なプロトタイピングに適しています。 2)JavaScriptの開発環境には、フロントエンドおよびバックエンド開発に適したnode.js、vscode、およびwebpackが含まれます。プロジェクトのニーズに応じて適切なツールを選択すると、開発効率とプロジェクトの成功率が向上する可能性があります。

JavaScriptはCで書かれていますか?証拠を調べるJavaScriptはCで書かれていますか?証拠を調べるApr 25, 2025 am 12:15 AM

はい、JavaScriptのエンジンコアはCで記述されています。1)C言語は、JavaScriptエンジンの開発に適した効率的なパフォーマンスと基礎となる制御を提供します。 2)V8エンジンを例にとると、そのコアはCで記述され、Cの効率とオブジェクト指向の特性を組み合わせて書かれています。3)JavaScriptエンジンの作業原理には、解析、コンパイル、実行が含まれ、C言語はこれらのプロセスで重要な役割を果たします。

JavaScriptの役割:WebをインタラクティブでダイナミックにするJavaScriptの役割:WebをインタラクティブでダイナミックにするApr 24, 2025 am 12:12 AM

JavaScriptは、Webページのインタラクティブ性とダイナミズムを向上させるため、現代のWebサイトの中心にあります。 1)ページを更新せずにコンテンツを変更できます。2)Domapiを介してWebページを操作する、3)アニメーションやドラッグアンドドロップなどの複雑なインタラクティブ効果、4)ユーザーエクスペリエンスを改善するためのパフォーマンスとベストプラクティスを最適化します。

CおよびJavaScript:接続が説明しましたCおよびJavaScript:接続が説明しましたApr 23, 2025 am 12:07 AM

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

Webサイトからアプリまで:JavaScriptの多様なアプリケーションWebサイトからアプリまで:JavaScriptの多様なアプリケーションApr 22, 2025 am 12:02 AM

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Python vs. JavaScript:ユースケースとアプリケーションと比較されますPython vs. JavaScript:ユースケースとアプリケーションと比較されますApr 21, 2025 am 12:01 AM

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

JavaScript通訳者とコンパイラにおけるC/Cの役割JavaScript通訳者とコンパイラにおけるC/Cの役割Apr 20, 2025 am 12:01 AM

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

JavaScript in Action:実際の例とプロジェクトJavaScript in Action:実際の例とプロジェクトApr 19, 2025 am 12:13 AM

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター