Skip to content

Commit 30aedb6

Browse files
mvaligurskyMartin Valigurskywilleastcott
authored
WGSL manual page (#749)
* WGSL manual page * lint * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * removed space * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * updated doc to use new chunk API * Update docs/user-manual/graphics/shaders/index.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> * Apply suggestions from code review Co-authored-by: Will Eastcott <[email protected]> * Apply suggestions from code review Co-authored-by: Will Eastcott <[email protected]> * built-ins * Update docs/user-manual/graphics/shaders/wgsl-specifics.md Co-authored-by: Will Eastcott <[email protected]> --------- Co-authored-by: Martin Valigursky <[email protected]> Co-authored-by: Will Eastcott <[email protected]>
1 parent 16c9047 commit 30aedb6

File tree

7 files changed

+317
-29
lines changed

7 files changed

+317
-29
lines changed

docs/user-manual/graphics/shaders/glsl-specifics.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ The following sections outline key aspects of writing GLSL shaders for PlayCanva
1515

1616
### Attributes
1717

18-
Attributes define per-vertex input data. They must be declared using the following syntax:
18+
Attributes define per-vertex input data, and can only be used in the vertex shader. They must be declared using the following syntax:
1919

2020
```glsl
2121
attribute vec2 aUv0;
2222
```
2323

24-
The attribute name must match the name specified in the `attributes` property when creating the [ShaderMaterial][1].
24+
The attribute names must match the names specified in the `attributes` property when creating the [ShaderMaterial][1].
2525

2626
:::note
2727

@@ -39,6 +39,12 @@ uniform vec3 view_position;
3939

4040
The engine automatically sets appropriate uniform values when rendering.
4141

42+
:::note
43+
44+
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.
45+
46+
:::
47+
4248
### Varyings
4349

4450
Varyings are used to pass values from the vertex shader to the fragment shader. They must be declared using standard GLSL syntax:

docs/user-manual/graphics/shaders/index.md

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,36 @@ To create an instance of `ShaderMaterial`, these are the steps:
1111

1212
Create a description of your shader:
1313

14-
``` javascript
14+
```javascript
1515
const shaderDesc = {
16-
uniqueName: 'MyShader',
17-
shaderLanguage: pc.SHADERLANGUAGE_GLSL,
18-
vertexCode: `
19-
// write your vertex shader source code
20-
`,
21-
fragmentCode: `
22-
// write your fragment shader source code
23-
`,
24-
attributes: {
25-
aPosition: pc.SEMANTIC_POSITION,
26-
aUv0: pc.SEMANTIC_TEXCOORD0
27-
}
28-
};
16+
uniqueName: 'MyShader',
17+
vertexGLSL: `
18+
// write your vertex shader source code in GLSL language
19+
`,
20+
fragmentGLSL: `
21+
// write your fragment shader source code in GLSL language
22+
`,
23+
vertexWGSL: `
24+
// write your vertex shader source code in WGSL language
25+
`,
26+
fragmentWGSL: `
27+
// write your fragment shader source code in WGSL language
28+
`,
29+
attributes: {
30+
aPosition: pc.SEMANTIC_POSITION,
31+
aUv0: pc.SEMANTIC_TEXCOORD0
32+
}
33+
};
34+
2935
```
3036

3137
Then create instances of your material, which you can use for rendering:
3238

33-
``` javascript
39+
```javascript
3440
const material = new pc.ShaderMaterial(shaderDesc);
3541
```
3642

37-
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.
43+
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.
3844

3945
:::note
4046

@@ -48,7 +54,9 @@ Before the shader is used, a preprocessing step is applied, allowing you to mana
4854

4955
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.
5056

51-
### Material Shader Defines {#material-shader-defines}
57+
You can also use a `#include` directive to include one of the registered shader chunks. For example: `#include "screenDepthPS"`
58+
59+
### Material Shader Defines
5260

5361
Shader defines can be set on a per-material basis, allowing dynamic customization of shader behavior. For example:
5462

@@ -207,4 +215,8 @@ And Each created shader will be logged in the browser console, where you can ins
207215

