-
-
Notifications
You must be signed in to change notification settings - Fork 35.8k
WebGPURenderer: Introduce Shadow Map Array #30830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WebGPURenderer: Introduce Shadow Map Array #30830
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
@sunag I also added Frustum support for ArrayCamera via a new FrustumArray class. I’ve tested everything on both backends (Windows and macOS), and it all looks good so far. I’ll move on to finishing VSM shadows in TileShadow, depending on your feedback, just want to avoid working on something that might get changed if you’re planning to work some magic on the TileShadow node side. Would be awesome if you could take a look at the node when you get a chance! 🙇 |
This would probably be a PR. Since this is about shadows, and I've been on the subject recently, I'm just asking. |
It seems that the background with Cubemap without PMREM broke |
I tried to help with some details, the PR is amazing, it will certainly be very useful <3 |
Overall the PR should be good now. I wanted to throw an error when using const shadowMapType = builder.renderer.shadowMap.type;
if ( shadowMapType === VSMShadowMap ) {
throw new Error( 'TileShadowNode: VSMShadowMap is not supported.' );
} because the renderer is only accessible when the node gets build, not when instancing, resulting in Also it feels too much like an edge case to pollute the code of Would it be ok to just add a comment somewhere or ignore that case? /cc @sunag @Mugen87 |
I think you can mention the edge case in the JSDoc for |
Is the TileShadowNodeHelper automatically rendered outside of the postProcessing pipeline or does that have to be configured via MRT. |
The |
).mul( 1 / 17 ); | ||
|
||
} ); | ||
export const getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RenaudRohlinger Would it be possible to refactor getShadowRenderObjectFunction()
so it does not return a new function object on every invocation? updateShadow()
is called per frame per shadow casting light so this might affect GC overhead.
By combining
RenderBundle
,ArrayCamera
,RenderTargetArray
, and a newDepthArrayTexture
andFrustumArray
, this PR opens the door to rendering multiple shadow passes in a single, highly performant render.I’ve added a new example along with a

TileShadowNode
to demonstrate a foundational use case that takes advantage of this feature. In the example, the scene is divided into four sections, enabling a 16K resolution shadow map at nearly the same cost as 8K. This technique bypasses the 8K resolution limit, improves performance, and avoids the 16-sampler bind limit.Looking ahead, it would be great to update nodes like CSM to leverage this new feature, especially since CSM already uses multiple FBOs at the same resolution, making it a perfect match. We could even implement a Tiled CSM system for open-world scenes, now that we can scale up to a 2048 shadow map limit per program.
TODO:
ArrayCamera
in the Renderer -> IntroduceFrustumArray
[] Support VSM Shadows in TileShadow@sunag Feedbacks and help on the node part would be greatly appreciated!
This contribution is funded by Renaud Rohlinger @ Utsubo