Skip to content

[WebGPU] Add WGSL shader paths for GUI3D and GPU particles#18460

Open
matthargett wants to merge 11 commits into
BabylonJS:masterfrom
rebeckerspecialties:codex/webgpu-wgsl-gui3d-particles
Open

[WebGPU] Add WGSL shader paths for GUI3D and GPU particles#18460
matthargett wants to merge 11 commits into
BabylonJS:masterfrom
rebeckerspecialties:codex/webgpu-wgsl-gui3d-particles

Conversation

@matthargett
Copy link
Copy Markdown
Contributor

@matthargett matthargett commented May 15, 2026

Summary

This adds WebGPU/WGSL shader paths for Babylon.js features that currently still create GLSL effects under WebGPU:

  • GUI3D fluent materials now load WGSL shaders and pass shaderLanguage: WGSL when running on a WebGPU engine.
  • HandleMaterial selects WGSL under WebGPU.
  • GPUParticleSystem render shaders now have WGSL vertex/fragment shaders and create the render effect with shaderLanguage: WGSL under WebGPU.
  • Focused unit coverage verifies the WebGPU effect creation paths select WGSL.

Why

These paths are visible in browsers through the WebGPU renderer, but runtimes that do not ship a GLSL-to-WGSL fallback need Babylon.js to select native WGSL shader sources. The new paths keep WebGL behavior unchanged and only opt into WGSL for WebGPU engines.

Browser WebGPU impact

This improves browser WebGPU robustness for these Babylon.js-owned paths, but it may not always show up as a visible before/after in browsers. Browser WebGPU builds can often hide this gap because the WebGPU engine has GLSL processing / TWGSL fallback support. These built-in GUI3D and GPU-particle paths should still use native WGSL when the engine is already running WebGPU.

With this change, GUI3D fluent/handle materials and GPUParticleSystem render effects select native WGSL sources under WebGPU. That removes fallback/translation dependency for these paths, keeps WebGL behavior unchanged, and makes browser WebGPU behavior line up better with stricter WebGPU runtimes that only accept WGSL. This does not translate arbitrary user-provided GLSL registered through Effect.ShadersStore / createEffectForParticles; those custom snippets still need WGSL sources or an explicit fallback path.

Native screenshot evidence and current limitation

These screenshots were captured from a BabylonNative WebGPU/wgpu-native macOS ASan+UBSan Playground build using the UMD output from this branch. For the GUI3D run, BabylonNative's local GUI3D shader shim was disabled in the app bundle so the screenshot validates the WGSL sources from this PR.

Important limitation: the BabylonNative screenshot runner marks the GUI3D cases as passing because the pixel delta is below its global 2.5% threshold, but visual inspection shows GUI3D text/icons are still missing. This PR fixes the missing WGSL shader path / readiness failure for the GUI3D materials; it does not yet prove full GUI3D visual parity.

GUI3D SpherePanel, with material surfaces rendered but text still missing:

GUI3D SpherePanel native WebGPU

GPU Particles - Basic Properties - Size:

GPU particles basic size native WebGPU

Validation

  • npm ci (completed; local Node 26 emitted the repo engine warning for >=20.17.0 <23.0.0)
  • npm run build:assets
  • npm run build:source
  • npx eslint packages/dev/core/src/Particles/gpuParticleSystem.ts packages/dev/core/test/unit/Particles/gpuParticleSystemAgeGradients.test.ts packages/dev/gui/src/3D/materials/fluent/fluentMaterial.ts packages/dev/gui/src/3D/materials/fluentBackplate/fluentBackplateMaterial.ts packages/dev/gui/src/3D/materials/handle/handleMaterial.ts packages/dev/gui/test/unit/gui3DWebGPUShaders.test.ts --quiet
  • npx vitest run --project=unit packages/dev/core/test/unit/Particles/gpuParticleSystemAgeGradients.test.ts packages/dev/gui/test/unit/gui3DWebGPUShaders.test.ts packages/dev/core/test/unit/Engines/WebGPU/webgpuShaderProcessorWGSL.test.ts (35 tests passed)
  • npx nx build babylonjs --outputStyle=static
  • npx nx build babylonjs-gui --outputStyle=static
  • git -c core.whitespace=cr-at-eol diff --check

