diff --git a/docs/user-manual/graphics/shaders/glsl-specifics.md b/docs/user-manual/graphics/shaders/glsl-specifics.md index b9c273a643..4a80a323a6 100644 --- a/docs/user-manual/graphics/shaders/glsl-specifics.md +++ b/docs/user-manual/graphics/shaders/glsl-specifics.md @@ -15,13 +15,13 @@ The following sections outline key aspects of writing GLSL shaders for PlayCanva ### Attributes -Attributes define per-vertex input data. They must be declared using the following syntax: +Attributes define per-vertex input data, and can only be used in the vertex shader. They must be declared using the following syntax: ```glsl attribute vec2 aUv0; ``` -The attribute name must match the name specified in the `attributes` property when creating the [ShaderMaterial][1]. +The attribute names must match the names specified in the `attributes` property when creating the [ShaderMaterial][1]. :::note @@ -39,6 +39,12 @@ uniform vec3 view_position; The engine automatically sets appropriate uniform values when rendering. +:::note + +Currently, our uniform system supports only simple types, including `float`, `int`, `uint`, as well as vectors and matrices (e.g., `vec4`, `mat4`). Structs are not supported at this time, so all uniform values must be declared as individual variables of basic types. + +::: + ### Varyings Varyings are used to pass values from the vertex shader to the fragment shader. They must be declared using standard GLSL syntax: diff --git a/docs/user-manual/graphics/shaders/index.md b/docs/user-manual/graphics/shaders/index.md index 1ed474d04e..d0cade86f2 100644 --- a/docs/user-manual/graphics/shaders/index.md +++ b/docs/user-manual/graphics/shaders/index.md @@ -11,30 +11,36 @@ To create an instance of `ShaderMaterial`, these are the steps: Create a description of your shader: -``` javascript +```javascript const shaderDesc = { - uniqueName: 'MyShader', - shaderLanguage: pc.SHADERLANGUAGE_GLSL, - vertexCode: ` - // write your vertex shader source code - `, - fragmentCode: ` - // write your fragment shader source code - `, - attributes: { - aPosition: pc.SEMANTIC_POSITION, - aUv0: pc.SEMANTIC_TEXCOORD0 - } -}; + uniqueName: 'MyShader', + vertexGLSL: ` + // write your vertex shader source code in GLSL language + `, + fragmentGLSL: ` + // write your fragment shader source code in GLSL language + `, + vertexWGSL: ` + // write your vertex shader source code in WGSL language + `, + fragmentWGSL: ` + // write your fragment shader source code in WGSL language + `, + attributes: { + aPosition: pc.SEMANTIC_POSITION, + aUv0: pc.SEMANTIC_TEXCOORD0 + } + }; + ``` Then create instances of your material, which you can use for rendering: -``` javascript +```javascript const material = new pc.ShaderMaterial(shaderDesc); ``` -The shader source code can be written in GLSL if you're targeting the WebGL2 or WebGPU platforms, or in WGSL if you're targeting WebGPU only. +The shader source code can be written in GLSL if you're targeting the WebGL2 or WebGPU platforms, or in WGSL if you're targeting WebGPU only, or both. :::note @@ -48,7 +54,9 @@ Before the shader is used, a preprocessing step is applied, allowing you to mana This preprocessing step follows a typical C-like preprocessor structure, handling directives such as `#define`, `#if`, `#else`, `#endif`, and similar. This gives you fine-grained control over how the shader code is compiled and customized for different use cases. -### Material Shader Defines {#material-shader-defines} +You can also use a `#include` directive to include one of the registered shader chunks. For example: `#include "screenDepthPS"` + +### Material Shader Defines Shader defines can be set on a per-material basis, allowing dynamic customization of shader behavior. For example: @@ -207,4 +215,8 @@ And Each created shader will be logged in the browser console, where you can ins For further information, refer to the [ShaderMaterial API documentation](https://api.playcanvas.com/engine/classes/ShaderMaterial.html). +### Compute shaders + +Compute shaders are currently supported by the engine when using WebGPU, but their integration is still evolving. Full documentation will be provided as the system matures and stabilizes. In the meantime, we recommend studying the available engine examples, which demonstrate how compute shaders can be written, dispatched, and used within the current framework. + [1]: /user-manual/graphics/physical-rendering/physical-materials/ diff --git a/docs/user-manual/graphics/shaders/migrations.md b/docs/user-manual/graphics/shaders/migrations.md index d6f8699fe0..4f27975853 100644 --- a/docs/user-manual/graphics/shaders/migrations.md +++ b/docs/user-manual/graphics/shaders/migrations.md @@ -15,11 +15,12 @@ The debug version of the Engine will report any API changes to the runtime conso ![Console output](/img/user-manual/graphics/shader-chunk-migrations/console-warning.png) -Once an application's chunks have been updated to the latest API they must be flagged as such. For example, after updating a material's custom chunks to the latest engine release (say v1.55), specify this in the chunks object as follows: +Once an application's chunks have been updated to the latest API they must be flagged as such. For example, after updating a material's custom chunks to the latest engine release (say v2.8), specify this in the chunks object as follows: ```javascript -material.chunks.diffusePS = '...'; -material.chunks.APIVersion = pc.CHUNKAPI_1_55; +const materialChunksGLSL = material.getShaderChunks(pc.SHADERLANGUAGE_GLSL); +materialChunksGLSL.set('diffusePS', '...'); +material.shaderChunksVersion = '2.8'; ``` By doing this you will no longer see warning messages in the console. diff --git a/docs/user-manual/graphics/shaders/wgsl-specifics.md b/docs/user-manual/graphics/shaders/wgsl-specifics.md index 52d9d7e34d..37845b28d7 100644 --- a/docs/user-manual/graphics/shaders/wgsl-specifics.md +++ b/docs/user-manual/graphics/shaders/wgsl-specifics.md @@ -3,4 +3,273 @@ title: WGSL Specifics sidebar_position: 2 --- -Support for WGSL in the PlayCanvas engine is under active development. Detailed information on WGSL shader requirements and integration will be provided once the implementation is finalized. +WGSL shaders used by the PlayCanvas engine must satisfy certain requirements. These requirements allow the engine to correctly integrate shaders, ensuring they receive the necessary resources such as attributes, uniforms, and varyings. + +The following sections outline key aspects of writing WGSL shaders for PlayCanvas. + +### Simplified Shader Interface Syntax + +In standard WGSL (WebGPU Shading Language), declaring uniforms, attributes, and varyings requires explicitly specifying a `@group` and `@binding` index for each resource. This can be verbose and error-prone, especially for common patterns. + +To improve usability and streamline shader development, we adopt a simplified syntax similar to GLSL. In this model, you do not need to specify `@group` or `@binding` attributes manually—these are automatically assigned and managed by the engine based on a predefined layout. + +#### Example Comparison + +Standard 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 { + // body +} +``` + +In contrast, the simplified syntax avoids a lot of the boilerplate. + +```wgsl +uniform uTime: f32; +varying uv0: vec2f; + +@fragment fn fragmentMain(input: FragmentInput) -> FragmentOutput { + // body +} +``` + +### Attributes + +Attributes define per-vertex input data, and can only be used in the vertex shader. They must be declared using the following syntax: + +```wgsl +attribute aUv0: vec2f; +``` + +Internally, a `VertexInput` struct is automatically created and populated with all the attributes. Attributes can be accessed from the structure passed to the main function, but also in the global scope. + +```wgsl +attribute aUv0: vec2f; + +@vertex fn vertexMain(input: VertexInput) -> VertexOutput { + + // access it using input passed to the main function + var myUv1 = input.aUv0; + + // but also as a global variable (particularly useful inside other functions) + var myUv2 = aUv0; +} +``` + +As part of the `VertexInput` structure, and also in the global scope, these built-in attributes are automatically available: + +```wgsl +vertexIndex: @builtin(vertex_index) +instanceIndex: @builtin(instance_index) +``` + +The attribute names must match the names specified in the `attributes` property when creating the [ShaderMaterial][1]. + +### Uniforms + +Uniforms are used to pass *numerical resources* from the engine to the shader. + +Uniforms are declared using this simplified syntax: + +```wgsl +uniform view_position: vec3f; +uniform tints: array; +uniform weights: array; +``` + +Internally, uniforms are automatically placed in uniform buffers, and in the shader code are accessed using a `uniform.` prefix: + +```wgsl +var pos = uniform.view_position; +var color = uniform.tints[2]; + +// f32 and vec2<> types used in an array are due to alignment requirements wrapped +// in an aligned structure, and the value is available as its `element` property. +// struct WrappedF32 { @size(16) element: f32 } +var weight = uniform.weights[3].element; +``` + +The engine automatically sets appropriate uniform values when rendering. + +:::note + +Currently, our uniform system supports only simple types, including `f32`, `i32`, `u32`, as well as vectors and matrices (e.g., `vec4f`, `mat4x4f`). Structs are not supported at this time, so all uniform values must be declared as individual variables of basic types. + +::: + +### Texture Resources + +Texture resources are using simplified WGSL syntax, where specifying a `@group` and `@binding` index for each resource has to be omitted. + +#### Sampling Textures + +In WGSL, textures and samplers are treated as separate objects, unlike in GLSL, where those are combined. + +When you want to sample a texture (i.e. retrieve filtered texel values), you must provide a texture object *directly followed* by a sampler. + +```wgsl +// 2d texture with a sampler declaration +var diffuseMap: texture_2d; +var diffuseMapSampler: sampler; + +// texture sampling +var texel = textureSample(diffuseMap, diffuseMapSampler, coords); +``` + +#### Fetching Textures + +If you only need to read raw texel data (i.e., without filtering, mipmapping, or addressing modes), you can use `textureLoad` instead of `textureSample`. This is called non-filtered access, or simply texel fetching. + +In such cases, no sampler is required or allowed. For example: + +```wlsl +// cubemap texture without a sampler +var noSamplerMap: texture_cube; + +// fetching the texel +let texel = textureLoad(noSamplerMap, coords, mipLevel); +``` + +#### Unfilterable Textures + +WebGPU supports unfilterable float textures, which are typically used for specialized purposes such as sampling from depth textures, where filtering is not allowed. However, WGSL does not provide a distinct sample type in the syntax for declaring these unfilterable float textures. To address this limitation and enable proper bind group auto-generation based on shader declarations, we introduce a new sample type called `uff` (unfilterable-float). + +Using `uff`, you can explicitly declare an unfilterable-float texture in the shader like this: + +```wgsl +// declaration +var colorMap: texture_2d; + +// sampling +let data: vec4f = textureLoad(colorMap, uv, 0); +``` + +This extension allows the engine to correctly interpret the texture’s sampling capabilities and bind it accordingly. + +:::note + +Support for `texture_external` is not available yet, and will be added in the future. + +::: + +### Storage Buffers + +Storage buffers are GPU-accessible memory resources that allow shaders to read and write arbitrary data with random access. In WGSL, they are declared using `var` and are ideal for working with large or structured datasets such as particle systems, compute data, or dynamic geometry. Unlike uniforms, storage buffers support both read and write access (with appropriate access control). + +Example of using storage buffer in Vertex Shader: + +```wgsl +struct Particle { + position: vec3f, + velocity: vec3f, +} + +// particle storage buffer in read-only mode +var particles: array; +``` + +### 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: + +```wgsl +varying texCoord: vec2f; +``` + +Internally, those are parsed, and stored in `VertexOutput` structure in the vertex shader, as well as in `FragmentInput` structure in the fragment shader. + +#### Vertex Shader + +As part of the `VertexOutput` structure these built-in variables are automatically available: + +```wgsl +position: @builtin(position) +``` + +Example: + +```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; +} +``` + +#### Fragment Shader + +As part of the `FragmentInput` structure these built-in variables are automatically available: + +```wgsl +position: @builtin(position) // interpolated fragment position +frontFacing: @builtin(front_facing) // front-facing +sampleIndex: builtin(sample_index) // sample index for MSAA +``` + +These built-ins are also available in the global scope using these names: + +```wgsl +pcPosition +pcFrontFacing +pcSampleIndex +``` + +Example: + +```wgsl +varying texCoord: vec2f; + +@fragment +fn fragmentMain(input: FragmentInput) -> FragmentOutput { + var output: FragmentOutput; + output.color = vec4f(1.0); + return output; +} +``` + +### Fragment Shader Outputs + +The fragment shader is responsible for producing one or more color outputs, which are written to the render targets (color attachments) of the framebuffer. + +The engine automatically provides a `FragmentOutput` structure, which includes a predefined set of vec4f fields: `color`, `color1`, `color2` and so on, covering all possible color attachments, up to the limit defined by `GraphicsDevice.maxColorAttachments`. + +As part of the `FragmentOutput` structure these built-in variables are automatically available: + +```wgsl +fragDepth: @builtin(frag_depth) +``` + +Example: + +```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 + +Support for rendering to integer textures (output format other then `vec4f`) is not available yet, and will be added in the future. + +::: + +[1]: /user-manual/graphics/shaders/ diff --git a/docs/user-manual/pcui/pcui-graph/context-menus.md b/docs/user-manual/pcui/pcui-graph/context-menus.md index bf7a766df0..799f5ca4e3 100644 --- a/docs/user-manual/pcui/pcui-graph/context-menus.md +++ b/docs/user-manual/pcui/pcui-graph/context-menus.md @@ -55,13 +55,13 @@ const schema = { Currently, node context menus support two actions: -``` javascript +```javascript Graph.GRAPH_ACTIONS.DELETE_NODE // Delete the node associated with this context menu. Graph.GRAPH_ACTIONS.ADD_EDGE // Add an edge that starts from the node associated with this context menu, selecting another node will complete the edge connection. Selecting the background canvas will cancel adding an edge. ``` While edges support their own deletion by adding this action in their context menu: -``` javascript +```javascript Graph.GRAPH_ACTIONS.DELETE_EDGE // Delete the edge associated with this context menu. ``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md index 76f7de7bbb..a1e5d2c70b 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md @@ -11,7 +11,7 @@ sidebar_position: 5 シェーダーの記述を作成します。 -``` javascript +```javascript const shaderDesc = { uniqueName: 'MyShader', shaderLanguage: pc.SHADERLANGUAGE_GLSL, @@ -30,7 +30,7 @@ const shaderDesc = { 次に、レンダリングに使用できるマテリアルのインスタンスを作成します。 -``` javascript +```javascript const material = new pc.ShaderMaterial(shaderDesc); ``` diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/pcui/pcui-graph/context-menus.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/pcui/pcui-graph/context-menus.md index 49ee41556b..9270301784 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/pcui/pcui-graph/context-menus.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/pcui/pcui-graph/context-menus.md @@ -55,13 +55,13 @@ const schema = { 現在、ノードのコンテキストメニューは2つのアクションをサポートしています。 -``` javascript +```javascript Graph.GRAPH_ACTIONS.DELETE_NODE // このコンテキストメニューに関連付けられたノードを削除します。 Graph.GRAPH_ACTIONS.ADD_EDGE // このコンテキストメニューに関連付けられたノードから開始するエッジを追加します。別のノードを選択するとエッジ接続が完了します。バックグラウンドキャンバスを選択すると、エッジの追加がキャンセルされます。 ``` 一方、エッジは、このアクションをコンテキストメニューに追加することで、自身の削除をサポートします。 -``` javascript +```javascript Graph.GRAPH_ACTIONS.DELETE_EDGE // このコンテキストメニューに関連付けられたエッジを削除します。 ```