From bed9fb71682b7d1cdd049d31598c0b8b60bdc4ca Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Wed, 4 Feb 2026 12:26:45 +0000 Subject: [PATCH] Docs for half types for wgsl --- .../graphics/shaders/compute-shaders.md | 21 + .../graphics/shaders/wgsl-specifics.md | 42 ++ .../graphics/shaders/compute-shaders.md | 484 ++++++++++++++++++ .../graphics/shaders/wgsl-specifics.md | 319 +++++++++++- 4 files changed, 865 insertions(+), 1 deletion(-) create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders.md diff --git a/docs/user-manual/graphics/shaders/compute-shaders.md b/docs/user-manual/graphics/shaders/compute-shaders.md index 03e32f6757a..88b92648cb6 100644 --- a/docs/user-manual/graphics/shaders/compute-shaders.md +++ b/docs/user-manual/graphics/shaders/compute-shaders.md @@ -423,6 +423,27 @@ Using `immediate: true` has a performance impact as it forces an early command b Compute shaders support the same [shader preprocessor](/user-manual/graphics/shaders/preprocessor) as vertex and fragment shaders, including `#define`, `#ifdef`, `#if`, `#include`, and more. +### Built-in Includes + +The engine provides built-in shader chunks that are automatically available in compute shaders: + +| Include | Description | +|---------|-------------| +| `halfTypesCS` | Half-precision type aliases (`half`, `half2`, etc.) that resolve to f16 when supported, f32 otherwise. See [Half-Precision Types](/user-manual/graphics/shaders/wgsl-specifics#half-precision-types). | + +Example: + +```wgsl +#include "halfTypesCS" + +@compute @workgroup_size(64, 1, 1) +fn main(@builtin(global_invocation_id) global_id: vec3u) { + // Use half types for calculations + var color: half3 = half3(1.0, 0.5, 0.0); + // ... +} +``` + ### Defines and Includes Use `cdefines` to pass defines and `cincludes` to provide include content: diff --git a/docs/user-manual/graphics/shaders/wgsl-specifics.md b/docs/user-manual/graphics/shaders/wgsl-specifics.md index 63bcde4b394..12665bbaebe 100644 --- a/docs/user-manual/graphics/shaders/wgsl-specifics.md +++ b/docs/user-manual/graphics/shaders/wgsl-specifics.md @@ -179,6 +179,48 @@ struct Particle { var particles: array; ``` +### Half-Precision Types + +When the device supports 16-bit floating-point operations (`device.supportsShaderF16`), shaders can use native WGSL half-precision types for improved performance and reduced memory bandwidth: + +| Native WGSL Type | Description | +|------------------|-------------| +| `f16` | 16-bit float scalar | +| `vec2h`, `vec3h`, `vec4h` | 16-bit float vectors | +| `mat2x2h`, `mat3x3h`, `mat4x4h` | 16-bit float matrices | + +For convenience, PlayCanvas provides type aliases that automatically resolve to f16 types when supported, or fall back to f32 types when not: + +| Alias | f16 Supported | f16 Not Supported | +|-------|---------------|-------------------| +| `half` | `f16` | `f32` | +| `half2` | `vec2` | `vec2f` | +| `half3` | `vec3` | `vec3f` | +| `half4` | `vec4` | `vec4f` | +| `half2x2` | `mat2x2` | `mat2x2f` | +| `half3x3` | `mat3x3` | `mat3x3f` | +| `half4x4` | `mat4x4` | `mat4x4f` | + +These aliases are automatically included in vertex and fragment shaders. For compute shaders, include them with `#include "halfTypesCS"`. + +Example usage: + +```wgsl +// Use half types for intermediate calculations +var color: half3 = half3(1.0, 0.5, 0.0); +var intensity: half = half(0.8); +var result: half3 = color * intensity; + +// Convert back to f32 when needed (e.g., for output) +output.color = vec4f(vec3f(result), 1.0); +``` + +:::note + +When `device.supportsShaderF16` is true, the engine automatically adds the `enable f16;` directive and defines `CAPS_SHADER_F16` for conditional compilation. WGSL requires explicit type conversions between f16 and f32—use constructors like `half3(vec3fValue)` or `vec3f(half3Value)` to convert between precisions. + +::: + ### Varyings Varyings are used to pass values from the vertex shader to the fragment shader. Declare them in both vertex and fragment shader using this simplified syntax: diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders.md new file mode 100644 index 00000000000..e19c2002dfb --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders.md @@ -0,0 +1,484 @@ +--- +title: コンピュートシェーダー +--- + +コンピュートシェーダーは、レンダリングパイプラインとは独立して、GPU上で汎用計算を実行するプログラムです。頂点シェーダーやフラグメントシェーダーとは異なり、コンピュートシェーダーはジオメトリやピクセルに縛られず、任意のデータを操作するため、パーティクルシミュレーション、画像処理、物理計算、プロシージャルコンテンツ生成などのタスクに理想的です。 + +:::warning + +コンピュートシェーダーは**WebGPU**プラットフォームでのみサポートされています。WebGLを使用している場合は利用できません。 + +::: + +## サポートの確認 + +コンピュートシェーダーを使用する前に、デバイスがサポートしているか確認してください: + +```javascript +if (device.supportsCompute) { + // コンピュートシェーダーが利用可能 +} +``` + +## コンピュートシェーダーの作成 + +コンピュートシェーダーは、WGSLコードを使用して`Shader`クラスで作成されます。シェーダー定義には、コンピュートシェーダーソース(`cshader`)、バインドグループフォーマット、およびオプションでユニフォームバッファフォーマットが含まれます。 + +### 基本的なシェーダー定義 + +```javascript +const shader = new pc.Shader(device, { + name: 'MyComputeShader', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: ` + @compute @workgroup_size(1, 1, 1) + fn main(@builtin(global_invocation_id) global_id: vec3u) { + // コンピュートシェーダーのロジックをここに記述 + } + `, + computeBindGroupFormat: new pc.BindGroupFormat(device, [ + // リソースバインディングをここに記述 + ]) +}); +``` + +デフォルトでは、エンジンはエントリポイント関数の名前が`main`であることを期待します。`computeEntryPoint`を使用して別の関数名を指定することもでき、これにより単一のシェーダーソースに複数のエントリポイントを含めることもできます: + +```javascript +const shaderSource = ` + @compute @workgroup_size(64, 1, 1) + fn initParticles(@builtin(global_invocation_id) global_id: vec3u) { + // パーティクルの初期化 + } + + @compute @workgroup_size(64, 1, 1) + fn updateParticles(@builtin(global_invocation_id) global_id: vec3u) { + // パーティクルの更新 + } +`; + +// 同じソースから、それぞれ異なるエントリポイントを使用して別々のシェーダーを作成 +const initShader = new pc.Shader(device, { + name: 'InitParticles', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: shaderSource, + computeEntryPoint: 'initParticles', + // ... +}); + +const updateShader = new pc.Shader(device, { + name: 'UpdateParticles', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: shaderSource, + computeEntryPoint: 'updateParticles', + // ... +}); +``` + +### バインドグループフォーマット + +`computeBindGroupFormat`は、コンピュートシェーダーで利用可能なリソースを定義します。様々なタイプのリソースをバインドできます: + +#### ストレージバッファ + +ストレージバッファは、大量のデータへの読み書きアクセスを可能にします: + +```javascript +// 読み書き可能なストレージバッファ +new pc.BindStorageBufferFormat('particles', pc.SHADERSTAGE_COMPUTE) + +// 読み取り専用のストレージバッファ +new pc.BindStorageBufferFormat('spheres', pc.SHADERSTAGE_COMPUTE, true) +``` + +WGSLでは、ストレージバッファに以下のようにアクセスします: + +```wgsl +@group(0) @binding(0) var particles: array; +@group(0) @binding(1) var spheres: array; +``` + +#### ストレージテクスチャ + +ストレージテクスチャは、コンピュートシェーダーがテクスチャに直接書き込むことを可能にします: + +```javascript +new pc.BindStorageTextureFormat('outTexture', pc.PIXELFORMAT_RGBA8, pc.TEXTUREDIMENSION_2D) +``` + +WGSLでは: + +```wgsl +@group(0) @binding(0) var outputTexture: texture_storage_2d; + +// テクスチャへの書き込み +textureStore(outputTexture, vec2i(global_id.xy), color); +``` + +#### 入力テクスチャ + +入力テクスチャは読み取り専用のテクスチャデータを提供します。最後のパラメータはサンプラーを含めるかどうかを制御します: + +```javascript +// サンプラーなしのテクスチャ(textureLoad用) +new pc.BindTextureFormat('inputTexture', pc.SHADERSTAGE_COMPUTE, undefined, undefined, false) + +// サンプラー付きのテクスチャ(textureSampleLevel用) +new pc.BindTextureFormat('inputTexture', pc.SHADERSTAGE_COMPUTE, undefined, undefined, true) +``` + +WGSLでは、サンプラーが含まれている場合、テクスチャ名に`_sampler`サフィックスを付けて使用します: + +```wgsl +// サンプラーなし - 直接テクセルアクセスにtextureLoadを使用 +@group(0) @binding(0) var inputTexture: texture_2d; +let color = textureLoad(inputTexture, position, 0); + +// サンプラー付き - フィルタリングされたサンプリングにtextureSampleLevelを使用 +@group(0) @binding(0) var inputTexture: texture_2d; +@group(0) @binding(1) var inputTexture_sampler: sampler; +let color = textureSampleLevel(inputTexture, inputTexture_sampler, uv, 0.0); +``` + +:::note + +コンピュートシェーダーでは、ミップレベル(LOD)を明示的に指定する必要があるため、`textureSample`の代わりに`textureSampleLevel`を使用してください。 + +::: + +#### ユニフォームバッファ + +コンピュートシェーダーにユニフォームデータを渡すには、まずユニフォームバッファフォーマットを定義します: + +```javascript +const uniformBufferFormat = new pc.UniformBufferFormat(device, [ + new pc.UniformFormat('tint', pc.UNIFORMTYPE_VEC4), + new pc.UniformFormat('time', pc.UNIFORMTYPE_FLOAT), + new pc.UniformFormat('count', pc.UNIFORMTYPE_UINT) +]); +``` + +次に、バインドグループとともにシェーダー定義に含めます: + +```javascript +const shader = new pc.Shader(device, { + name: 'ComputeShader', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: shaderCode, + + // ユニフォームバッファフォーマットを割り当て + computeUniformBufferFormats: { + ub: uniformBufferFormat + }, + + // バインドグループにユニフォームバッファを含める + computeBindGroupFormat: new pc.BindGroupFormat(device, [ + new pc.BindUniformBufferFormat('ub', pc.SHADERSTAGE_COMPUTE), + // ... その他のバインディング + ]) +}); +``` + +WGSLでは: + +```wgsl +struct ub_compute { + tint: vec4f, + time: f32, + count: u32 +} + +@group(0) @binding(0) var ubCompute: ub_compute; + +@compute @workgroup_size(1, 1, 1) +fn main(@builtin(global_invocation_id) global_id: vec3u) { + let t = ubCompute.time; + let c = ubCompute.count; +} +``` + +## コンピュートインスタンスの作成 + +`Compute`クラスは、関連するパラメータを持つコンピュートシェーダーの実行可能なインスタンスを表します: + +```javascript +const compute = new pc.Compute(device, shader, 'MyComputeInstance'); +``` + +## パラメータの設定 + +`setParameter`を使用してリソースをバインドし、ユニフォーム値を設定します: + +```javascript +// ストレージバッファをバインド +compute.setParameter('particles', storageBuffer); + +// テクスチャをバインド +compute.setParameter('inputTexture', texture); + +// ユニフォーム値を設定 +compute.setParameter('time', 1.5); +compute.setParameter('count', 1024); +compute.setParameter('tint', [1.0, 0.5, 0.0, 1.0]); +``` + +## ストレージバッファの作成 + +ストレージバッファは、コンピュートシェーダーが読み書きできるデータを保持します: + +```javascript +const storageBuffer = new pc.StorageBuffer( + device, + bufferSizeInBytes, + pc.BUFFERUSAGE_COPY_SRC | // CPUへの読み戻しを有効化 + pc.BUFFERUSAGE_COPY_DST // CPUからの書き込みを有効化 +); + +// 初期データを書き込み +const data = new Float32Array([...]); +storageBuffer.write(0, data); + +// バッファをクリア +storageBuffer.clear(); +``` + +## ストレージテクスチャの作成 + +ストレージテクスチャは`storage: true`オプションで作成されます: + +```javascript +const storageTexture = new pc.Texture(device, { + name: 'StorageTexture', + width: 512, + height: 512, + format: pc.PIXELFORMAT_RGBA8, + mipmaps: false, + minFilter: pc.FILTER_LINEAR, + magFilter: pc.FILTER_LINEAR, + storage: true // ストレージテクスチャとして有効化 +}); +``` + +## コンピュートシェーダーのディスパッチ + +コンピュートシェーダーを実行するには、まずディスパッチ次元を設定してからディスパッチします: + +```javascript +// ディスパッチ次元を設定(X、Y、Zのワークグループ数) +compute.setupDispatch(width, height, 1); + +// コンピュートシェーダーをディスパッチ +device.computeDispatch([compute], 'MyDispatch'); +``` + +複数のコンピュートシェーダーを単一のコンピュートパスでまとめてディスパッチできます: + +```javascript +compute1.setupDispatch(64, 64); +compute2.setupDispatch(128, 128); +device.computeDispatch([compute1, compute2], 'BatchedDispatch'); +``` + +### ワークグループサイズ + +総呼び出し回数は`dispatchSize × workgroupSize`です。例えば、`(width, height)`でディスパッチし、シェーダーが`@workgroup_size(1, 1, 1)`の場合、`width × height`回の呼び出しが行われます。 + +大規模なデータセットでのパフォーマンス向上のために、より大きなワークグループサイズを使用してください: + +```wgsl +@compute @workgroup_size(64, 1, 1) +fn main(@builtin(global_invocation_id) global_id: vec3u) { + // global_id.xの要素を処理 +} +``` + +そして、それに応じてディスパッチします: + +```javascript +const numElements = 1024 * 1024; +const workgroupSize = 64; +compute.setupDispatch(numElements / workgroupSize); +``` + +## 間接ディスパッチ + +間接ディスパッチは、あるコンピュートシェーダーが別のコンピュートシェーダーのディスパッチパラメータを生成することを可能にし、CPUへの読み戻しなしで完全にGPU駆動のワークロードを実現します。これは以下の場合に便利です: + +- GPUで決定される可変ワークロードサイズ +- タイル数が動的に計算されるタイルベースの処理 +- GPUカリング後の可視要素のみの処理 + +### ディスパッチスロットの予約 + +デバイスは間接ディスパッチパラメータ用の組み込みバッファを提供します。毎フレームスロットを予約してください: + +```javascript +const slot = device.getIndirectDispatchSlot(); +``` + +各スロットは、x、y、zワークグループ数を表す3つの32ビット符号なし整数を保持します。最大スロット数は`device.maxIndirectDispatchCount`で制御されます(デフォルト:256)。 + +### ディスパッチパラメータの書き込み + +コンピュートシェーダーがディスパッチパラメータを書き込めるように、間接バッファを渡します。バインドグループフォーマットで: + +```javascript +new pc.BindStorageBufferFormat('indirectBuffer', pc.SHADERSTAGE_COMPUTE) +``` + +WGSLでは、間接ディスパッチレイアウトに一致する構造体を定義し、パラメータを書き込みます: + +```wgsl +struct DispatchIndirectArgs { + x: u32, + y: u32, + z: u32 +}; + +@group(0) @binding(0) var indirectBuffer: array; +@group(0) @binding(1) var uniforms: Uniforms; // スロットインデックスを含む + +@compute @workgroup_size(1) +fn main() { + // ワークロードサイズを動的に計算 + let workloadSize = calculateWorkload(); + + // ディスパッチパラメータをスロットに書き込み + indirectBuffer[uniforms.slot].x = workloadSize; + indirectBuffer[uniforms.slot].y = 1u; + indirectBuffer[uniforms.slot].z = 1u; +} +``` + +### 間接ディスパッチの使用 + +`setupIndirectDispatch`を使用して、2番目のコンピュートシェーダーがバッファからディスパッチパラメータを読み取るように設定します: + +```javascript +// このフレームのスロットを予約 +const slot = device.getIndirectDispatchSlot(); + +// 最初のパス:コンピュートシェーダーがディスパッチパラメータを書き込む +prepareCompute.setParameter('indirectBuffer', device.indirectDispatchBuffer); +prepareCompute.setParameter('slot', slot); +prepareCompute.setupDispatch(1, 1, 1); +device.computeDispatch([prepareCompute]); + +// 2番目のパス:バッファからのパラメータを使用してディスパッチ +processCompute.setupIndirectDispatch(slot); +device.computeDispatch([processCompute]); +``` + +:::note + +デバイスの組み込み間接バッファを使用する場合、スロットは現在のフレームでのみ有効なため、`setupIndirectDispatch`を毎フレーム呼び出す必要があります。 + +::: + +### カスタム間接バッファ + +レンダリングフレーム外での複雑なスケジューリングなどの高度なユースケースでは、独自のストレージバッファを提供できます: + +```javascript +// 間接ディスパッチ用のカスタムバッファを作成 +const customBuffer = new pc.StorageBuffer(device, 3 * 4, pc.BUFFERUSAGE_INDIRECT); + +// 間接ディスパッチにカスタムバッファを使用 +compute.setupIndirectDispatch(0, customBuffer); +``` + +カスタムバッファを使用する場合、そのライフタイムと内容を自分で管理します。フレーム検証は行われません。 + +## CPUへのデータの読み戻し + +ストレージバッファからCPUに結果を読み戻すには: + +```javascript +const resultData = new Float32Array(numElements); +storageBuffer.read(0, undefined, resultData).then((data) => { + // データを処理 + console.log('First value:', data[0]); +}); +``` + +`read()`はGPU操作が非同期であるためPromiseを返します。データはGPUがコンピュートシェーダーの実行を完了した後に利用可能になり、これは数フレーム後になる場合があります。 + +時間に厳しい読み取りの場合、4番目のパラメータとして`immediate: true`を渡すことができます: + +```javascript +storageBuffer.read(0, undefined, resultData, true).then((data) => { + // データがより早く利用可能になるが、パフォーマンスコストがある +}); +``` + +デフォルト(`immediate: false`)では、読み取りはGPUコマンドバッファが自然に送信される次のイベント処理サイクルまで延期されます。`immediate: true`では、コマンドバッファが即座に送信され、読み取りがすぐに実行されます。 + +:::warning + +`immediate: true`を使用すると、コマンドバッファの早期送信を強制するため、パフォーマンスに影響があります。低レイテンシの読み取りが不可欠な場合にのみ使用してください。 + +::: + +## プリプロセッサ + +コンピュートシェーダーは、頂点シェーダーやフラグメントシェーダーと同じ[シェーダープリプロセッサ](/user-manual/graphics/shaders/preprocessor)をサポートしており、`#define`、`#ifdef`、`#if`、`#include`などが含まれます。 + +### 組み込みインクルード + +エンジンは、コンピュートシェーダーで自動的に利用可能な組み込みシェーダーチャンクを提供します: + +| インクルード | 説明 | +|-------------|------| +| `halfTypesCS` | 半精度型エイリアス(`half`、`half2`など)。サポートされている場合はf16に、そうでない場合はf32に解決されます。[半精度型](/user-manual/graphics/shaders/wgsl-specifics#半精度型)を参照。 | + +例: + +```wgsl +#include "halfTypesCS" + +@compute @workgroup_size(64, 1, 1) +fn main(@builtin(global_invocation_id) global_id: vec3u) { + // 計算にhalf型を使用 + var color: half3 = half3(1.0, 0.5, 0.0); + // ... +} +``` + +### 定義とインクルード + +`cdefines`を使用して定義を渡し、`cincludes`を使用してインクルードコンテンツを提供します: + +```javascript +const shader = new pc.Shader(device, { + name: 'ComputeShader', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: ` + #include "myHelper" + + @compute @workgroup_size({WORKGROUP_SIZE}, 1, 1) + fn main(@builtin(global_invocation_id) global_id: vec3u) { + var sharedData: array; + // ... + } + `, + cdefines: new Map([ + ['{WORKGROUP_SIZE}', '64'] + ]), + cincludes: pc.ShaderChunks.get(device, pc.SHADERLANGUAGE_WGSL), + // ... +}); +``` + +`{WORKGROUP_SIZE}`プレースホルダーはコンパイル前に`64`に置き換えられます。通常の定義とインジェクション定義の詳細については、[プリプロセッサドキュメント](/user-manual/graphics/shaders/preprocessor)を参照してください。 + +## サンプル + +様々なコンピュートシェーダーのユースケースを示すライブサンプルを探索してください: + +- [Histogram](https://playcanvas.github.io/#/compute/histogram) - アトミック操作を使用した画像ヒストグラムの計算 +- [Texture Generation](https://playcanvas.github.io/#/compute/texture-gen) - コンピュートシェーダーでテクスチャを生成・変更 +- [Particles](https://playcanvas.github.io/#/compute/particles) - 衝突検出付きGPUベースのパーティクルシミュレーション +- [Vertex Update](https://playcanvas.github.io/#/compute/vertex-update) - メッシュ頂点バッファのリアルタイム変更 +- [Edge Detect](https://playcanvas.github.io/#/compute/edge-detect) - エッジ検出による画像処理 +- [Indirect Draw](https://playcanvas.github.io/#/compute/indirect-draw) - 間接描画呼び出しによるGPU駆動レンダリング +- [Indirect Dispatch](https://playcanvas.github.io/#/compute/indirect-dispatch) - 深度ベースのタイル分類によるGPU駆動コンピュートディスパッチ diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-specifics.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-specifics.md index 0d4c3d2705f..3f76d3b564b 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-specifics.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-specifics.md @@ -2,4 +2,321 @@ title: WGSL の詳細 --- -PlayCanvasエンジンでのWGSLサポートは、現在積極的に開発を進めています。WGSLシェーダーの要件と統合についての詳しい情報は、実装が完了次第提供されます。 +PlayCanvasエンジンで使用されるWGSLシェーダーは、特定の要件を満たす必要があります。これらの要件により、エンジンはシェーダーを正しく統合し、属性、ユニフォーム、バリイングなどの必要なリソースを確実に受け取ることができます。 + +以下のセクションでは、PlayCanvas用のWGSLシェーダーを記述する際の主要な側面について説明します。 + +### 簡略化されたシェーダーインターフェース構文 + +標準的なWGSL(WebGPUシェーディング言語)では、ユニフォーム、属性、バリイングを宣言する際に、各リソースに対して`@group`と`@binding`インデックスを明示的に指定する必要があります。これは冗長でエラーが発生しやすく、特に一般的なパターンでは問題となります。 + +使いやすさを向上させ、シェーダー開発を効率化するために、GLSLに似た簡略化された構文を採用しています。このモデルでは、`@group`や`@binding`属性を手動で指定する必要はありません。これらは事前定義されたレイアウトに基づいて、エンジンによって自動的に割り当てられ、管理されます。 + +#### 比較例 + +標準的なWGSL: + +```wgsl +struct Uniforms { + uTime: f32, +}; + +struct FragmentInput { + @location(0) uv0: vec2f, + @builtin(position) position: vec4f +}; + +@group(0) @binding(0) var ub: Uniforms; + +@fragment fn fragmentMain(FragmentInput) -> @location(0) vec4f { + // 本体 +} +``` + +対照的に、簡略化された構文では多くの定型コードを省略できます。 + +```wgsl +uniform uTime: f32; +varying uv0: vec2f; + +@fragment fn fragmentMain(input: FragmentInput) -> FragmentOutput { + // 本体 +} +``` + +### 属性 + +属性は頂点ごとの入力データを定義し、頂点シェーダーでのみ使用できます。以下の構文を使用して宣言する必要があります: + +```wgsl +attribute aUv0: vec2f; +``` + +内部的には、`VertexInput`構造体が自動的に作成され、すべての属性が格納されます。属性はメイン関数に渡される構造体からアクセスできますが、グローバルスコープでもアクセスできます。 + +```wgsl +attribute aUv0: vec2f; + +@vertex fn vertexMain(input: VertexInput) -> VertexOutput { + + // メイン関数に渡されたinputを使用してアクセス + var myUv1 = input.aUv0; + + // グローバル変数としてもアクセス可能(他の関数内で特に便利) + var myUv2 = aUv0; +} +``` + +`VertexInput`構造体の一部として、およびグローバルスコープでも、これらの組み込み属性が自動的に利用可能です: + +```wgsl +vertexIndex: @builtin(vertex_index) +instanceIndex: @builtin(instance_index) +``` + +属性名は、[ShaderMaterial](/user-manual/graphics/shaders/)を作成する際に`attributes`プロパティで指定した名前と一致する必要があります。 + +### ユニフォーム + +ユニフォームは、エンジンからシェーダーに*数値リソース*を渡すために使用されます。 + +ユニフォームは以下の簡略化された構文を使用して宣言されます: + +```wgsl +uniform view_position: vec3f; +uniform tints: array; +uniform weights: array; +``` + +内部的には、ユニフォームは自動的にユニフォームバッファに配置され、シェーダーコードでは`uniform.`プレフィックスを使用してアクセスされます: + +```wgsl +var pos = uniform.view_position; +var color = uniform.tints[2]; + +// 配列で使用されるf32およびvec2<>型は、アラインメント要件のためにアラインされた構造体でラップされ、 +// 値は`element`プロパティとして利用可能です。 +// struct WrappedF32 { @size(16) element: f32 } +var weight = uniform.weights[3].element; +``` + +エンジンはレンダリング時に適切なユニフォーム値を自動的に設定します。 + +:::note + +現在、ユニフォームシステムは`f32`、`i32`、`u32`を含む単純な型、およびベクトルと行列(例:`vec4f`、`mat4x4f`)のみをサポートしています。構造体は現時点ではサポートされていないため、すべてのユニフォーム値は基本型の個別の変数として宣言する必要があります。 + +::: + +### テクスチャリソース + +テクスチャリソースは簡略化されたWGSL構文を使用し、各リソースに対して`@group`と`@binding`インデックスを指定する必要はありません。 + +#### テクスチャのサンプリング + +WGSLでは、GLSLとは異なり、テクスチャとサンプラーは別々のオブジェクトとして扱われます。 + +テクスチャをサンプリングする(フィルタリングされたテクセル値を取得する)場合、テクスチャオブジェクトの*直後に*サンプラーを提供する必要があります。 + +```wgsl +// サンプラー付き2Dテクスチャの宣言 +var diffuseMap: texture_2d; +var diffuseMapSampler: sampler; + +// テクスチャサンプリング +var texel = textureSample(diffuseMap, diffuseMapSampler, coords); +``` + +#### テクスチャのフェッチ + +生のテクセルデータのみを読み取る必要がある場合(フィルタリング、ミップマッピング、アドレッシングモードなし)、`textureSample`の代わりに`textureLoad`を使用できます。これはノンフィルタアクセス、または単にテクセルフェッチと呼ばれます。 + +このような場合、サンプラーは必要ありませんし、許可されていません。例えば: + +```wgsl +// サンプラーなしのキューブマップテクスチャ +var noSamplerMap: texture_cube; + +// テクセルのフェッチ +let texel = textureLoad(noSamplerMap, coords, mipLevel); +``` + +#### フィルタリング不可テクスチャ + +WebGPUはフィルタリング不可のfloatテクスチャをサポートしており、これは通常、フィルタリングが許可されていない深度テクスチャからのサンプリングなどの特殊な目的に使用されます。しかし、WGSLはこれらのフィルタリング不可floatテクスチャを宣言するための構文で明確なサンプルタイプを提供していません。この制限に対処し、シェーダー宣言に基づいた適切なバインドグループの自動生成を可能にするために、`uff`(unfilterable-float)という新しいサンプルタイプを導入しています。 + +`uff`を使用すると、シェーダーでフィルタリング不可floatテクスチャを明示的に宣言できます: + +```wgsl +// 宣言 +var colorMap: texture_2d; + +// サンプリング +let data: vec4f = textureLoad(colorMap, uv, 0); +``` + +この拡張により、エンジンはテクスチャのサンプリング機能を正しく解釈し、適切にバインドできます。 + +:::note + +`texture_external`のサポートはまだ利用できませんが、将来追加される予定です。 + +::: + +### ストレージバッファ + +ストレージバッファは、シェーダーがランダムアクセスで任意のデータを読み書きできるGPUアクセス可能なメモリリソースです。WGSLでは`var`を使用して宣言され、パーティクルシステム、コンピュートデータ、動的ジオメトリなどの大規模または構造化されたデータセットの処理に理想的です。ユニフォームとは異なり、ストレージバッファは読み取りと書き込みの両方のアクセスをサポートしています(適切なアクセス制御付き)。 + +頂点シェーダーでストレージバッファを使用する例: + +```wgsl +struct Particle { + position: vec3f, + velocity: vec3f, +} + +// 読み取り専用モードのパーティクルストレージバッファ +var particles: array; +``` + +### 半精度型 + +デバイスが16ビット浮動小数点演算をサポートしている場合(`device.supportsShaderF16`)、シェーダーはネイティブWGSL半精度型を使用してパフォーマンスを向上させ、メモリ帯域幅を削減できます: + +| ネイティブWGSL型 | 説明 | +|------------------|------| +| `f16` | 16ビット浮動小数点スカラー | +| `vec2h`, `vec3h`, `vec4h` | 16ビット浮動小数点ベクトル | +| `mat2x2h`, `mat3x3h`, `mat4x4h` | 16ビット浮動小数点行列 | + +PlayCanvasは、サポートされている場合はf16型に、そうでない場合はf32型に自動的に解決される型エイリアスを提供します: + +| エイリアス | f16サポート時 | f16非サポート時 | +|-----------|---------------|-----------------| +| `half` | `f16` | `f32` | +| `half2` | `vec2` | `vec2f` | +| `half3` | `vec3` | `vec3f` | +| `half4` | `vec4` | `vec4f` | +| `half2x2` | `mat2x2` | `mat2x2f` | +| `half3x3` | `mat3x3` | `mat3x3f` | +| `half4x4` | `mat4x4` | `mat4x4f` | + +これらのエイリアスは頂点シェーダーとフラグメントシェーダーに自動的に含まれます。コンピュートシェーダーの場合は、`#include "halfTypesCS"`で含めます。 + +使用例: + +```wgsl +// 中間計算にhalf型を使用 +var color: half3 = half3(1.0, 0.5, 0.0); +var intensity: half = half(0.8); +var result: half3 = color * intensity; + +// 必要に応じてf32に変換(例:出力用) +output.color = vec4f(vec3f(result), 1.0); +``` + +:::note + +`device.supportsShaderF16`がtrueの場合、エンジンは自動的に`enable f16;`ディレクティブを追加し、条件付きコンパイル用に`CAPS_SHADER_F16`を定義します。WGSLではf16とf32間の明示的な型変換が必要です。精度間の変換には`half3(vec3fValue)`や`vec3f(half3Value)`などのコンストラクタを使用してください。 + +::: + +### バリイング + +バリイングは、頂点シェーダーからフラグメントシェーダーに値を渡すために使用されます。頂点シェーダーとフラグメントシェーダーの両方で、以下の簡略化された構文を使用して宣言します: + +```wgsl +varying texCoord: vec2f; +``` + +内部的には、これらは解析され、頂点シェーダーでは`VertexOutput`構造体に、フラグメントシェーダーでは`FragmentInput`構造体に格納されます。 + +#### 頂点シェーダー + +`VertexOutput`構造体の一部として、これらの組み込み変数が自動的に利用可能です: + +```wgsl +position: @builtin(position) +``` + +例: + +```wgsl +varying texCoord: vec2f; + +@vertex fn vertexMain(input: VertexInput) -> VertexOutput { + var output: VertexOutput; + output.position = uniform.matrix_viewProjection * pos; + output.texCoord = vec2f(0.0, 1.0); + return output; +} +``` + +#### フラグメントシェーダー + +`FragmentInput`構造体の一部として、これらの組み込み変数が自動的に利用可能です: + +```wgsl +position: @builtin(position) // 補間されたフラグメント位置 +frontFacing: @builtin(front_facing) // 前面向き +sampleIndex: @builtin(sample_index) // MSAAのサンプルインデックス +primitiveIndex: @builtin(primitive_index) // プリミティブインデックス(サポート時) +``` + +これらの組み込み変数は、以下の名前でグローバルスコープでも利用可能です: + +```wgsl +pcPosition +pcFrontFacing +pcSampleIndex +pcPrimitiveIndex // サポート時 +``` + +:::note + +`primitiveIndex` / `pcPrimitiveIndex`組み込み変数は、`device.supportsPrimitiveIndex`がtrueの場合にのみ利用可能です。この機能はWebGPU専用です(WebGL2では利用不可)。機能がサポートされている場合、エンジンは必要な`enable primitive_index;` WGSLディレクティブを自動的に追加し、条件付きコンパイル用のシェーダー定義`CAPS_PRIMITIVE_INDEX`が利用可能になります。 + +::: + +例: + +```wgsl +varying texCoord: vec2f; + +@fragment +fn fragmentMain(input: FragmentInput) -> FragmentOutput { + var output: FragmentOutput; + output.color = vec4f(1.0); + return output; +} +``` + +### フラグメントシェーダー出力 + +フラグメントシェーダーは、フレームバッファのレンダーターゲット(カラーアタッチメント)に書き込まれる1つ以上のカラー出力を生成する責任があります。 + +エンジンは`FragmentOutput`構造体を自動的に提供し、これには`color`、`color1`、`color2`などの定義済みvec4fフィールドのセットが含まれ、`GraphicsDevice.maxColorAttachments`で定義された制限までのすべての可能なカラーアタッチメントをカバーします。 + +`FragmentOutput`構造体の一部として、これらの組み込み変数が自動的に利用可能です: + +```wgsl +fragDepth: @builtin(frag_depth) +``` + +例: + +```wgsl +@fragment fn fragmentMain(input: FragmentInput) -> FragmentOutput { + var output: FragmentOutput; + output.color = vec4f(1.0); + output.color1 = vec4f(0.5); + output.fragDepth = 0.2; + return output; +} +``` + +:::note + +整数テクスチャへのレンダリング(`vec4f`以外の出力フォーマット)のサポートはまだ利用できませんが、将来追加される予定です。 + +:::