Additional native smoke validation with the built UMD output in a BabylonNative WebGPU/wgpu-native macOS ASan+UBSan Playground build:

  • GUI3D SpherePanel, GUI Slate, and GUI Near Menu pass the current native runner threshold with the local BabylonNative GUI3D shader shim disabled, but text/icons are visibly missing and remain a follow-up issue.
  • GPU Particles - Basic Properties - Size and GPU Particles - Basic Properties - Scale passed after wgpu shader-module validation accepted the new WGSL.
  • GPU Particles - Basic Properties - Color rendered and reached screenshot comparison, but still fails pixel comparison. This is a real render mismatch now, not a shader-language readiness timeout.

Note

This does not attempt to translate arbitrary user-provided GLSL registered through Effect.ShadersStore / createEffectForParticles. Those custom shader snippets still need a WGSL source or an explicit GLSL fallback path.

Effect shader preparation can reject asynchronously before a pipeline context is available. Previously that rejection could be left as a floating promise, which made Native/WebGPU readiness failures show up as a timeout or a swallowed console error instead of a useful JS exception.\n\nRoute the async rejection through the normal compilation-error path, preserve the original stack as the cause, and keep getCompilationError actionable for field diagnostics.
The GUI3D fluent button and backplate paths need real WGSL shader sources when the host engine is WebGPU. Add WGSL sources for FluentButtonMaterial, load them through extraInitializationsAsync, and replace the placeholder FluentBackplate WGSL with the full shader port.\n\nThis removes the need for Native validation to force GUI3D effects onto ad hoc WGSL shims and lets browser WebGPU and NativeWebGPU exercise the same BabylonJS material path.
MeshDebugPluginMaterial advertised WGSL compatibility, but several WGSL snippets still used GLSL syntax or interpolation semantics: float declarations, ternary expressions, unqualified uniforms, single-line discard, and missing flat varyings.\n\nPort those snippets to valid WGSL and restore flat interpolation for per-primitive debug data so the WebGPU screenshot renders the intended triangle/vertex overlay instead of timing out or producing a mostly black mesh.
@Popov72
Copy link
Copy Markdown
Contributor

Popov72 commented May 16, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 16, 2026

Please make sure to label your PR with "bug", "new feature" or "breaking change" label(s).
To prevent this PR from going to the changelog marked it with the "skip changelog" label.

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 16, 2026

Snapshot stored with reference name:
refs/pull/18460/merge

Test environment:
https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/18460/merge/index.html

To test a playground add it to the URL, for example:

https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/18460/merge/index.html#WGZLGJ#4600

Links to test your changes to core in the published versions of the Babylon tools (does not contain changes you made to the tools themselves):

https://playground.babylonjs.com/?snapshot=refs/pull/18460/merge
https://sandbox.babylonjs.com/?snapshot=refs/pull/18460/merge
https://gui.babylonjs.com/?snapshot=refs/pull/18460/merge
https://nme.babylonjs.com/?snapshot=refs/pull/18460/merge

To test the snapshot in the playground with a playground ID add it after the snapshot query string:

https://playground.babylonjs.com/?snapshot=refs/pull/18460/merge#BCU1XR#0

If you made changes to the sandbox or playground in this PR, additional comments will be generated soon containing links to the dev versions of those tools.

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 16, 2026

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 16, 2026

🟢 Memory Leak Test Results

13 passed, 0 leaked out of 13 scenarios

🟢 All memory leak tests passed — no leaks detected.

Passed Scenarios (13)
Scenario Package
Core Feature Stack @babylonjs/core
Core Rendering Materials Shadows Stack @babylonjs/core
Core Textures Render Targets PostProcess Stack @babylonjs/core
GUI Fullscreen UI Controls @babylonjs/gui
GUI Mesh ADT Controls @babylonjs/gui
Loaders Boombox Import @babylonjs/loaders
Loaders OBJ Direct Load @babylonjs/loaders
Loaders STL Direct Load @babylonjs/loaders
Materials Library Stack @babylonjs/materials
Serializers glTF Export @babylonjs/serializers
Serializers GLB Export @babylonjs/serializers
PostProcesses Digital Rain Stack @babylonjs/post-processes
Procedural Textures Stack @babylonjs/procedural-textures

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 16, 2026

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 16, 2026

⚡ Performance Test Results

🟢 All performance tests passed — no regressions detected.

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 16, 2026

Visualization tests for WebGPU

https://snapshots-cvgtc2eugrd3cgfd.z01.azurefd.net/refs/pull/18460/merge/testResults/webgpuplaywright/index.html

@matthargett
Copy link
Copy Markdown
Contributor Author

Looks like there's failures that I didn't see locally due to WebGPU implementation differences. I'm on it :)

Use textureSampleLevel for GPU particle color-gradient lookups in the WGSL vertex shader so WebGPU validation does not reject implicit-derivative sampling in the vertex stage.

