Mesh invisible and WebGl warn when clustered lights and directional light (whitelist mode) on

Hi everyone,

Super mean bug here. I have not figured out yet how to reproduce. So I can only the describe and hope. In sum, I cannot have shadows and clustered lighting. More specifically, the bug throws a WebGL warning

[.WebGL-0x47fc04470d00] GL_INVALID_OPERATION: glDrawElements: It is undefined behaviour to use a uniform buffer that is too small.

and leaves the one affected mesh “B” invisible (it is there in the Inspector).

Here are the prerequisites

  • Clustered Lights activated: there must be PointLIghts in the container. They must have certain properties. Cannot replicate with arbitrary numbers. There is no NaN or undefines.
  • 1 DirectionalLight with: Dir: 0.5, -0.5, 0.5 and Pos: -31.999999847888077, 32, -41. A zeroed-out light will not trigger the bug.
  • Have mesh A and B
  • Add both meshes to the DirectionalLight’s “includedOnlyMeshes” list. Leaving out mesh A will not trigger the bug.
  • Other unknown requirements :frowning:

To trigger it, I can start the render loop or render mesh B directly.

For what it is worth, here is my test code:

  const mesh = scene.getMeshByName("LevelMegaTerrain");

  await mesh.material.forceCompilationAsync(mesh); //just trying

  console.log( mesh.isReady(true) ); //true
  console.log( mesh.material.isFrozen ); //false
  console.log( mesh.material.isReady(mesh, false) ); //true
  console.log( mesh.material.isReadyForSubMesh(mesh, mesh.subMeshes[0], false) ); //true

  mesh.directRender(); //will break it (so will starting the render loop)

If I dispose the DirectionalLight, fixes it
If I dispose the ClusteredLights container, bug remains.
If I dispose mesh A, bug remains.
Replacing material, bug remains.

Any tips welcome. I am stuck :slightly_frowning_face:

Best wishes
Joe


For own reference : Babylon.js Playground

ping @Evgeni_Popov

1 Like

Can you run a test in WebGPU? The error message (if any) could provide additional information about the issue. Of course, a repro would be ideal, as it seems that a number of fairly specific conditions are required to reproduce the bug.

1 Like

Oh, here we go. Nice trick, thanks Evgeni_Popov :slightly_smiling_face:

Texture “lightDataTexture0” not found in the material context. Make sure you bound it (something like effect.setTexture(“lightDataTexture0”, texture)). entry={“binding”:0,“visibility”:2,“texture”:{“sampleType”:“float”,“viewDimension”:“2d”,“multisampled”:false}}, materialContext={“useVertexPulling”:false,“uniqueId”:706,“updateId”:5,“textureState”:0,“samplers”:{“reflectionSamplerSampler”:{“sampler”:“”,“hashCode”:151655},“environmentBrdfSamplerSampler”:{“sampler”:“”,“hashCode”:135395}},“textures”:{“reflectionSampler”:{“texture”:“”,“isFloatOrDepthTexture”:false,“isExternalTexture”:false},“environmentBrdfSampler”:{“texture”:“”,“isFloatOrDepthTexture”:false,“isExternalTexture”:false},“lightDataTexture1”:{“texture”:“”,“isFloatOrDepthTexture”:true,“isExternalTexture”:false}},“isDirty”:false,“_numFloatOrDepthTextures”:1,“_numExternalTextures”:0}


Can’t find buffer “tileMaskBuffer0” in the draw context. Make sure you bound it. entry={“binding”:9,“visibility”:2,“buffer”:{“type”:“read-only-storage”}}, buffers={“Mesh”:{“references”:1,“capacity”:80,“is32Bits”:false,“uniqueId”:4183,“engineId”:0,“_buffer”:{}},“Light0”:{“references”:1,“capacity”:80,“is32Bits”:false,“uniqueId”:4424,“engineId”:0,“_buffer”:{}},“tileMaskBuffer1”:{“references”:1,“capacity”:16384,“is32Bits”:false,“uniqueId”:4767,“engineId”:0,“_buffer”:{}},“Light1”:{“references”:1,“capacity”:352,“is32Bits”:false,“uniqueId”:4761,“engineId”:0,“_buffer”:{}},“Scene”:{“references”:1,“capacity”:208,“is32Bits”:false,“uniqueId”:5140,“engineId”:0,“_buffer”:{}},“Internals”:{“references”:1,“capacity”:8,“is32Bits”:false,“uniqueId”:2,“engineId”:0,“_buffer”:{}},“LeftOver”:{“references”:1,“capacity”:2960,“is32Bits”:false,“uniqueId”:4789,“engineId”:0,“_buffer”:{}}}, drawContext.uniqueId=715


