Skip to content

PMREMGenerator: Replace separable blur with spiral blur on both renderers - #32367

Merged
mrdoob merged 8 commits into
devfrom
pmrem
Jul 8, 2026
Merged

PMREMGenerator: Replace separable blur with spiral blur on both renderers#32367
mrdoob merged 8 commits into
devfrom
pmrem

Conversation

@mrdoob

@mrdoob mrdoob commented Nov 25, 2025

Copy link
Copy Markdown
Owner

Description

This PR replaces the separable blur (latitudinal/longitudinal) in PMREMGenerator with a spiral kernel that importance-samples the Gaussian, ports the same approach to the WebGPU PMREMGenerator so both renderers produce matching output, and optimizes the internal vertex shader.

Changes

  • Spiral Blur: Golden Angle spiral kernel, isotropic on the sphere. Replaces the latitudinal/longitudinal approximation, which was "least accurate at the poles" by its own admission and needed a poleAxis special case.
  • Importance Sampling: Samples are placed by stratified inverse-CDF sampling of the Gaussian, so every sample carries equal weight (~2x the effective sample count of a weighted kernel at the same cost). A sin(theta) / theta term corrects planar sample density to solid angle.
  • Split Sigma: _blur performs two passes at sigma / sqrt(2), composing to the requested sigma while squaring the effective sample count.
  • Robustness: The kernel truncates at three standard deviations or the antipode, and sigma is clamped to PI. Large sigmas now produce the requested blur; the previous kernel was capped at 20 pixels of reach and silently under-blurred beyond sigma ≈ 0.04 at 256 (e.g. sigma = 1.0 produced only ~0.12 radians of blur).
  • WebGPU: The PMREMGenerator of WebGPURenderer received the same port (TSL blur in PMREMUtils.js plus the baked outputDirection attribute), removing the last divergence between the two generators for fromScene().
  • PMREMUtils: The internal blur function is renamed to sphericalGaussianBlur (with new parameters). Nothing is added to the TSL namespace (PMREMUtils is no longer exported there since TSL: Do not export PMREMUtils #33986).
  • Shader Optimization: The outputDirection attribute is precomputed in JavaScript, removing the faceIndex attribute and the branching getDirection logic from the vertex shader, plus the now-unused uv attribute.
  • Cleanup: Removed poleAxis, the CPU Gaussian weight table, dTheta, the vestigial sigmas array and EXTRA_LOD_SIGMA. Blur uniforms reduced from 7 to 3. GGX_SAMPLES aligned to 256 on both renderers (was 512 on WebGPU; 0.03% of pixels differ, halves the prefilter cost).

Verification

  • fromScene( new RoomEnvironment(), 0.04 ) is pixel-equivalent to dev on both renderers (mean diff 0.7/255, under 0.4% of pixels above 5/255).
  • WebGPURenderer and WebGLRenderer now agree on fromScene() output (0.04% of pixels differ at sigma = 0.04); WGSL and GLSL node backends match at 0.01%.
  • The equirectangular path through the reworked vertex attribute is pixel-identical (0.01%).
  • Total fromScene() time is unchanged (sub-millisecond either way; the blur does 40 texture taps per pixel vs 78 before).
  • sigma = 0 and sigma = Infinity degrade gracefully (copy and near-uniform blur respectively).

(Made using https://jules.google/, https://antigravity.google/ and Claude Code)

@mrdoob mrdoob added this to the r182 milestone Nov 25, 2025
Comment thread src/extras/PMREMGenerator.js Fixed
@github-actions

github-actions Bot commented Nov 25, 2025

Copy link
Copy Markdown

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 366.73
87.07
365.5
86.6
-1.23 kB
-473 B
WebGPU 677.88
187.81
676.2
187.18
-1.67 kB
-633 B
WebGPU Nodes 675.92
187.49
674.24
186.86
-1.67 kB
-629 B

🌳 Bundle size after tree-shaking

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

Before After Diff
WebGL 510
124.11
508.77
123.63
-1.23 kB
-473 B
WebGPU 758.56
204.67
756.88
203.98
-1.69 kB
-686 B
WebGPU Nodes 708.34
192.16
706.65
191.5
-1.69 kB
-659 B

@mrdoob mrdoob modified the milestones: r182, r183 Dec 10, 2025
@mrdoob mrdoob modified the milestones: r183, r184 Feb 18, 2026
@mrdoob mrdoob modified the milestones: r184, r185 Apr 16, 2026
@mrdoob mrdoob modified the milestones: r185, r186 Jun 24, 2026
@mrdoob mrdoob changed the title PMREMGenerator: Replace separable blur with spiral blur and optimize vertex shader PMREMGenerator: Replace separable blur with spiral blur on both renderers Jul 7, 2026
Comment thread src/Three.TSL.js Outdated
mrdoob and others added 7 commits July 8, 2026 14:19
…rt, function or class

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mrdoob
mrdoob merged commit 77053e2 into dev Jul 8, 2026
15 of 16 checks passed
@mrdoob
mrdoob deleted the pmrem branch July 8, 2026 06:29
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.

3 participants