208216
For further information, refer to the [ShaderMaterial API documentation](https://api.playcanvas.com/engine/classes/ShaderMaterial.html).
209217

218+
### Compute shaders
219+
220+
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.
221+
210222
[1]: /user-manual/graphics/physical-rendering/physical-materials/

docs/user-manual/graphics/shaders/migrations.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ The debug version of the Engine will report any API changes to the runtime conso
1515

1616
![Console output](/img/user-manual/graphics/shader-chunk-migrations/console-warning.png)
1717

18-
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:
18+
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:
1919

2020
```javascript
21-
material.chunks.diffusePS = '...';
22-
material.chunks.APIVersion = pc.CHUNKAPI_1_55;
21+
const materialChunksGLSL = material.getShaderChunks(pc.SHADERLANGUAGE_GLSL);
22+
materialChunksGLSL.set('diffusePS', '...');
23+
material.shaderChunksVersion = '2.8';
2324
```
2425

2526
By doing this you will no longer see warning messages in the console.

docs/user-manual/graphics/shaders/wgsl-specifics.md

Lines changed: 270 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,273 @@ title: WGSL Specifics
33
sidebar_position: 2
44
---
55

6-
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.
6+
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.
7+
8+
The following sections outline key aspects of writing WGSL shaders for PlayCanvas.
9+
10+
### Simplified Shader Interface Syntax
11+
12+
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.
13+
14+
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.
15+
16+
#### Example Comparison
17+
18+
Standard WGSL:
19+
20+
```wgsl
21+
struct Uniforms {
22+
uTime: f32,
23+
};
24+
25+
struct FragmentInput {
26+
@location(0) uv0: vec2f,
27+
@builtin(position) position: vec4f
28+
};
29+
30+
@group(0) @binding(0) var<uniform> ub: Uniforms;
31+
32+
@fragment fn fragmentMain(FragmentInput) -> @location(0) vec4f {
33+
// body
34+
}
35+
```
36+
37+
In contrast, the simplified syntax avoids a lot of the boilerplate.
38+
39+
```wgsl
40+
uniform uTime: f32;
41+
varying uv0: vec2f;
42+
43+
@fragment fn fragmentMain(input: FragmentInput) -> FragmentOutput {
44+
// body
45+
}
46+
```
47+
48+
### Attributes
49+
50+
Attributes define per-vertex input data, and can only be used in the vertex shader. They must be declared using the following syntax:
51+
52+
```wgsl
53+
attribute aUv0: vec2f;
54+
```
55+
56+
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.
57+
58+
```wgsl
59+
attribute aUv0: vec2f;
60+
61+
@vertex fn vertexMain(input: VertexInput) -> VertexOutput {
62+
63+
// access it using input passed to the main function
64+
var myUv1 = input.aUv0;
65+
66+
// but also as a global variable (particularly useful inside other functions)
67+
var myUv2 = aUv0;
68+
}
69+
```
70+
71+
As part of the `VertexInput` structure, and also in the global scope, these built-in attributes are automatically available:
72+
73+
```wgsl
74+
vertexIndex: @builtin(vertex_index)
75+
instanceIndex: @builtin(instance_index)
76+
```
77+
78+
The attribute names must match the names specified in the `attributes` property when creating the [ShaderMaterial][1].
79+
80+
### Uniforms
81+
82+
Uniforms are used to pass *numerical resources* from the engine to the shader.
83+
84+
Uniforms are declared using this simplified syntax:
85+
86+
```wgsl
87+
uniform view_position: vec3f;
88+
uniform tints: array<vec3f, 4>;
89+
uniform weights: array<f32, 8>;
90+
```
91+
92+
Internally, uniforms are automatically placed in uniform buffers, and in the shader code are accessed using a `uniform.` prefix:
93+
94+
```wgsl
95+
var pos = uniform.view_position;
96+
var color = uniform.tints[2];
97+
98+
// f32 and vec2<> types used in an array are due to alignment requirements wrapped
99+
// in an aligned structure, and the value is available as its `element` property.
100+
// struct WrappedF32 { @size(16) element: f32 }
101+
var weight = uniform.weights[3].element;
102+
```
103+
104+
The engine automatically sets appropriate uniform values when rendering.
105+
106+
:::note
107+
108+
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.
109+
110+
:::
111+
112+
### Texture Resources
113+
114+
Texture resources are using simplified WGSL syntax, where specifying a `@group` and `@binding` index for each resource has to be omitted.
115+
116+
#### Sampling Textures
117+
118+
In WGSL, textures and samplers are treated as separate objects, unlike in GLSL, where those are combined.
119+
120+
When you want to sample a texture (i.e. retrieve filtered texel values), you must provide a texture object *directly followed* by a sampler.
121+
122+
```wgsl
123+
// 2d texture with a sampler declaration
124+
var diffuseMap: texture_2d<f32>;
125+
var diffuseMapSampler: sampler;
126+
127+
// texture sampling
128+
var texel = textureSample(diffuseMap, diffuseMapSampler, coords);
129+
```
130+
131+
#### Fetching Textures
132+
133+
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.
134+
135+
In such cases, no sampler is required or allowed. For example:
136+
137+
```wlsl
138+
// cubemap texture without a sampler
139+
var noSamplerMap: texture_cube<f32>;
140+
141+
// fetching the texel
142+
let texel = textureLoad(noSamplerMap, coords, mipLevel);
143+
```
144+
145+
#### Unfilterable Textures
146+
147+
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).
148+
149+
Using `uff`, you can explicitly declare an unfilterable-float texture in the shader like this:
150+
151+
```wgsl
152+
// declaration
153+
var colorMap: texture_2d<uff>;
154+
155+
// sampling
156+
let data: vec4f = textureLoad(colorMap, uv, 0);
157+
```
158+
159+
This extension allows the engine to correctly interpret the texture’s sampling capabilities and bind it accordingly.
160+
161+
:::note
162+
163+
Support for `texture_external` is not available yet, and will be added in the future.
164+
165+
:::
166+
167+
### Storage Buffers
168+
169+
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<storage>` 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).
170+
171+
Example of using storage buffer in Vertex Shader:
172+
173+
```wgsl
174+
struct Particle {
175+
position: vec3f,
176+
velocity: vec3f,
177+
}
178+
179+
// particle storage buffer in read-only mode
180+
var<storage, read> particles: array<Particle>;
181+
```
182+
183+
### Varyings
184+
185+
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:
186+
187+
```wgsl
188+
varying texCoord: vec2f;
189+
```
190+
191+
Internally, those are parsed, and stored in `VertexOutput` structure in the vertex shader, as well as in `FragmentInput` structure in the fragment shader.
192+
193+
#### Vertex Shader
194+
195+
As part of the `VertexOutput` structure these built-in variables are automatically available:
196+
197+
```wgsl
198+
position: @builtin(position)
199+
```
200+
201+
Example:
202+
203+
```wgsl
204+
varying texCoord: vec2f;
205+
206+
@vertex fn vertexMain(input: VertexInput) -> VertexOutput {
207+
var output: VertexOutput;
208+
output.position = uniform.matrix_viewProjection * pos;
209+
output.texCoord = vec2f(0.0, 1.0);
210+
return output;
211+
}
212+
```
213+
214+
#### Fragment Shader
215+
216+
As part of the `FragmentInput` structure these built-in variables are automatically available:
217+
218+
```wgsl
219+
position: @builtin(position) // interpolated fragment position
220+
frontFacing: @builtin(front_facing) // front-facing
221+
sampleIndex: builtin(sample_index) // sample index for MSAA
222+
```
223+
224+
These built-ins are also available in the global scope using these names:
225+
226+
```wgsl
227+
pcPosition
228+
pcFrontFacing
229+
pcSampleIndex
230+
```
231+
232+
Example:
233+
234+
```wgsl
235+
varying texCoord: vec2f;
236+
237+
@fragment
238+
fn fragmentMain(input: FragmentInput) -> FragmentOutput {
239+
var output: FragmentOutput;
240+
output.color = vec4f(1.0);
241+
return output;
242+
}
243+
```
244+
245+
### Fragment Shader Outputs
246+
247+
The fragment shader is responsible for producing one or more color outputs, which are written to the render targets (color attachments) of the framebuffer.
248+
249+
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`.
250+
251+
As part of the `FragmentOutput` structure these built-in variables are automatically available:
252+
253+
```wgsl
254+
fragDepth: @builtin(frag_depth)
255+
```
256+
257+
Example:
258+
259+
```wgsl
260+
@fragment fn fragmentMain(input: FragmentInput) -> FragmentOutput {
261+
var output: FragmentOutput;
262+
output.color = vec4f(1.0);
263+
output.color1 = vec4f(0.5);
264+
output.fragDepth = 0.2;
265+
return output;
266+
}
267+
```
268+
269+
:::note
270+
271+
Support for rendering to integer textures (output format other then `vec4f`) is not available yet, and will be added in the future.
272+
273+
:::
274+
275+
[1]: /user-manual/graphics/shaders/

0 commit comments

Comments
 (0)