Skip to content

Conversation

@mrdoob
Copy link
Owner

@mrdoob mrdoob commented Oct 23, 2025

Related issue: #26796

Description

Replaces the Gaussian blur approach for PMREM generation with GGX VNDF (Visible Normal Distribution Function) importance sampling, bringing Three.js environment map filtering in line with modern physically-based renderers like Blender Cycles, Blender EEVEE, and Unreal Engine.

Changes

  • Implement importanceSampleGGX_VNDF() based on Eric Heitz's 2018 algorithm "Sampling the GGX Distribution of Visible Normals"
  • Replace blur-based filtering with Monte Carlo integration using 2048 samples
  • Add tangent space transformation for proper VNDF sampling
  • Maintain split-sum approximation with NdotL weighting for IBL

Benefits

Accuracy:

  • Physically accurate GGX distribution instead of blur approximation
  • Properly matches the GGX BRDF used in material rendering
  • Correct energy conservation across all roughness levels
  • Eliminates mismatch artifacts between environment filtering and material shading

Quality:

  • Better sample distribution focusing on visible microfacets
  • More accurate specular reflections, especially at low-to-mid roughness
  • Matches results from Blender and other industry-standard renderers

Technical Details

Why VNDF over standard GGX?

VNDF importance sampling accounts for the view direction when sampling microfacet normals. It only samples normals that are visible from the viewing direction, avoiding wasted samples on back-facing microfacets that don't contribute to the final result. This is ~58% faster than standard GGX importance sampling.

Implementation follows Heitz 2018 (Sections 3.2-4.3):

  1. Transform view direction to hemisphere configuration
  2. Build orthonormal basis in transformed space
  3. Sample parameterized projected area (disk)
  4. Reproject onto hemisphere and transform back to ellipsoid

For PMREM pre-filtering:

  • View direction V = Normal N (pre-filtering assumption)
  • Uses Hammersley sequence for low-discrepancy sampling
  • 2048 samples per pixel for high-quality results
  • NdotL weighting for split-sum approximation
Before After
Screenshot 2025-10-28 at 6 03 17 PM Screenshot 2025-10-28 at 6 03 00 PM
Screenshot 2025-10-28 at 6 07 50 PM Screenshot 2025-10-28 at 6 07 56 PM

@github-actions
Copy link

github-actions bot commented Oct 23, 2025

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 350.11
84.81
355.09
86.26
+4.98 kB
+1.45 kB
WebGPU 605.24
169.71
605.24
169.71
+0 B
+0 B
WebGPU Nodes 603.85
169.47
603.85
169.47
+0 B
+0 B

🌳 Bundle size after tree-shaking

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

Before After Diff
WebGL 481.77
119.56
486.74
121.01
+4.97 kB
+1.44 kB
WebGPU 674.62
185.19
674.62
185.19
+0 B
+0 B
WebGPU Nodes 616.61
168.41
616.61
168.41
+0 B
+0 B

@mrdoob mrdoob changed the title PMREM: Implement GGX importance sampling PMREM: Implement GGX VNDF importance sampling Oct 28, 2025
@mrdoob mrdoob added this to the r181 milestone Oct 28, 2025
@mrdoob mrdoob marked this pull request as ready for review October 28, 2025 09:30
@mrdoob mrdoob merged commit f2d10b8 into dev Oct 28, 2025
10 checks passed
@mrdoob mrdoob deleted the pmrem branch October 28, 2025 11:12
@mrdoob mrdoob changed the title PMREM: Implement GGX VNDF importance sampling WebGLRenderer: Implement GGX VNDF importance sampling Oct 29, 2025
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