From ea669cb8dc6c96b83f5b2fb1600d517f6606f3db Mon Sep 17 00:00:00 2001 From: Weizhen Huang Date: Thu, 4 Jan 2024 14:17:06 +1300 Subject: [PATCH] EEVEE-Next: implement more efficient GGX VNDF sampling from paper "Sampling the GGX Distribution of Visible Normals" --- .../shaders/eevee_bxdf_sampling_lib.glsl | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_bxdf_sampling_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_bxdf_sampling_lib.glsl index 103d3c327a7..f602053fe1f 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_bxdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_bxdf_sampling_lib.glsl @@ -39,35 +39,33 @@ float sample_pdf_ggx_refract( * * \param rand: random point on the unit cylinder (result of sample_cylinder). * \param alpha: roughness parameter. - * \param tV: tangent space view vector. + * \param Vt: tangent space view vector. * \param G1_V: output G1_V factor to be reused. */ vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt, out float G1_V) { #if GGX_USE_VISIBLE_NORMAL - /* From: - * "A Simpler and Exact Sampling Routine for the GGXDistribution of Visible Normals" - * by Eric Heitz. - * http://jcgt.org/published/0007/04/01/slides.pdf + /* Sampling Visible GGX Normals with Spherical Caps. + * Jonathan Dupuy and Anis Benyoub, HPG Vol. 42, No. 8, 2023. + * https://diglib.eg.org/bitstream/handle/10.1111/cgf14867/v42i8_03_14867.pdf * View vector is expected to be in tangent space. */ - /* Stretch view. */ - vec3 Th, Bh, Vh = normalize(vec3(alpha * Vt.xy, Vt.z)); - make_orthonormal_basis(Vh, Th, Bh); - /* Sample point with polar coordinates (r, phi). */ - float r = sqrt(rand.x); - float x = r * rand.y; - float y = r * rand.z; - float s = 0.5 * (1.0 + Vh.z); - G1_V = Vh.z / s; - y = (1.0 - s) * sqrt(1.0 - x * x) + s * y; - float z = sqrt(saturate(1.0 - x * x - y * y)); - /* Compute normal. */ - vec3 Hh = x * Th + y * Bh + z * Vh; - /* Unstretch. */ - vec3 Ht = normalize(vec3(alpha * Hh.xy, saturate(Hh.z))); - /* Microfacet Normal. */ - return Ht; + /* Transforming the view direction to the hemisphere configuration. */ + vec3 Vh = normalize(vec3(alpha * Vt.xy, Vt.z)); + + /* Visibility term. */ + G1_V = 2.0 * Vh.z / (1.0 + Vh.z); + + /* Sample a spherical cap in (-Vh.z, 1]. */ + float cos_theta = mix(-Vh.z, 1.0, 1.0 - rand.x); + float sin_theta = sqrt(saturate(1.0 - square(cos_theta))); + vec3 Lh = vec3(sin_theta * rand.yz, cos_theta); + + /* Compute unnormalized halfway direction. */ + vec3 Hh = Vh + Lh; + + /* Transforming the normal back to the ellipsoid configuration. */ + return normalize(vec3(alpha * Hh.xy, max(0.0, Hh.z))); #else /* Theta is the cone angle. */ float z = sqrt((1.0 - rand.x) / (1.0 + square(alpha) * rand.x - rand.x)); /* cos theta */