Hey there!
I have been trying to use SSS inside a NodeMaterial with clustered lights but unfortunately the shader does not compile:
I think that might be a bug, or maybe there I missed a step to make it work ?
Thanks for the repro!
I found and fixed the Node Material compile issue when subsurface scattering is used together with clustered lights. The root cause was shader generation order: the clustered-light helper could be emitted before the subsurface-scattering declarations it depends on.
The fix is in this PR:
master ← Popov72:fix/nodematerial-sss-clustered-lights-clean
opened 11:44AM - 03 May 26 UTC
> 🤖 *This PR was created by the create-pr skill.*
## Summary
- Fix NodeMaterial… PBR shader generation so subsurface-scattering declarations are emitted before clustered-light helper functions.
- Prepare and bind clustered-light tile-mask resources according to the effect shader language, keeping WebGPU WGSL effects on the storage-buffer path.
- Bind a default empty texture for WebGPU `TextureBlock`s that declare texture resources but have no texture assigned, preventing bind group creation failures.
- Propagate material shader language through materials-library clustered-light preparation.
## Motivation
The forum repro at https://forum.babylonjs.com/t/nodematerial-compile-error-when-using-sub-surface-scattering-with-clustered-lights/63299 failed with NodeMaterial subsurface scattering and clustered lights.
For the WebGPU playground repro (`#CSCJO2#97`), the NodeMaterial snippet must be loaded as WGSL, for example by passing `{ shaderLanguage: BABYLON.ShaderLanguage.WGSL }` to `NodeMaterial.ParseFromSnippetAsync`. This preserves the WebGPU clustered-light fast path (`tileMaskBuffer`, batch size 32) instead of adding a slower GLSL texture fallback.
## Validation
- Added unit coverage for NodeMaterial SSS clustered-light shader ordering.
- Added unit coverage for clustered-light tile-mask sampler/buffer selection.
- Added unit coverage for WebGPU default texture binding for missing `TextureBlock` resources.
- Verified the WebGPU playground repro locally with the snippet loaded as WGSL, clustered lights using `tileMaskBuffer`, and WebGPU batch size remaining 32.
For the WebGPU version of the repro, make sure the Node Material snippet is loaded as WGSL, for example:
const material = await BABYLON.NodeMaterial.ParseFromSnippetAsync(
"EPY8BV#619",
scene,
"",
undefined,
false,
false,
undefined,
{ shaderLanguage: BABYLON.ShaderLanguage.WGSL }
);
That keeps WebGPU on the clustered-light storage-buffer path instead of using the GLSL fallback path. The PR also fixes the WebGPU binding issue caused by texture blocks that declare texture resources but do not have textures assigned.
Thanks a lot for the fix! Can’t wait to try it