Skip to content

Commit 8380531

Browse files
authored
PMREM: Simplify GGX VNDF importance sampling. (mrdoob#32737)
1 parent 1cf2378 commit 8380531

File tree

2 files changed

+13
-23
lines changed

2 files changed

+13
-23
lines changed

src/extras/PMREMGenerator.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -845,24 +845,20 @@ function _getGGXShader( lodMax, width, height ) {
845845
vec3 importanceSampleGGX_VNDF(vec2 Xi, vec3 V, float roughness) {
846846
float alpha = roughness * roughness;
847847
848-
// Section 3.2: Transform view direction to hemisphere configuration
849-
vec3 Vh = normalize(vec3(alpha * V.x, alpha * V.y, V.z));
850-
851848
// Section 4.1: Orthonormal basis
852-
float lensq = Vh.x * Vh.x + Vh.y * Vh.y;
853-
vec3 T1 = lensq > 0.0 ? vec3(-Vh.y, Vh.x, 0.0) / sqrt(lensq) : vec3(1.0, 0.0, 0.0);
854-
vec3 T2 = cross(Vh, T1);
849+
vec3 T1 = vec3(1.0, 0.0, 0.0);
850+
vec3 T2 = cross(V, T1);
855851
856852
// Section 4.2: Parameterization of projected area
857853
float r = sqrt(Xi.x);
858854
float phi = 2.0 * PI * Xi.y;
859855
float t1 = r * cos(phi);
860856
float t2 = r * sin(phi);
861-
float s = 0.5 * (1.0 + Vh.z);
857+
float s = 0.5 * (1.0 + V.z);
862858
t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2;
863859
864860
// Section 4.3: Reprojection onto hemisphere
865-
vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * Vh;
861+
vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * V;
866862
867863
// Section 3.4: Transform back to ellipsoid configuration
868864
return normalize(vec3(alpha * Nh.x, alpha * Nh.y, max(0.0, Nh.z)));

src/nodes/pmrem/PMREMUtils.js

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -312,30 +312,24 @@ const hammersley = /*@__PURE__*/ Fn( ( [ i, N ] ) => {
312312
// GGX VNDF importance sampling (Eric Heitz 2018)
313313
// "Sampling the GGX Distribution of Visible Normals"
314314
// https://jcgt.org/published/0007/04/01/
315-
const importanceSampleGGX_VNDF = /*@__PURE__*/ Fn( ( [ Xi, V_immutable, roughness_immutable ] ) => {
315+
const importanceSampleGGX_VNDF = /*@__PURE__*/ Fn( ( [ Xi, V, roughness ] ) => {
316316

317-
const V = vec3( V_immutable ).toVar();
318-
const roughness = float( roughness_immutable );
319-
const alpha = roughness.mul( roughness ).toVar();
320-
321-
// Section 3.2: Transform view direction to hemisphere configuration
322-
const Vh = normalize( vec3( alpha.mul( V.x ), alpha.mul( V.y ), V.z ) ).toVar();
317+
const alpha = roughness.mul( roughness ).toConst();
323318

324319
// Section 4.1: Orthonormal basis
325-
const lensq = Vh.x.mul( Vh.x ).add( Vh.y.mul( Vh.y ) );
326-
const T1 = select( lensq.greaterThan( 0.0 ), vec3( Vh.y.negate(), Vh.x, 0.0 ).div( sqrt( lensq ) ), vec3( 1.0, 0.0, 0.0 ) ).toVar();
327-
const T2 = cross( Vh, T1 ).toVar();
320+
const T1 = vec3( 1.0, 0.0, 0.0 ).toConst();
321+
const T2 = cross( V, T1 ).toConst();
328322

329323
// Section 4.2: Parameterization of projected area
330-
const r = sqrt( Xi.x );
331-
const phi = mul( 2.0, 3.14159265359 ).mul( Xi.y );
332-
const t1 = r.mul( cos( phi ) ).toVar();
324+
const r = sqrt( Xi.x ).toConst();
325+
const phi = mul( 2.0, 3.14159265359 ).mul( Xi.y ).toConst();
326+
const t1 = r.mul( cos( phi ) ).toConst();
333327
const t2 = r.mul( sin( phi ) ).toVar();
334-
const s = mul( 0.5, Vh.z.add( 1.0 ) );
328+
const s = mul( 0.5, V.z.add( 1.0 ) ).toConst();
335329
t2.assign( s.oneMinus().mul( sqrt( t1.mul( t1 ).oneMinus() ) ).add( s.mul( t2 ) ) );
336330

337331
// Section 4.3: Reprojection onto hemisphere
338-
const Nh = T1.mul( t1 ).add( T2.mul( t2 ) ).add( Vh.mul( sqrt( max( 0.0, t1.mul( t1 ).add( t2.mul( t2 ) ).oneMinus() ) ) ) );
332+
const Nh = T1.mul( t1 ).add( T2.mul( t2 ) ).add( V.mul( sqrt( max( 0.0, t1.mul( t1 ).add( t2.mul( t2 ) ).oneMinus() ) ) ) );
339333

340334
// Section 3.4: Transform back to ellipsoid configuration
341335
return normalize( vec3( alpha.mul( Nh.x ), alpha.mul( Nh.y ), max( 0.0, Nh.z ) ) );

0 commit comments

Comments
 (0)