Skip to content

ShadowNode: Add support for renderer.highPrecision#33246

Merged
sunag merged 2 commits intomrdoob:devfrom
shotamatsuda:feat/highp-shadow-model-matrix
Mar 29, 2026
Merged

ShadowNode: Add support for renderer.highPrecision#33246
sunag merged 2 commits intomrdoob:devfrom
shotamatsuda:feat/highp-shadow-model-matrix

Conversation

@shotamatsuda
Copy link
Copy Markdown
Contributor

@shotamatsuda shotamatsuda commented Mar 26, 2026

Related issue: #30955

Description

This PR multiplies the light shadow matrix and object world matrix on the CPU when renderer.highPrecision is enabled.

This is the shadow maps equivalent of the issue #30955. Shadow maps become unusable at a large distance from the origin (and relatively at a small scale) in WebGPURenderer, because ShadowNode uses world positions multiplied on the GPU. WebGLRenderer has no such issue.

Alternatives

We could use a custom shadow node on the user side, but this is not very feasible because ShadowNode is not a leaf class here.

Doing world origin rebasing would surely solve this precision issue, but the purpose of renderer.highPrecision is to handle such use cases where world origin rebasing is difficult to implement for various reasons, with some performance trade off.

--

Results with a torus knot with a diameter of 1 at 6e6 away from the origin, with renderer.highPrecision enabled for all cases.

r183 PR
Directional Light image image
Spot Light image image

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 26, 2026

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 360.01
85.46
360.01
85.46
+0 B
+0 B
WebGPU 633.56
175.64
633.79
175.73
+236 B
+89 B
WebGPU Nodes 631.68
175.35
631.91
175.44
+236 B
+89 B

🌳 Bundle size after tree-shaking

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

Before After Diff
WebGL 492.21
120.03
492.21
120.03
+0 B
+0 B
WebGPU 705.59
190.53
705.82
190.61
+236 B
+83 B
WebGPU Nodes 654.8
177.78
655.04
177.86
+236 B
+85 B

const shadowPosition = lightShadowMatrix( light ).mul( shadowPositionWorld.add( normalWorld.mul( normalBias ) ) );
let shadowPosition;

if ( ! renderer.highPrecision || builder.material.receivedShadowPositionNode || builder.context.shadowPositionWorld ) {
Copy link
Copy Markdown
Contributor Author

@shotamatsuda shotamatsuda Mar 26, 2026

Choose a reason for hiding this comment

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

Just skipping the high precision path when receivedShadowPositionNode or a context value overrides shadowPositionWorld, though it's not ideal.

@shotamatsuda shotamatsuda marked this pull request as ready for review March 26, 2026 05:46
@sunag sunag added this to the r184 milestone Mar 27, 2026
@sunag sunag merged commit d0d5c36 into mrdoob:dev Mar 29, 2026
15 of 16 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.

2 participants