Failed to execute ‘createBindGroup’ on ‘GPUDevice’: Failed to read the ‘entries’ property from ‘GPUBindGroupDescriptor’: Failed to read the ‘resource’ property from ‘GPUBindGroupEntry’: Required member is undefined.

I think you are using a node material? To make it work in WebGPU with clustered lights, you must set the shader language to WGSL, see (2nd paragraph):

2 Likes

I am afraid not. The problem mesh itself has a PBRMaterial instance. I do have NodeMaterials, disabled them, but still got the crash.


The crash happens when rendering mesh "B"². webgpuCacheBindGroups; source reproduced below.

²Mesh.render() → Mesh._draw() → engine.drawElementsType() → engine._draw() → engine._cacheBindGroups.getBindGroups()

The console.logs (else-branch, lower half of screenshot) look as follow:

It seems it wants lightTexture1 but only got lightTexture2. To put this into perspective: I have switched back to the full production setup. There is now (in order of creation):

  • 1 DirectionalLight for dynamic shadows (character meshes are on whitelist)
  • 1 DirectionalLight for static shadows (problem meshes A and B are on whitelist)
  • 1 ClusteredLightContainer with 9 lights (unrestricted)
  • 1 ShadowGenerator per DirectionalLight
  • 1 PointLight (unrestricted)

Now, if I turn off ClusteredLights…

…I get for

  • entryInfo: shadowTexture0, shadowTexture1, albedoSampler, reflectionSampler, environmentBrdfSampler, bumpSampler,… repeats: shadowTexture1, albedoSampler…

as well as for each entry

  • materialContext: albedoSampler, bumpSampler, environmentSampler, reflectionSampler, shadowTexture0, shadowTexture1

No lightTextures? Now with WebGPU still on, I do get 2 new warnings (identical):

WebGPU uncaptured error (1): [object GPUValidationError] - Destroyed texture [Texture “D3DImageBacking_D3DSharedImage_WebGPUSwapBufferProvider_Pid:9284”] used in a submit. While calling [Queue].Submit([[CommandBuffer from CommandEncoder “upload”], [CommandBuffer from CommandEncoder “render”]])

The staticLight stopped working too. Changing any of the settings has no visual effect. Disposing the staticLight crashes the renderer.

N.B. If I switch to WebGL, with ClusteredLights still off, everything ok.

Without reproduction (even an external link), it will be difficult to investigate… I don’t understand why the bind group expects to transmit the light data texture via “lightDataTexture1” when the material context refers to it as “lightDataTexture2”… I tried to reproduce this situation, but without success.

1 Like

I think I have just found one way. Technically, in my local project, the bug does happen earlier before I run the code I have replicated. But the error is the same. So I am just hoping it is the same cause somehow.

So anyway, here is the playground: https://playground.babylonjs.com/#WLDCUC#267

N.B. use case. Obviously this is all nonesense code. But the “makeItCrashAlready” function minimally replicates a warmup phase in my actual code. There, I basically enable everything, render the scene, and then bring it back to the previous state. This is to counteract startup lag.

Good news: this PR (done because of Crash when disposing light (ClusteredLights need to be present)) fixes the problem in your PG!

1 Like

No way, cool :smiley: Thanks Evgeni_Popov!

Sorry, for not using it earlier. I thought it is not related due to the disposing thing. And it says it right there in the PR how you can easily test it on any playground! https://playground.babylonjs.com/?snapshot=refs/pull/17206/merge#WLDCUC#267