Also fills the TSDoc comments and parameter docs required by the TypeDoc CI gate for the WebGPU/GU3D APIs touched by this PR.
@matthargett
Copy link
Copy Markdown
Contributor Author

Ran the CI pipeline locally where I have Chrome Canary and Edge Dev installed.

Key pass signals:
GPU particles: 57 passed, including the CI-failing color-gradient cases.
CPU particles: 57 passed.
Shader-heavy/WebGPU readiness set: 23 passed.
Material/refraction/node-material set: 22 passed.
GUI/GUI3D focused set: passed except one FrameGraph gui bloom screenshot flake that passed 5/5 on repeat.
GUI gradient linear/radial/transparency tests passed in the broad shard.
Thin instance and motion blur coverage in shard 2 passed.

New things worth watching:

  • Clustered Lighting (lhs pbr material) hit one WebGPU bind-group/material-context runtime failure: missing tileMaskTexture0 / tileMaskTexture0Sampler. It did not reproduce in direct repeats or grouped reruns, so this looks order-sensitive or flaky.

@matthargett matthargett marked this pull request as ready for review May 16, 2026 23:22
Copilot AI review requested due to automatic review settings May 16, 2026 23:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds native WGSL shader paths for WebGPU execution in GUI3D fluent/handle materials and GPU particle rendering, plus related effect error handling and focused unit coverage.

Changes:

  • Adds WGSL shader sources for GUI3D fluent, fluent button, fluent backplate, handle, and GPU particle render shaders.
  • Updates material/particle effect creation to select ShaderLanguage.WGSL under WebGPU and import WGSL shader modules asynchronously.
  • Adds unit coverage for selected GUI3D and GPU particle WebGPU effect creation paths, and fixes WGSL snippets in mesh debug plugin material.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/dev/gui/test/unit/gui3DWebGPUShaders.test.ts Adds GUI3D material WebGPU shader-language tests.
packages/dev/gui/src/3D/materials/handle/wgsl/handle.vertex.fx Adds HandleMaterial WGSL vertex shader.
packages/dev/gui/src/3D/materials/handle/wgsl/handle.fragment.fx Adds HandleMaterial WGSL fragment shader.
packages/dev/gui/src/3D/materials/handle/handleMaterial.ts Selects WGSL shader language for HandleMaterial on WebGPU.
packages/dev/gui/src/3D/materials/fluentButton/wgsl/fluentButton.vertex.fx Adds FluentButtonMaterial WGSL vertex shader.
packages/dev/gui/src/3D/materials/fluentButton/wgsl/fluentButton.fragment.fx Adds FluentButtonMaterial WGSL fragment shader.
packages/dev/gui/src/3D/materials/fluentButton/fluentButtonMaterial.ts Passes shader language and WGSL initialization for FluentButtonMaterial effects.
packages/dev/gui/src/3D/materials/fluentBackplate/wgsl/fluentBackplate.vertex.fx Adds FluentBackplateMaterial WGSL vertex shader.
packages/dev/gui/src/3D/materials/fluentBackplate/wgsl/fluentBackplate.fragment.fx Adds FluentBackplateMaterial WGSL fragment shader.
packages/dev/gui/src/3D/materials/fluentBackplate/fluentBackplateMaterial.ts Passes shader language and WGSL initialization for FluentBackplateMaterial effects.
packages/dev/gui/src/3D/materials/fluent/wgsl/fluent.vertex.fx Adds FluentMaterial WGSL vertex shader.
packages/dev/gui/src/3D/materials/fluent/wgsl/fluent.fragment.fx Adds FluentMaterial WGSL fragment shader.
packages/dev/gui/src/3D/materials/fluent/fluentMaterial.ts Passes shader language and WGSL initialization for FluentMaterial effects.
packages/dev/core/test/unit/Particles/gpuParticleSystemAgeGradients.test.ts Adds GPU particle WebGPU render shader-language test.
packages/dev/core/src/ShadersWGSL/gpuRenderParticles.vertex.fx Adds GPU particle render WGSL vertex shader.
packages/dev/core/src/ShadersWGSL/gpuRenderParticles.fragment.fx Adds GPU particle render WGSL fragment shader.
packages/dev/core/src/Particles/gpuParticleSystem.ts Selects WGSL render shaders for GPU particles under WebGPU.
packages/dev/core/src/Materials/meshDebugPluginMaterial.ts Fixes WGSL syntax/interpolation in mesh debug plugin snippets.
packages/dev/core/src/Materials/effect.ts Reports async shader preparation failures through effect compilation error handling.

