From 16ba55620b8ae19e3c6dc32bd1c01772f9caf691 Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Tue, 2 Jun 2026 11:28:49 +0100 Subject: [PATCH] Document simplified compute shaders; add Compute Shaders Advanced page Stage 2 of the WGSL docs restructure. Now that compute shaders support automatic bind-group reflection, the Compute Shaders page leads with the simplified syntax (matching vertex/fragment), and manual bind-group control moves to a dedicated Compute Shaders Advanced page. - WGSL Reflection: generalized to vertex/fragment/compute; added a Storage Textures section. - Compute Shaders: rewritten simplified-only (no computeBindGroupFormat, loose uniforms, simplified indirect-dispatch), added a dispatch-must-run-in-frame note, examples reordered. - Compute Shaders Advanced (new): manual computeBindGroupFormat / computeUniformBufferFormats, explicit @group/@binding, the reflected-vs-manual mixing rule, and a note that manual bind groups remain fully supported. - Japanese pages reconciled to match the new structure (new wgsl-capabilities, wgsl-vertex-fragment-shaders, compute-shaders-advanced), reusing existing translations and updating moved-anchor links. --- .../shaders/compute-shaders-advanced.md | 173 ++++++++++++ .../graphics/shaders/compute-shaders.md | 204 +++----------- .../graphics/shaders/wgsl-reflection.md | 18 +- .../shaders/compute-shaders-advanced.md | 173 ++++++++++++ .../graphics/shaders/compute-shaders.md | 208 ++++---------- .../graphics/shaders/wgsl-capabilities.md | 123 +++++++++ .../graphics/shaders/wgsl-reflection.md | 257 +----------------- .../shaders/wgsl-vertex-fragment-shaders.md | 140 ++++++++++ sidebars.js | 1 + 9 files changed, 731 insertions(+), 566 deletions(-) create mode 100644 docs/user-manual/graphics/shaders/compute-shaders-advanced.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders-advanced.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-capabilities.md create mode 100644 i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-vertex-fragment-shaders.md diff --git a/docs/user-manual/graphics/shaders/compute-shaders-advanced.md b/docs/user-manual/graphics/shaders/compute-shaders-advanced.md new file mode 100644 index 00000000000..deba2881a79 --- /dev/null +++ b/docs/user-manual/graphics/shaders/compute-shaders-advanced.md @@ -0,0 +1,173 @@ +--- +title: Compute Shaders Advanced +description: "Manual bind group control for WebGPU compute shaders: hand-authored computeBindGroupFormat, explicit bindings, and mixing with reflected resources." +--- + +For most compute shaders, the simplified syntax described on the [Compute Shaders](/user-manual/graphics/shaders/compute-shaders) page is all you need — declare resources in WGSL and the engine reflects them automatically. + +This page covers **manual** control over bind groups, which remains fully supported. You provide a `computeBindGroupFormat` (and optionally `computeUniformBufferFormats`) describing the resources yourself, and write explicit `@group`/`@binding` indices in the WGSL. Reach for this when you need: + +- precise control over the binding layout, +- to interop with engine- or application-owned buffers at fixed bindings, or +- to mix explicitly-bound resources with reflected ones. + +:::note + +Manual bind groups are not deprecated. If you have existing compute shaders that hand-author a `computeBindGroupFormat`, they continue to work unchanged — you can migrate them to the simplified syntax whenever convenient, or not at all. + +::: + +## Bind Group Format + +The `computeBindGroupFormat` defines what resources are available to the compute shader. When you supply it, write explicit `@group`/`@binding` indices in the WGSL to match. You can bind various types of resources: + +```javascript +const shader = new pc.Shader(device, { + name: 'MyComputeShader', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: shaderCode, + computeBindGroupFormat: new pc.BindGroupFormat(device, [ + // Resource bindings go here + ]) +}); +``` + +### Storage Buffers + +Storage buffers allow read/write access to large amounts of data: + +```javascript +// Read-write storage buffer +new pc.BindStorageBufferFormat('particles', pc.SHADERSTAGE_COMPUTE) + +// Read-only storage buffer +new pc.BindStorageBufferFormat('spheres', pc.SHADERSTAGE_COMPUTE, true) +``` + +In WGSL, access storage buffers like this: + +```wgsl +@group(0) @binding(0) var particles: array; +@group(0) @binding(1) var spheres: array; +``` + +### Storage Textures + +Storage textures allow the compute shader to write directly to a texture: + +```javascript +new pc.BindStorageTextureFormat('outTexture', pc.PIXELFORMAT_RGBA8, pc.TEXTUREDIMENSION_2D) +``` + +In WGSL: + +```wgsl +@group(0) @binding(0) var outputTexture: texture_storage_2d; + +// Writing to the texture +textureStore(outputTexture, vec2i(global_id.xy), color); +``` + +### Input Textures + +Input textures provide read-only texture data. The last parameter controls whether a sampler is included: + +```javascript +// Texture without sampler (for textureLoad) +new pc.BindTextureFormat('inputTexture', pc.SHADERSTAGE_COMPUTE, undefined, undefined, false) + +// Texture with sampler (for textureSampleLevel) +new pc.BindTextureFormat('inputTexture', pc.SHADERSTAGE_COMPUTE, undefined, undefined, true) +``` + +In WGSL, when a sampler is included, it uses the texture name with a `_sampler` suffix: + +```wgsl +// Without sampler - use textureLoad for direct texel access +@group(0) @binding(0) var inputTexture: texture_2d; +let color = textureLoad(inputTexture, position, 0); + +// With sampler - use textureSampleLevel for filtered sampling +@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 + +In compute shaders, use `textureSampleLevel` instead of `textureSample` because you must explicitly specify the mip level (LOD). + +::: + +### Uniform Buffers + +For passing uniform data to compute shaders, first define the uniform buffer format: + +```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) +]); +``` + +Then include it in the shader definition along with the bind group: + +```javascript +const shader = new pc.Shader(device, { + name: 'ComputeShader', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: shaderCode, + + // Assign the uniform buffer format + computeUniformBufferFormats: { + ub: uniformBufferFormat + }, + + // Include uniform buffer in bind group + computeBindGroupFormat: new pc.BindGroupFormat(device, [ + new pc.BindUniformBufferFormat('ub', pc.SHADERSTAGE_COMPUTE), + // ... other bindings + ]) +}); +``` + +In 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; +} +``` + +## Mixing Reflected and Manual Resources + +A caller-provided `computeBindGroupFormat` and the simplified (reflected) syntax can be used together in the same shader: + +- Resources you describe in `computeBindGroupFormat` use the bindings you give them, in **group 0**. +- Any resources you declare with the simplified syntax (no `@group`/`@binding`) are still reflected — they are placed in a **separate bind group at index 1**. +- Explicitly-bound (`@group`/`@binding`) declarations in the WGSL are left untouched. + +If you do **not** provide a `computeBindGroupFormat`, reflected resources are placed in group 0 instead (see [Compute Shaders](/user-manual/graphics/shaders/compute-shaders)). + +In all cases, values are assigned by name with `setParameter`, regardless of whether a resource is manually bound or reflected. + +## Examples + +The following examples use manually-authored bind group formats: + + + + + + diff --git a/docs/user-manual/graphics/shaders/compute-shaders.md b/docs/user-manual/graphics/shaders/compute-shaders.md index 9e58baf4baf..5dfa26ddbb5 100644 --- a/docs/user-manual/graphics/shaders/compute-shaders.md +++ b/docs/user-manual/graphics/shaders/compute-shaders.md @@ -1,6 +1,6 @@ --- title: Compute Shaders -description: "WebGPU-only compute shaders: device checks, WGSL cshader definitions, bind groups, and general-purpose GPU work." +description: "WebGPU-only compute shaders: device checks, simplified WGSL resource declarations, dispatch, and general-purpose GPU work." --- Compute shaders are programs that run general-purpose computations on the GPU, independent of the rendering pipeline. Unlike vertex and fragment shaders, compute shaders are not tied to geometry or pixels—they operate on arbitrary data, making them ideal for tasks such as particle simulation, image processing, physics calculations, and procedural content generation. @@ -27,7 +27,7 @@ When the browser exposes optional WGSL features (for example [linear workgroup / ## Creating a Compute Shader -A compute shader is created using the `Shader` class with WGSL code. The shader definition includes the compute shader source (`cshader`), bind group format, and optionally uniform buffer formats. +A compute shader is created using the `Shader` class with a WGSL `cshader` source. Declare the resources it uses — uniforms, storage buffers, textures, and storage textures — with the simplified WGSL syntax (no `@group`/`@binding`), and the engine reflects them from the source and builds the bind group automatically. See [WGSL Reflection](/user-manual/graphics/shaders/wgsl-reflection) for the full resource declaration syntax. ### Basic Shader Definition @@ -36,17 +36,29 @@ const shader = new pc.Shader(device, { name: 'MyComputeShader', shaderLanguage: pc.SHADERLANGUAGE_WGSL, cshader: ` - @compute @workgroup_size(1, 1, 1) + // resources declared with the simplified syntax are reflected automatically - + // no computeBindGroupFormat required + uniform count: u32; + var data: array; + + @compute @workgroup_size(64, 1, 1) fn main(@builtin(global_invocation_id) global_id: vec3u) { - // Compute shader logic here + let i = global_id.x; + if (i >= uniform.count) { return; } + data[i] = data[i] * 2.0; } - `, - computeBindGroupFormat: new pc.BindGroupFormat(device, [ - // Resource bindings go here - ]) + ` }); ``` +:::note + +If you need explicit control over bind groups — a hand-authored `computeBindGroupFormat`, explicit `@group`/`@binding` indices, or mixing manually-bound resources with reflected ones — see [Compute Shaders Advanced](/user-manual/graphics/shaders/compute-shaders-advanced). + +::: + +### Entry Points + By default, the engine expects the entry point function to be named `main`. You can use `computeEntryPoint` to specify a different function name, which also allows a single shader source to contain multiple entry points: ```javascript @@ -67,141 +79,17 @@ const initShader = new pc.Shader(device, { name: 'InitParticles', shaderLanguage: pc.SHADERLANGUAGE_WGSL, cshader: shaderSource, - computeEntryPoint: 'initParticles', - // ... + computeEntryPoint: 'initParticles' }); const updateShader = new pc.Shader(device, { name: 'UpdateParticles', shaderLanguage: pc.SHADERLANGUAGE_WGSL, cshader: shaderSource, - computeEntryPoint: 'updateParticles', - // ... + computeEntryPoint: 'updateParticles' }); ``` -### Bind Group Format - -The `computeBindGroupFormat` defines what resources are available to the compute shader. You can bind various types of resources: - -#### Storage Buffers - -Storage buffers allow read/write access to large amounts of data: - -```javascript -// Read-write storage buffer -new pc.BindStorageBufferFormat('particles', pc.SHADERSTAGE_COMPUTE) - -// Read-only storage buffer -new pc.BindStorageBufferFormat('spheres', pc.SHADERSTAGE_COMPUTE, true) -``` - -In WGSL, access storage buffers like this: - -```wgsl -@group(0) @binding(0) var particles: array; -@group(0) @binding(1) var spheres: array; -``` - -#### Storage Textures - -Storage textures allow the compute shader to write directly to a texture: - -```javascript -new pc.BindStorageTextureFormat('outTexture', pc.PIXELFORMAT_RGBA8, pc.TEXTUREDIMENSION_2D) -``` - -In WGSL: - -```wgsl -@group(0) @binding(0) var outputTexture: texture_storage_2d; - -// Writing to the texture -textureStore(outputTexture, vec2i(global_id.xy), color); -``` - -#### Input Textures - -Input textures provide read-only texture data. The last parameter controls whether a sampler is included: - -```javascript -// Texture without sampler (for textureLoad) -new pc.BindTextureFormat('inputTexture', pc.SHADERSTAGE_COMPUTE, undefined, undefined, false) - -// Texture with sampler (for textureSampleLevel) -new pc.BindTextureFormat('inputTexture', pc.SHADERSTAGE_COMPUTE, undefined, undefined, true) -``` - -In WGSL, when a sampler is included, it uses the texture name with a `_sampler` suffix: - -```wgsl -// Without sampler - use textureLoad for direct texel access -@group(0) @binding(0) var inputTexture: texture_2d; -let color = textureLoad(inputTexture, position, 0); - -// With sampler - use textureSampleLevel for filtered sampling -@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 - -In compute shaders, use `textureSampleLevel` instead of `textureSample` because you must explicitly specify the mip level (LOD). - -::: - -#### Uniform Buffers - -For passing uniform data to compute shaders, first define the uniform buffer format: - -```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) -]); -``` - -Then include it in the shader definition along with the bind group: - -```javascript -const shader = new pc.Shader(device, { - name: 'ComputeShader', - shaderLanguage: pc.SHADERLANGUAGE_WGSL, - cshader: shaderCode, - - // Assign the uniform buffer format - computeUniformBufferFormats: { - ub: uniformBufferFormat - }, - - // Include uniform buffer in bind group - computeBindGroupFormat: new pc.BindGroupFormat(device, [ - new pc.BindUniformBufferFormat('ub', pc.SHADERSTAGE_COMPUTE), - // ... other bindings - ]) -}); -``` - -In 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; -} -``` - ## Creating a Compute Instance The `Compute` class represents an executable instance of a compute shader with its associated parameters: @@ -212,17 +100,16 @@ const compute = new pc.Compute(device, shader, 'MyComputeInstance'); ## Setting Parameters -Use `setParameter` to bind resources and set uniform values: +Use `setParameter` to bind resources and set uniform values. Resources are matched to the shader declarations by name: ```javascript // Bind a storage buffer -compute.setParameter('particles', storageBuffer); +compute.setParameter('data', storageBuffer); // Bind a texture compute.setParameter('inputTexture', texture); // Set uniform values -compute.setParameter('time', 1.5); compute.setParameter('count', 1024); compute.setParameter('tint', [1.0, 0.5, 0.0, 1.0]); ``` @@ -284,6 +171,12 @@ compute2.setupDispatch(128, 128); device.computeDispatch([compute1, compute2], 'BatchedDispatch'); ``` +:::note + +`device.computeDispatch` records into the current frame's command encoder, so it must be called **within the render frame** — typically from an `app.on('update', ...)` handler. Calling it from a bare `setTimeout` or a detached promise outside the frame is unreliable and may silently skip the dispatch. + +::: + ### Workgroup Size The total number of invocations is `dispatchSize × workgroupSize`. For example, if you dispatch with `(width, height)` and your shader has `@workgroup_size(1, 1, 1)`, you get `width × height` invocations. @@ -325,13 +218,7 @@ Each slot holds three 32-bit unsigned integers representing the x, y, and z work ### Writing Dispatch Parameters -Pass the indirect buffer to your compute shader so it can write dispatch parameters. In your bind group format: - -```javascript -new pc.BindStorageBufferFormat('indirectBuffer', pc.SHADERSTAGE_COMPUTE) -``` - -In WGSL, define a struct matching the indirect dispatch layout and write the parameters: +Declare the indirect buffer in your compute shader (reflected automatically) and write the dispatch parameters into the reserved slot: ```wgsl struct DispatchIndirectArgs { @@ -340,8 +227,8 @@ struct DispatchIndirectArgs { z: u32 }; -@group(0) @binding(0) var indirectBuffer: array; -@group(0) @binding(1) var uniforms: Uniforms; // Contains slot index +var indirectBuffer: array; +uniform slot: u32; // slot index to write into @compute @workgroup_size(1) fn main() { @@ -349,9 +236,9 @@ fn main() { let workloadSize = calculateWorkload(); // Write dispatch parameters to the slot - indirectBuffer[uniforms.slot].x = workloadSize; - indirectBuffer[uniforms.slot].y = 1u; - indirectBuffer[uniforms.slot].z = 1u; + indirectBuffer[uniform.slot].x = workloadSize; + indirectBuffer[uniform.slot].y = 1u; + indirectBuffer[uniform.slot].z = 1u; } ``` @@ -469,8 +356,7 @@ const shader = new pc.Shader(device, { cdefines: new Map([ ['{WORKGROUP_SIZE}', '64'] ]), - cincludes: pc.ShaderChunks.get(device, pc.SHADERLANGUAGE_WGSL), - // ... + cincludes: pc.ShaderChunks.get(device, pc.SHADERLANGUAGE_WGSL) }); ``` @@ -480,6 +366,14 @@ The `{WORKGROUP_SIZE}` placeholders are replaced with `64` before compilation. S Explore these live examples demonstrating various compute shader use cases: +- Edge Detect - Image processing with edge detection + + + +- Particles - GPU-based particle simulation with collision detection + + + - Histogram - Compute image histogram using atomic operations @@ -488,18 +382,10 @@ Explore these live examples demonstrating various compute shader use cases: -- Particles - GPU-based particle simulation with collision detection - - - - Vertex Update - Modify mesh vertex buffers in real-time -- Edge Detect - Image processing with edge detection - - - - Indirect Draw - GPU-driven rendering with indirect draw calls diff --git a/docs/user-manual/graphics/shaders/wgsl-reflection.md b/docs/user-manual/graphics/shaders/wgsl-reflection.md index 8669af4a920..3a61c8387f8 100644 --- a/docs/user-manual/graphics/shaders/wgsl-reflection.md +++ b/docs/user-manual/graphics/shaders/wgsl-reflection.md @@ -3,7 +3,7 @@ title: WGSL Reflection description: "Simplified WGSL declarations without manual bind groups: how PlayCanvas reflects resources from shader source and assigns bindings." --- -PlayCanvas reflects resources directly from your WGSL shader source: you declare uniforms, textures, and storage buffers without `@group`/`@binding` indices, and the engine parses these declarations, builds the bind group format, and assigns the bindings automatically. This simplified syntax is used by vertex and fragment shaders. +PlayCanvas reflects resources directly from your WGSL shader source: you declare uniforms, textures, and storage buffers without `@group`/`@binding` indices, and the engine parses these declarations, builds the bind group format, and assigns the bindings automatically. This simplified syntax is used by vertex, fragment, and compute shaders. The following sections outline how resources are declared and reflected. For the vertex/fragment-only constructs (attributes, varyings, and fragment outputs), see [WGSL Vertex and Fragment Shaders](/user-manual/graphics/shaders/wgsl-vertex-fragment-shaders). @@ -184,3 +184,19 @@ struct Particle { // particle storage buffer in read-only mode var particles: array; ``` + +### Storage Textures + +Storage textures let a shader write (and optionally read) texels directly, without a sampler. They are most commonly used as the output of a compute shader. Declare them with the simplified `texture_storage_*` syntax, specifying the format and the access mode: + +```wgsl +// write-only storage texture (the common case for compute output) +var outputTexture: texture_storage_2d; + +// writing a texel +textureStore(outputTexture, vec2i(global_id.xy), color); +``` + +The access mode can be `write`, `read`, or `read_write`. Reading from a storage texture (`read` / `read_write`) requires the `device.supportsStorageTextureRead` capability and an author-supplied `requires readonly_and_readwrite_storage_textures;` directive — see [WGSL Capabilities](/user-manual/graphics/shaders/wgsl-capabilities#wgsl-language-extensions). + +The texture you bind must be created with the `storage: true` option (see [Compute Shaders](/user-manual/graphics/shaders/compute-shaders)). diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders-advanced.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders-advanced.md new file mode 100644 index 00000000000..4747b4cc091 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/compute-shaders-advanced.md @@ -0,0 +1,173 @@ +--- +title: コンピュートシェーダー(応用) +description: "WebGPU コンピュートシェーダーのバインドグループ手動制御:手書きの computeBindGroupFormat、明示的なバインディング、反映リソースとの混在。" +--- + +ほとんどのコンピュートシェーダーでは、[コンピュートシェーダー](/user-manual/graphics/shaders/compute-shaders) のページで説明している簡略化された構文だけで十分です。WGSL でリソースを宣言すれば、エンジンが自動的に反映します。 + +このページでは、バインドグループの **手動** 制御について説明します。これは現在も完全にサポートされています。リソースを記述する `computeBindGroupFormat`(および必要に応じて `computeUniformBufferFormats`)を自分で指定し、WGSL に明示的な `@group`/`@binding` インデックスを記述します。次のような場合に使用します: + +- バインディングレイアウトを正確に制御したい +- 固定のバインディングでエンジンやアプリケーション所有のバッファと連携したい +- 明示的にバインドしたリソースと反映されるリソースを混在させたい + +:::note + +手動バインドグループは非推奨ではありません。`computeBindGroupFormat` を手書きしている既存のコンピュートシェーダーは、変更なしでそのまま動作します。都合のよいときに簡略化された構文へ移行しても、まったく移行しなくても構いません。 + +::: + +## バインドグループフォーマット + +`computeBindGroupFormat`は、コンピュートシェーダーで利用可能なリソースを定義します。これを指定する場合は、一致するように WGSL に明示的な `@group`/`@binding` インデックスを記述します。様々なタイプのリソースをバインドできます: + +```javascript +const shader = new pc.Shader(device, { + name: 'MyComputeShader', + shaderLanguage: pc.SHADERLANGUAGE_WGSL, + cshader: shaderCode, + computeBindGroupFormat: new pc.BindGroupFormat(device, [ + // リソースバインディングをここに記述 + ]) +}); +``` + +### ストレージバッファ + +ストレージバッファは、大量のデータへの読み書きアクセスを可能にします: + +```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; +} +``` + +## 反映リソースと手動リソースの混在 + +呼び出し側が指定する `computeBindGroupFormat` と、簡略化された(反映される)構文は、同じシェーダー内で併用できます: + +- `computeBindGroupFormat` に記述したリソースは、指定したバインディングで **グループ 0** に配置されます。 +- 簡略化された構文(`@group`/`@binding` なし)で宣言したリソースは引き続き反映され、**インデックス 1 の別のバインドグループ** に配置されます。 +- WGSL 内の明示的な(`@group`/`@binding` 付きの)宣言はそのまま保持されます。 + +`computeBindGroupFormat` を指定しない場合、反映されるリソースはグループ 0 に配置されます([コンピュートシェーダー](/user-manual/graphics/shaders/compute-shaders) を参照)。 + +いずれの場合も、リソースが手動バインドか反映かにかかわらず、値は `setParameter` で名前によって割り当てられます。 + +## サンプル + +以下のサンプルは手書きのバインドグループフォーマットを使用しています: + + + + + + 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 index 7f5efcea2ad..86d649a1374 100644 --- 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 @@ -1,6 +1,6 @@ --- title: コンピュートシェーダー -description: "WebGPU 専用の compute シェーダー:デバイスチェック、WGSL の cshader 定義、bind group、汎用 GPU 処理。" +description: "WebGPU 専用の compute シェーダー:デバイスチェック、簡略化された WGSL リソース宣言、ディスパッチ、汎用 GPU 処理。" --- コンピュートシェーダーは、レンダリングパイプラインとは独立して、GPU上で汎用計算を実行するプログラムです。頂点シェーダーやフラグメントシェーダーとは異なり、コンピュートシェーダーはジオメトリやピクセルに縛られず、任意のデータを操作するため、パーティクルシミュレーション、画像処理、物理計算、プロシージャルコンテンツ生成などのタスクに理想的です。 @@ -23,11 +23,11 @@ if (device.supportsCompute) { ## WGSL 言語拡張 -ブラウザが任意の WGSL 機能(例: [線形ワーカー / 呼び出しインデックス](https://developer.chrome.com/blog/new-in-webgpu-147-148#wgsl_linear_indexing_extension)、サブグループ、半精度 float)を公開している場合、エンジンは対応する `device.supports*` フラグと `CAPS_*` プリプロセッサ定義を設定します。一覧と注意点は [WGSL の詳細 — 言語拡張](/user-manual/graphics/shaders/wgsl-reflection#wgsl-language-extensions) を参照してください。 +ブラウザが任意の WGSL 機能(例: [線形ワーカー / 呼び出しインデックス](https://developer.chrome.com/blog/new-in-webgpu-147-148#wgsl_linear_indexing_extension)、サブグループ、半精度 float)を公開している場合、エンジンは対応する `device.supports*` フラグと `CAPS_*` プリプロセッサ定義を設定します。一覧と注意点は [WGSL 言語拡張](/user-manual/graphics/shaders/wgsl-capabilities#wgsl-language-extensions) を参照してください。 ## コンピュートシェーダーの作成 -コンピュートシェーダーは、WGSLコードを使用して`Shader`クラスで作成されます。シェーダー定義には、コンピュートシェーダーソース(`cshader`)、バインドグループフォーマット、およびオプションでユニフォームバッファフォーマットが含まれます。 +コンピュートシェーダーは、WGSL の `cshader` ソースを使用して `Shader` クラスで作成します。使用するリソース(ユニフォーム、ストレージバッファ、テクスチャ、ストレージテクスチャ)を簡略化された WGSL 構文(`@group`/`@binding` なし)で宣言すると、エンジンがソースからそれらを反映し、バインドグループを自動的に構築します。リソース宣言構文の詳細は [WGSL リフレクション](/user-manual/graphics/shaders/wgsl-reflection) を参照してください。 ### 基本的なシェーダー定義 @@ -36,17 +36,29 @@ const shader = new pc.Shader(device, { name: 'MyComputeShader', shaderLanguage: pc.SHADERLANGUAGE_WGSL, cshader: ` - @compute @workgroup_size(1, 1, 1) + // 簡略化された構文で宣言されたリソースは自動的に反映されます - + // computeBindGroupFormat は不要です + uniform count: u32; + var data: array; + + @compute @workgroup_size(64, 1, 1) fn main(@builtin(global_invocation_id) global_id: vec3u) { - // コンピュートシェーダーのロジックをここに記述 + let i = global_id.x; + if (i >= uniform.count) { return; } + data[i] = data[i] * 2.0; } - `, - computeBindGroupFormat: new pc.BindGroupFormat(device, [ - // リソースバインディングをここに記述 - ]) + ` }); ``` +:::note + +バインドグループを明示的に制御する必要がある場合(手動で記述する `computeBindGroupFormat`、明示的な `@group`/`@binding` インデックス、または手動バインドのリソースと反映されるリソースの混在)は、[コンピュートシェーダー(応用)](/user-manual/graphics/shaders/compute-shaders-advanced) を参照してください。 + +::: + +### エントリポイント + デフォルトでは、エンジンはエントリポイント関数の名前が`main`であることを期待します。`computeEntryPoint`を使用して別の関数名を指定することもでき、これにより単一のシェーダーソースに複数のエントリポイントを含めることもできます: ```javascript @@ -67,141 +79,17 @@ const initShader = new pc.Shader(device, { name: 'InitParticles', shaderLanguage: pc.SHADERLANGUAGE_WGSL, cshader: shaderSource, - computeEntryPoint: 'initParticles', - // ... + computeEntryPoint: 'initParticles' }); const updateShader = new pc.Shader(device, { name: 'UpdateParticles', shaderLanguage: pc.SHADERLANGUAGE_WGSL, cshader: shaderSource, - computeEntryPoint: 'updateParticles', - // ... + 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`クラスは、関連するパラメータを持つコンピュートシェーダーの実行可能なインスタンスを表します: @@ -212,17 +100,16 @@ const compute = new pc.Compute(device, shader, 'MyComputeInstance'); ## パラメータの設定 -`setParameter`を使用してリソースをバインドし、ユニフォーム値を設定します: +`setParameter`を使用してリソースをバインドし、ユニフォーム値を設定します。リソースは名前によってシェーダーの宣言に対応付けられます: ```javascript // ストレージバッファをバインド -compute.setParameter('particles', storageBuffer); +compute.setParameter('data', 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]); ``` @@ -284,6 +171,12 @@ compute2.setupDispatch(128, 128); device.computeDispatch([compute1, compute2], 'BatchedDispatch'); ``` +:::note + +`device.computeDispatch` は現在のフレームのコマンドエンコーダに記録されるため、**レンダリングフレーム内**(通常は `app.on('update', ...)` ハンドラ内)で呼び出す必要があります。フレーム外(`setTimeout` や切り離された Promise など)から呼び出すと信頼できず、ディスパッチが暗黙的にスキップされることがあります。 + +::: + ### ワークグループサイズ 総呼び出し回数は`dispatchSize × workgroupSize`です。例えば、`(width, height)`でディスパッチし、シェーダーが`@workgroup_size(1, 1, 1)`の場合、`width × height`回の呼び出しが行われます。 @@ -325,13 +218,7 @@ const slot = device.getIndirectDispatchSlot(); ### ディスパッチパラメータの書き込み -コンピュートシェーダーがディスパッチパラメータを書き込めるように、間接バッファを渡します。バインドグループフォーマットで: - -```javascript -new pc.BindStorageBufferFormat('indirectBuffer', pc.SHADERSTAGE_COMPUTE) -``` - -WGSLでは、間接ディスパッチレイアウトに一致する構造体を定義し、パラメータを書き込みます: +コンピュートシェーダー内で間接バッファを宣言し(自動的に反映されます)、予約したスロットにディスパッチパラメータを書き込みます。間接ディスパッチレイアウトに一致する構造体を定義します: ```wgsl struct DispatchIndirectArgs { @@ -340,8 +227,8 @@ struct DispatchIndirectArgs { z: u32 }; -@group(0) @binding(0) var indirectBuffer: array; -@group(0) @binding(1) var uniforms: Uniforms; // スロットインデックスを含む +var indirectBuffer: array; +uniform slot: u32; // 書き込み先のスロットインデックス @compute @workgroup_size(1) fn main() { @@ -349,9 +236,9 @@ fn main() { let workloadSize = calculateWorkload(); // ディスパッチパラメータをスロットに書き込み - indirectBuffer[uniforms.slot].x = workloadSize; - indirectBuffer[uniforms.slot].y = 1u; - indirectBuffer[uniforms.slot].z = 1u; + indirectBuffer[uniform.slot].x = workloadSize; + indirectBuffer[uniform.slot].y = 1u; + indirectBuffer[uniform.slot].z = 1u; } ``` @@ -434,7 +321,7 @@ storageBuffer.read(0, undefined, resultData, true).then((data) => { | インクルード | 説明 | |-------------|------| -| `halfTypesCS` | 半精度型エイリアス(`half`、`half2`など)。サポートされている場合はf16に、そうでない場合はf32に解決されます。[半精度型](/user-manual/graphics/shaders/wgsl-reflection#half-precision-types)を参照。 | +| `halfTypesCS` | 半精度型エイリアス(`half`、`half2`など)。サポートされている場合はf16に、そうでない場合はf32に解決されます。[半精度型](/user-manual/graphics/shaders/wgsl-capabilities#half-precision-types)を参照。 | 例: @@ -469,8 +356,7 @@ const shader = new pc.Shader(device, { cdefines: new Map([ ['{WORKGROUP_SIZE}', '64'] ]), - cincludes: pc.ShaderChunks.get(device, pc.SHADERLANGUAGE_WGSL), - // ... + cincludes: pc.ShaderChunks.get(device, pc.SHADERLANGUAGE_WGSL) }); ``` @@ -480,6 +366,14 @@ const shader = new pc.Shader(device, { 様々なコンピュートシェーダーのユースケースを示すライブサンプルを探索してください: +- Edge Detect - エッジ検出による画像処理 + + + +- Particles - 衝突検出付きGPUベースのパーティクルシミュレーション + + + - Histogram - アトミック操作を使用した画像ヒストグラムの計算 @@ -488,18 +382,10 @@ const shader = new pc.Shader(device, { -- Particles - 衝突検出付きGPUベースのパーティクルシミュレーション - - - - Vertex Update - メッシュ頂点バッファのリアルタイム変更 -- Edge Detect - エッジ検出による画像処理 - - - - Indirect Draw - 間接描画呼び出しによるGPU駆動レンダリング diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-capabilities.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-capabilities.md new file mode 100644 index 00000000000..5386b9ece82 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-capabilities.md @@ -0,0 +1,123 @@ +--- +title: WGSL ケイパビリティ +description: "デバイス依存の任意の WGSL 機能:半精度型と WGSL 言語拡張、およびそれらの CAPS_* 定義。" +--- + +このページでは、デバイスのサポートに依存する任意の WGSL 機能について説明します。エンジンは各ケイパビリティを `device.supports*` フラグと対応する `CAPS_*` プリプロセッサ定義で公開し、必要に応じて `enable …;` / `requires …;` ディレクティブを生成される WGSL に注入します。これらの機能は頂点・フラグメント・コンピュートシェーダーにわたって利用できます。 + +### 半精度型 {#half-precision-types} + +デバイスが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 言語拡張 {#wgsl-language-extensions} + +デバイス作成時に、エンジンは `navigator.gpu.wgslLanguageFeatures` を読み取り、任意の言語機能用に必要な `enable …;` および `requires …;` ディレクティブを生成される WGSL に付加します。シェーダー側では、対応する `CAPS_*` 定義(`Shader` 定義の `vertexDefines` / `fragmentDefines` / `cdefines` とマージ)で分岐できます。 + +- **`device.supportsShaderF16`** + - **エンジンが注入:** `enable f16;` + - **プリプロセッサ定義:** `CAPS_SHADER_F16` + - **シェーダー段階:** 頂点、フラグメント、コンピュート + - **説明:** 本ページの [半精度型](#half-precision-types) および、エンジンが付与する `half` / `half2` などのエイリアス +- **`device.supportsPrimitiveIndex`** + - **エンジンが注入:** `enable primitive_index;` + - **プリプロセッサ定義:** `CAPS_PRIMITIVE_INDEX` + - **シェーダー段階:** フラグメント + - **説明:** 簡略 API では、対応端末向けに `FragmentInput` の `primitiveIndex` およびグローバル `pcPrimitiveIndex` +- **`device.supportsSubgroups`** + - **エンジンが注入:** `enable subgroups;` + - **プリプロセッサ定義:** `CAPS_SUBGROUPS` + - **シェーダー段階:** フラグメントとコンピュート + - **説明:** サブグループ組み込み(`subgroupBroadcast` 等)。`device.supportsSubgroupUniformity` 専用の `requires` / `enable` は追加されず、subgroups 機能と合わせて扱う +- **`device.supportsSubgroupId`** + - **エンジンが注入:** `requires subgroup_id;` + - **プリプロセッサ定義:** `CAPS_SUBGROUP_ID` + - **シェーダー段階:** その `Shader` 定義に応じ、エンジンが WGSL へコンパイルする段階(使用する各段階向けのモジュール) + - **説明:** ワークグループ内の `subgroup_id` / `num_subgroups` 組み込み +- **`device.supportsLinearIndexing`** + - **エンジンが注入:** `requires linear_indexing;`(**コンピュート** エントリのモジュールのみ。頂点・フラグメントには入れない) + - **プリプロセッサ定義:** `CAPS_LINEAR_INDEXING` + - **シェーダー段階:** コンピュート + - **説明:** `global_invocation_index` / `workgroup_index`。解説: [WebGPU 147-148](https://developer.chrome.com/blog/new-in-webgpu-147-148#wgsl_linear_indexing_extension) +- **`device.supportsStorageTextureRead`** + - **エンジンが注入:** *なし* — ストレージテクスチャを読む場合は、WGSL 内に `requires readonly_and_readwrite_storage_textures;` を自前で記述 + - **プリプロセッサ定義:** `CAPS_STORAGE_TEXTURE_READ`(デバイスがストレージテクスチャの読み取りに対応しているときに有効。コードパス分岐用) + - **シェーダー段階:** 機能を使う場合にコンピュート + - **説明:** エンジンは能力の宣言のみ。`requires` は必ず筆者が書く想定 +- **`device.supportsUnrestrictedPointerParameters`** + - **エンジンが注入:** `requires unrestricted_pointer_parameters;` + - **プリプロセッサ定義:** `CAPS_UNRESTRICTED_POINTER_PARAMETERS` + - **シェーダー段階:** 頂点・フラグメント・コンピュート + - **説明:** `storage`・`uniform`・`workgroup` アドレス空間のポインタを関数の引数として渡せるようにします +- **`device.supportsPointerCompositeAccess`** + - **エンジンが注入:** `requires pointer_composite_access;` + - **プリプロセッサ定義:** `CAPS_POINTER_COMPOSITE_ACCESS` + - **シェーダー段階:** 頂点・フラグメント・コンピュート + - **説明:** 複合型へのポインタのデリファレンスの糖衣構文。`(*p).field` や `(*p)[i]` の代わりに `p.field` や `p[i]` と書けます +- **`device.supportsPacked4x8IntegerDotProduct`** + - **エンジンが注入:** `requires packed_4x8_integer_dot_product;` + - **プリプロセッサ定義:** `CAPS_PACKED_4X8_INTEGER_DOT_PRODUCT` + - **シェーダー段階:** 頂点・フラグメント・コンピュート + - **説明:** 8ビットパック整数の内積向け DP4a 系の組み込み関数(`dot4U8Packed`、`dot4I8Packed`、および `pack4x{I,U}8`、`pack4x{I,U}8Clamp`、`unpack4x{I,U}8` ヘルパー)を公開します。量子化推論や整数中心のコンピュートに有用 +- **`device.supportsTextureAndSamplerLet`** + - **エンジンが注入:** `requires texture_and_sampler_let;` + - **プリプロセッサ定義:** `CAPS_TEXTURE_AND_SAMPLER_LET` + - **シェーダー段階:** 頂点・フラグメント・コンピュート + - **説明:** テクスチャ・サンプラー変数を `let` バインディングに代入できるようにします(バインドレス的な間接参照パターンへの準備) + +使用例(コンピュート)— `CAPS_LINEAR_INDEXING` があるときは線形のワークグループ番号を使い、なければ従来の方法で求めます。 + +```wgsl +@compute @workgroup_size(64, 1, 1) +fn main( + @builtin(global_invocation_id) global_id: vec3u, + @builtin(num_workgroups) nwg: vec3u, +#ifdef CAPS_LINEAR_INDEXING + @builtin(workgroup_index) flat_wg: u32, +#endif +) { +#ifdef CAPS_LINEAR_INDEXING + let wg = flat_wg; +#else + let wg = global_id.x; // 1D ディスパッチ; 2D/3D は必要に応じて拡張 +#endif + _ = wg; +} +``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-reflection.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-reflection.md index 9e037df3757..021d1d88a01 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-reflection.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-reflection.md @@ -1,11 +1,11 @@ --- -title: WGSL の詳細 -description: "手動の bind group なしの簡略化された WGSL 宣言:PlayCanvas がバインディングを割り当てリソースを統合する方法。" +title: WGSL リフレクション +description: "手動の bind group なしの簡略化された WGSL 宣言:PlayCanvas がシェーダーソースからリソースを反映しバインディングを割り当てる方法。" --- -PlayCanvasエンジンで使用されるWGSLシェーダーは、特定の要件を満たす必要があります。これらの要件により、エンジンはシェーダーを正しく統合し、属性、ユニフォーム、バリイングなどの必要なリソースを確実に受け取ることができます。 +PlayCanvas は WGSL シェーダーのソースからリソースを直接反映(リフレクト)します。ユニフォーム、テクスチャ、ストレージバッファを `@group`/`@binding` インデックスなしで宣言すると、エンジンがこれらの宣言を解析し、バインドグループ形式を構築してバインディングを自動的に割り当てます。この簡略化された構文は、頂点・フラグメント・コンピュートシェーダーで使用されます。 -以下のセクションでは、PlayCanvas用のWGSLシェーダーを記述する際の主要な側面について説明します。 +以下のセクションでは、リソースの宣言と反映の方法を説明します。頂点/フラグメント固有の構文(属性、バリイング、フラグメント出力)については、[WGSL 頂点・フラグメントシェーダー](/user-manual/graphics/shaders/wgsl-vertex-fragment-shaders) を参照してください。 ### 簡略化されたシェーダーインターフェース構文 @@ -45,38 +45,6 @@ varying uv0: vec2f; } ``` -### 属性 - -属性は頂点ごとの入力データを定義し、頂点シェーダーでのみ使用できます。以下の構文を使用して宣言する必要があります: - -```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`プロパティで指定した名前と一致する必要があります。 - ### ユニフォーム ユニフォームは、エンジンからシェーダーに*数値リソース*を渡すために使用されます。 @@ -217,219 +185,18 @@ struct Particle { var particles: array; ``` -### 半精度型 {#half-precision-types} - -デバイスが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;` および `CAPS_PRIMITIVE_INDEX` については [WGSL 言語拡張](#wgsl-language-extensions) を参照してください。 - -::: - -例: +ストレージテクスチャを使うと、シェーダーはサンプラーなしでテクセルを直接書き込み(および必要に応じて読み取り)できます。最も一般的にはコンピュートシェーダーの出力として使用されます。簡略化された`texture_storage_*`構文で、フォーマットとアクセスモードを指定して宣言します: ```wgsl -varying texCoord: vec2f; +// 書き込み専用ストレージテクスチャ(コンピュート出力の一般的なケース) +var outputTexture: texture_storage_2d; -@fragment -fn fragmentMain(input: FragmentInput) -> FragmentOutput { - var output: FragmentOutput; - output.color = vec4f(1.0); - return output; -} +// テクセルの書き込み +textureStore(outputTexture, vec2i(global_id.xy), color); ``` -### フラグメントシェーダー出力 +アクセスモードは`write`、`read`、`read_write`のいずれかです。ストレージテクスチャの読み取り(`read` / `read_write`)には、`device.supportsStorageTextureRead`のサポートと、筆者が記述する`requires readonly_and_readwrite_storage_textures;`ディレクティブが必要です。[WGSL ケイパビリティ](/user-manual/graphics/shaders/wgsl-capabilities#wgsl-language-extensions)を参照してください。 -フラグメントシェーダーは、フレームバッファのレンダーターゲット(カラーアタッチメント)に書き込まれる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`以外の出力フォーマット)のサポートはまだ利用できませんが、将来追加される予定です。 - -::: - -### WGSL 言語拡張 {#wgsl-language-extensions} - -デバイス作成時に、エンジンは `navigator.gpu.wgslLanguageFeatures` を読み取り、任意の言語機能用に必要な `enable …;` および `requires …;` ディレクティブを生成される WGSL に付加します。シェーダー側では、対応する `CAPS_*` 定義(`Shader` 定義の `vertexDefines` / `fragmentDefines` / `cdefines` とマージ)で分岐できます。 - -- **`device.supportsShaderF16`** - - **エンジンが注入:** `enable f16;` - - **プリプロセッサ定義:** `CAPS_SHADER_F16` - - **シェーダー段階:** 頂点、フラグメント、コンピュート - - **説明:** 本ページの [半精度型](#half-precision-types) および、エンジンが付与する `half` / `half2` などのエイリアス -- **`device.supportsPrimitiveIndex`** - - **エンジンが注入:** `enable primitive_index;` - - **プリプロセッサ定義:** `CAPS_PRIMITIVE_INDEX` - - **シェーダー段階:** フラグメント - - **説明:** 簡略 API では、対応端末向けに `FragmentInput` の `primitiveIndex` およびグローバル `pcPrimitiveIndex` -- **`device.supportsSubgroups`** - - **エンジンが注入:** `enable subgroups;` - - **プリプロセッサ定義:** `CAPS_SUBGROUPS` - - **シェーダー段階:** フラグメントとコンピュート - - **説明:** サブグループ組み込み(`subgroupBroadcast` 等)。`device.supportsSubgroupUniformity` 専用の `requires` / `enable` は追加されず、subgroups 機能と合わせて扱う -- **`device.supportsSubgroupId`** - - **エンジンが注入:** `requires subgroup_id;` - - **プリプロセッサ定義:** `CAPS_SUBGROUP_ID` - - **シェーダー段階:** その `Shader` 定義に応じ、エンジンが WGSL へコンパイルする段階(使用する各段階向けのモジュール) - - **説明:** ワークグループ内の `subgroup_id` / `num_subgroups` 組み込み -- **`device.supportsLinearIndexing`** - - **エンジンが注入:** `requires linear_indexing;`(**コンピュート** エントリのモジュールのみ。頂点・フラグメントには入れない) - - **プリプロセッサ定義:** `CAPS_LINEAR_INDEXING` - - **シェーダー段階:** コンピュート - - **説明:** `global_invocation_index` / `workgroup_index`。解説: [WebGPU 147-148](https://developer.chrome.com/blog/new-in-webgpu-147-148#wgsl_linear_indexing_extension) -- **`device.supportsStorageTextureRead`** - - **エンジンが注入:** *なし* — ストレージテクスチャを読む場合は、WGSL 内に `requires readonly_and_readwrite_storage_textures;` を自前で記述 - - **プリプロセッサ定義:** `CAPS_STORAGE_TEXTURE_READ`(デバイスがストレージテクスチャの読み取りに対応しているときに有効。コードパス分岐用) - - **シェーダー段階:** 機能を使う場合にコンピュート - - **説明:** エンジンは能力の宣言のみ。`requires` は必ず筆者が書く想定 -- **`device.supportsUnrestrictedPointerParameters`** - - **エンジンが注入:** `requires unrestricted_pointer_parameters;` - - **プリプロセッサ定義:** `CAPS_UNRESTRICTED_POINTER_PARAMETERS` - - **シェーダー段階:** 頂点・フラグメント・コンピュート - - **説明:** `storage`・`uniform`・`workgroup` アドレス空間のポインタを関数の引数として渡せるようにします -- **`device.supportsPointerCompositeAccess`** - - **エンジンが注入:** `requires pointer_composite_access;` - - **プリプロセッサ定義:** `CAPS_POINTER_COMPOSITE_ACCESS` - - **シェーダー段階:** 頂点・フラグメント・コンピュート - - **説明:** 複合型へのポインタのデリファレンスの糖衣構文。`(*p).field` や `(*p)[i]` の代わりに `p.field` や `p[i]` と書けます -- **`device.supportsPacked4x8IntegerDotProduct`** - - **エンジンが注入:** `requires packed_4x8_integer_dot_product;` - - **プリプロセッサ定義:** `CAPS_PACKED_4X8_INTEGER_DOT_PRODUCT` - - **シェーダー段階:** 頂点・フラグメント・コンピュート - - **説明:** 8ビットパック整数の内積向け DP4a 系の組み込み関数(`dot4U8Packed`、`dot4I8Packed`、および `pack4x{I,U}8`、`pack4x{I,U}8Clamp`、`unpack4x{I,U}8` ヘルパー)を公開します。量子化推論や整数中心のコンピュートに有用 -- **`device.supportsTextureAndSamplerLet`** - - **エンジンが注入:** `requires texture_and_sampler_let;` - - **プリプロセッサ定義:** `CAPS_TEXTURE_AND_SAMPLER_LET` - - **シェーダー段階:** 頂点・フラグメント・コンピュート - - **説明:** テクスチャ・サンプラー変数を `let` バインディングに代入できるようにします(バインドレス的な間接参照パターンへの準備) - -使用例(コンピュート)— `CAPS_LINEAR_INDEXING` があるときは線形のワークグループ番号を使い、なければ従来の方法で求めます。 - -```wgsl -@compute @workgroup_size(64, 1, 1) -fn main( - @builtin(global_invocation_id) global_id: vec3u, - @builtin(num_workgroups) nwg: vec3u, -#ifdef CAPS_LINEAR_INDEXING - @builtin(workgroup_index) flat_wg: u32, -#endif -) { -#ifdef CAPS_LINEAR_INDEXING - let wg = flat_wg; -#else - let wg = global_id.x; // 1D ディスパッチ; 2D/3D は必要に応じて拡張 -#endif - _ = wg; -} -``` +バインドするテクスチャは`storage: true`オプションで作成する必要があります([コンピュートシェーダー](/user-manual/graphics/shaders/compute-shaders)を参照)。 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-vertex-fragment-shaders.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-vertex-fragment-shaders.md new file mode 100644 index 00000000000..da23fcc8bb3 --- /dev/null +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/wgsl-vertex-fragment-shaders.md @@ -0,0 +1,140 @@ +--- +title: WGSL 頂点・フラグメントシェーダー +description: "PlayCanvas における頂点・フラグメント固有の WGSL 構文:属性、バリイング、フラグメント出力。" +--- + +このページでは、頂点シェーダーとフラグメントシェーダーに固有の WGSL 構文(属性、バリイング、フラグメント出力)について説明します。 + +すべてのシェーダー段階で共有されるリソース(ユニフォーム、テクスチャ、ストレージバッファ。簡略化された構文で宣言され、バインドグループへ自動的に反映されます)については、[WGSL リフレクション](/user-manual/graphics/shaders/wgsl-reflection) を参照してください。 + +### 属性 + +属性は頂点ごとの入力データを定義し、頂点シェーダーでのみ使用できます。以下の構文を使用して宣言する必要があります: + +```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 +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;` および `CAPS_PRIMITIVE_INDEX` については [WGSL 言語拡張](/user-manual/graphics/shaders/wgsl-capabilities#wgsl-language-extensions) を参照してください。 + +::: + +例: + +```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`以外の出力フォーマット)のサポートはまだ利用できませんが、将来追加される予定です。 + +::: diff --git a/sidebars.js b/sidebars.js index 1221ff27978..d3916309df0 100644 --- a/sidebars.js +++ b/sidebars.js @@ -769,6 +769,7 @@ const sidebars = { 'user-manual/graphics/shaders/wgsl-capabilities', 'user-manual/graphics/shaders/wgsl-vertex-fragment-shaders', 'user-manual/graphics/shaders/compute-shaders', + 'user-manual/graphics/shaders/compute-shaders-advanced', 'user-manual/graphics/shaders/migrations', ], },