DrawWrapper for shadow map?

Hi @Evgeni_Popov,

This is a follow up issue I am facing from what you helped me (Dynamic size of instance count). I notice each render pass has a draw wrapper. I was able to setup 2 cameras, and sync the instance count in indirect draw buffer for these 2 camera views.

Now I am having problem with the shadow mapping. I am able to access the indirect draw buffer of the light shadow map render pass, and bind it to the compute shader. However, it seems there is no effect of setting the instance count on the indirect draw buffer of light shadow map.

Even if I hardcode the instance count to 1, the shadow is still generated for all the visible instances. It somehow is able to get the most of shadows right. But as the view center moves or rotates, there are some shadows left over on areas that don’t have instances. Is there something special about shadow mapping?

But I am not able to reproduce this issue in this PG: https://playground.babylonjs.com/?webgpu#SLP3YY#43. You can see I can set shadow instance count = sphere instance count - 1.

I don’t know why the instance count or the instance positions are out of sync for my meshes and their shadows. Is it possible that I use GLSL for shadowDepthwrapper, and I mapped struct in WGSL to a VertexBuffer and sets position attributes as following:

    const meshPositionVBuffer = new VertexBuffer(
    mesh.setVerticesBuffer(meshPositionVBuffer, false);

Would this be the problem?

It’s hard to say, as it works as expected in the PG…

Are you sure you’re updating the number of instances correctly in the compute shader for the shadow mapping case?

Using PIX would probably help in your case. See the last sentence of [this answer] (Compute Shaders Order Execution - #3 by Evgeni_Popov) for quick instructions on how to install it.


I used PIX, and the situation as I’m able to understand it at this moment is like so:

We set a maximum amount for the number of instanced entities that can be rendered, this corresponds to the size of either a storage buffer or position vertex attribute buffer that we use to store position info.
Lets say that at max capacity, this buffer holds the corresponding position info for 1000 unique entities.

We dynamically set the number of instanced entities being drawn on a per frame basis controlled through an indirect draw buffer; this number of instances is what is passed to an indirect draw call being made in the render pass with the webGPU engine.

When we use a shadow depth wrapper for the ShaderMaterial that belongs to the mesh of our instanced entities, the amount of shadow instances being passed to the indirect draw call of rendering shadows is always the maximum amount; 1000. I confirmed this with PIX. This is despite us setting the number of shadow instances through the indirect draw buffer used as the light source of the shadows. We update the value of both indirect draw buffers (instanced entities and shadows) at the same time and place in our code.

One thing that we do that may be breaking things is the fact that we create a new shader material written in glsl to be used as the base material for the shadow wrapper. We do this because the shadow wrapper throws an error when try to use our meshes shader material written in wgsl as the base material of the shadow wrapper. This works correctly as providing the right locations for the shadows. Again the problem is that the number of shadow instances does not seem to be affected by the number of instances specified in the indirect draw buffer of the light source.

Any advice here would be greatly appreciated. Thanks!

If you don’t see the right value in the indirect draw buffer, it could be because you don’t update the right one: are you sure you retrieve the right draw wrapper for the shadow map pass? Also, do you use the standard shadow generator and not the CSM?

By the way, I missed it in your code, it’s better to retrieve the render pass ids this way than to use the pass names:

const drawWrapperLight = submesh._getDrawWrapper(shadowGenerator.getShadowMap().renderPassId, false);
const drawWrapper = submesh._getDrawWrapper(camera.renderPassId, false);

It would really help if you could provide a repro somewhere.

1 Like

Nice, thank you, we’ll make that switch.

are you sure you retrieve the right draw wrapper for the shadow map pass?

Yeah, pretty sure anyways. Using your method to retrieve the render pass id still results in the same value, 2, in our setup.

Also, do you use the standard shadow generator and not the CSM?

Just the standard shadow generator:

// entity.material is a ShaderMaterial we create with our own vertex and fragment wgsl programs
// shadowMaterial is another ShaderMaterial we create with some skeleton vertex and fragment glsl programs
entity.material.shadowDepthWrapper = new ShadowDepthWrapper(
                standalone: true,
            } as IIOptionShadowDepthMaterial

I’ll work on getting a representative pg set up soon.

Hi @Evgeni_Popov

I am able to reproduce the issue in a PG: https://playground.babylonjs.com/?webgpu#SLP3YY#52

It is broken after adding ShadowDepthWrapper. It seems the shadow map render pass no longer uses indirect draw buffer after using ShadowDepthWrapper. You can see the code doesn’t go into the if branch any more because drawWrapperLight?.drawContext?.indirectDrawBuffer is undefined.

if (drawWrapper?.drawContext?.indirectDrawBuffer && drawWrapperLight?.drawContext?.indirectDrawBuffer && !engine.compatibilityMode)
1 Like

Thanks for the repro!

The shadow depth wrapper class manages the draw wrappers of the sub meshes itself, so the one from submesh._drawWrappers is not used.

You can retrieve the drawWrapper by calling ShadowDepthWrapper.getEffect (misnamed because of backwards compatibility issues):


Thanks @Evgeni_Popov. It fixed the shadow problem!

1 Like

Thank you for pointing that out!