Comment on lines +155 to +160
fn lineVertex(uv: vec2f, rate: f32, highlightTransform: vec4f) -> vec3f {
let angle2: f32 = rate * 2.0 * 3.1416;
let sinAngle2: f32 = sin(angle2);
let cosAngle2: f32 = cos(angle2);
let xformUV: vec2f = uv * highlightTransform.xy + highlightTransform.zw;
return vec3f(0.0, cosAngle2 * xformUV.x - sinAngle2 * xformUV.y, 0.0);
Comment on lines +451 to +456
shaderLanguage: this._shaderLanguage,
extraInitializationsAsync: this._shadersLoaded
? undefined
: async () => {
if (this.shaderLanguage === ShaderLanguage.WGSL) {
await Promise.all([import("./wgsl/fluentButton.vertex"), import("./wgsl/fluentButton.fragment")]);
Preserve the WGSL line-highlight timing parameter so native WebGPU uses the same disabled highlight state as the GLSL shader.

This keeps the GUI3D slate shader correction in the existing GUI3D/WebGPU PR without bundling the separate font metric fallback.
@matthargett matthargett force-pushed the codex/webgpu-wgsl-gui3d-particles branch from 80c829a to 697d3b5 Compare May 17, 2026 02:37
@RaananW
Copy link
Copy Markdown
Member

RaananW commented May 17, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 17, 2026

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 17, 2026

🟢 Memory Leak Test Results

13 passed, 0 leaked out of 13 scenarios

🟢 All memory leak tests passed — no leaks detected.

Passed Scenarios (13)
Scenario Package
Core Feature Stack @babylonjs/core
Core Rendering Materials Shadows Stack @babylonjs/core
Core Textures Render Targets PostProcess Stack @babylonjs/core
GUI Fullscreen UI Controls @babylonjs/gui
GUI Mesh ADT Controls @babylonjs/gui
Loaders Boombox Import @babylonjs/loaders
Loaders OBJ Direct Load @babylonjs/loaders
Loaders STL Direct Load @babylonjs/loaders
Materials Library Stack @babylonjs/materials
Serializers glTF Export @babylonjs/serializers
Serializers GLB Export @babylonjs/serializers
PostProcesses Digital Rain Stack @babylonjs/post-processes
Procedural Textures Stack @babylonjs/procedural-textures

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 17, 2026

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 17, 2026

@bjsplat
Copy link
Copy Markdown
Collaborator

bjsplat commented May 17, 2026

⚡ Performance Test Results

🟢 All performance tests passed — no regressions detected.

@matthargett
Copy link
Copy Markdown
Contributor Author

sorry for the thrash, I'm going through all the screenshot tests semi-manually on multiple devices (M4 Mac, iPhone XS, Apple Watch SE2) and tightening up differences. there's actually a number of these tests that should be failing in BabylonNative's bgfx backend already due to differences with browser render, but the pixel match threshold is so wide that they've been missed. I'm just focused on WebGPU for right now, but I'll file issues for the WebGL differences as well in case they're important enough for others to follow up on.

@RaananW
Copy link
Copy Markdown
Member

RaananW commented May 18, 2026

Moving all active PRs to draft for the next 24 to 48 hours.
This is due to the tree-shaking PR #18441 being merged later today.

@RaananW RaananW marked this pull request as draft May 18, 2026 08:39
@RaananW
Copy link
Copy Markdown
Member

RaananW commented May 18, 2026

Please make sure to merge from master. Apologies for the many merge conflicts. please make sure to put the code in the right place

@RaananW RaananW marked this pull request as ready for review May 18, 2026 16:35
@matthargett
Copy link
Copy Markdown
Contributor Author

Merged latest master (9.9.1) into the branch and reconciled the WebGPU changes into the tree-shaken .pure.ts files.

Local validation with the reconciled 18460 + 18463 patches:

  • Focused unit tests passed: gpuParticleSystemAgeGradients, gui3DWebGPUShaders, engine.common.
  • nx build babylonjs and nx build babylonjs-gui passed at 9.9.1.
  • BabylonNative NativeWebGPU focused screenshots passed for GUI3D SpherePanel, GUI Slate, GUI Near Menu, MeshDebugPluginMaterial, GPU Particles - Noise, Lighting Volume, GLTF Texture Linear Interpolation, Fluid rendering particle system, and Texture Repetition Standard/PBR.

Fresh PR checks currently show GitGuardian passing, with Azure/Mergify entries neutral/skipping rather than failing.

@Popov72
Copy link
Copy Markdown
Contributor

Popov72 commented May 22, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants