Skip to content

Renderer: Shadow map improvements.#32705

Merged
Mugen87 merged 5 commits intomrdoob:devfrom
Mugen87:dev4
Jan 11, 2026
Merged

Renderer: Shadow map improvements.#32705
Mugen87 merged 5 commits intomrdoob:devfrom
Mugen87:dev4

Conversation

@Mugen87
Copy link
Collaborator

@Mugen87 Mugen87 commented Jan 10, 2026

Fixed #32698.

Description

After reviewing the shadow code base and an in-depth WebGL state comparison between the reproduction test cases from #32698, I'm confident to change the following:

  • In WebGPURenderer, the shadow side wasn't configured correctly which was the main reasons for the extreme shadow acne.
  • In WebGLRenderer, vogelDiskSample() was redundantly called in the point light code path. The sample values are now computed once and shared like in WebGPURenderer which improves performance.
  • In WebGPURenderer, the depth textures for PCF (Soft) shadows must use LinearFilter. This noticeably improves shadow quality which you can see in the SSS demo.
  • In WebGPURenderer, blending should be disabled when rendering shadows (similar to WebGLRenderer). This improves performance a bit.
  • In WebGPURenderer, the precision for all shadow samplers should be highp for consistency with WebGLRenderer.
  • In WebGPURenderer, the compare function LessEqual is now used to match WebGLRenderer.
  • In WebGPURenderer, the point light shadow code can be significantly simplified.

@github-actions
Copy link

github-actions bot commented Jan 10, 2026

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 355.36
84.47
355.41
84.51
+52 B
+38 B
WebGPU 621.1
172.47
621.08
172.51
-20 B
+43 B
WebGPU Nodes 619.71
172.23
619.69
172.28
-20 B
+48 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 487.31
119.25
487.36
119.29
+52 B
+37 B
WebGPU 692.34
187.8
692.25
187.78
-86 B
-20 B
WebGPU Nodes 642.14
175.03
642.05
174.97
-86 B
-57 B

@Mugen87 Mugen87 added this to the r183 milestone Jan 10, 2026

// dp = normalized distance from light to fragment position
const dp = lightToPositionLength.sub( cameraNearLocal ).div( cameraFarLocal.sub( cameraNearLocal ) ).toVar(); // need to clamp?
const dp = viewZToPerspectiveDepth( viewZ.negate(), shadowCameraNear, shadowCameraFar );
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think the usage of viewZToPerspectiveDepth() makes much more clear what's going on in this function.


overrideMaterial.side = ( material.shadowSide !== null ) ? material.shadowSide : _shadowSide[ material.side ];

}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This block here is the most important fix. It eliminates the shadow acne that has been reported over months, including #32698.

@Mugen87
Copy link
Collaborator Author

Mugen87 commented Jan 10, 2026

With this change, many WebGPU demos using shadows don't need a shadow bias anymore. When this is merged, I'll go trough all of them and remove the bias if possible.

@Mugen87 Mugen87 merged commit 49fef39 into mrdoob:dev Jan 11, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Severe shadow artifacts in WebGPURenderer compared to WebGLRenderer

1 participant