diff options
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl')
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index bbc79a2d05b..004d884dc75 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -1,4 +1,5 @@ +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) #pragma BLENDER_REQUIRE(bsdf_common_lib.glsl) uniform sampler1D texHammersley; @@ -8,6 +9,11 @@ vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B) return T * vector.x + B * vector.y + N * vector.z; } +vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B) +{ + return vec3(dot(T, vector), dot(B, vector), dot(N, vector)); +} + #ifdef HAMMERSLEY_SIZE vec3 hammersley_3d(float i, float invsamplenbr) { @@ -22,9 +28,18 @@ vec3 hammersley_3d(float i, float invsamplenbr) /* -------------- BSDFS -------------- */ -float pdf_ggx_reflect(float NH, float a2) +#define USE_VISIBLE_NORMAL 1 + +float pdf_ggx_reflect(float NH, float NV, float VH, float alpha) { + float a2 = sqr(alpha); +#if USE_VISIBLE_NORMAL + float D = a2 / D_ggx_opti(NH, a2); + float G1 = NV * 2.0 / G1_Smith_GGX_opti(NV, a2); + return G1 * VH * D / NV; +#else return NH * a2 / D_ggx_opti(NH, a2); +#endif } float pdf_hemisphere() @@ -32,22 +47,50 @@ float pdf_hemisphere() return 0.5 * M_1_PI; } -vec3 sample_ggx(vec3 rand, float a2) +vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt) { +#if 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 + * 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); + 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; +#else /* Theta is the cone angle. */ - float z = sqrt((1.0 - rand.x) / (1.0 + a2 * rand.x - rand.x)); /* cos theta */ - float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ + float z = sqrt((1.0 - rand.x) / (1.0 + sqr(alpha) * rand.x - rand.x)); /* cos theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ float x = r * rand.y; float y = r * rand.z; - /* Microfacet Normal */ return vec3(x, y, z); +#endif } -vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH) +vec3 sample_ggx(vec3 rand, float alpha, vec3 V, vec3 N, vec3 T, vec3 B, out float pdf) { - vec3 Ht = sample_ggx(rand, a2); - NH = Ht.z; + vec3 Vt = world_to_tangent(V, N, T, B); + vec3 Ht = sample_ggx(rand, alpha, Vt); + float NH = saturate(Ht.z); + float NV = saturate(Vt.z); + float VH = saturate(dot(Vt, Ht)); + pdf = pdf_ggx_reflect(NH, NV, VH, alpha); return tangent_to_world(Ht, N, T, B); } @@ -69,18 +112,23 @@ vec3 sample_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B) } #ifdef HAMMERSLEY_SIZE -vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 B) +vec3 sample_ggx(float nsample, + float inv_sample_count, + float alpha, + vec3 V, + vec3 N, + vec3 T, + vec3 B, + out float pdf) { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - vec3 Ht = sample_ggx(Xi, a2); - return tangent_to_world(Ht, N, T, B); + return sample_ggx(Xi, alpha, V, N, T, B, pdf); } vec3 sample_hemisphere(float nsample, float inv_sample_count, vec3 N, vec3 T, vec3 B) { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - vec3 Ht = sample_hemisphere(Xi); - return tangent_to_world(Ht, N, T, B); + return sample_hemisphere(Xi, N, T, B); } vec3 sample_cone(float nsample, float inv_sample_count, float angle, vec3 N, vec3 T, vec3 B) |