[Bf-blender-cvs] [0399badca57] principled-v2: Cleanup microfacet code (move distribution helpers to header, reduce nested ifs)
Lukas Stockner
noreply at git.blender.org
Mon Jul 4 23:56:11 CEST 2022
Commit: 0399badca5736c8097c5a99b59e14f15b1080b9d
Author: Lukas Stockner
Date: Mon Jul 4 23:31:47 2022 +0200
Branches: principled-v2
https://developer.blender.org/rB0399badca5736c8097c5a99b59e14f15b1080b9d
Cleanup microfacet code (move distribution helpers to header, reduce nested ifs)
===================================================================
M intern/cycles/kernel/CMakeLists.txt
M intern/cycles/kernel/closure/bsdf_microfacet.h
A intern/cycles/kernel/closure/bsdf_microfacet_util.h
===================================================================
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index a37c0299652..7948031ec40 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -103,6 +103,7 @@ set(SRC_KERNEL_CLOSURE_HEADERS
closure/bsdf_microfacet_beckmann.h
closure/bsdf_microfacet_multi.h
closure/bsdf_microfacet_multi_impl.h
+ closure/bsdf_microfacet_util.h
closure/bsdf_oren_nayar.h
closure/bsdf_phong_ramp.h
closure/bsdf_reflection.h
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 42ea71f62a9..000bde9e5d5 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -8,6 +8,7 @@
#pragma once
+#include "kernel/closure/bsdf_microfacet_util.h"
#include "kernel/closure/bsdf_util.h"
CCL_NAMESPACE_BEGIN
@@ -66,80 +67,6 @@ ccl_device_forceinline void bsdf_microfacet_fresnel_color(ccl_private const Shad
bsdf->sample_weight *= average(bsdf->extra->fresnel_color);
}
-/* GGX microfacet with Smith shadow-masking from:
- *
- * Microfacet Models for Refraction through Rough Surfaces
- * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007
- *
- * VNDF sampling as well as D and lambda terms from:
- *
- * Sampling the GGX Distribution of Visible Normals.
- * E. Heitz and E. d'Eon, JCGT Vol. 7, No. 4, 2018.
- * https://jcgt.org/published/0007/04/01/
- *
- * Also see for more details on marking-shadowing:
- * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs.
- * E. Heitz, JCGT Vol. 3, No. 2, 2014.
- * https://jcgt.org/published/0003/02/03/
- *
- * Anisotropy is only supported for reflection currently, but adding it for
- * transmission is just a matter of copying code from reflection if needed. */
-
-ccl_device_forceinline float microfacet_ggx_lambda(const float cosTheta, const float alpha2)
-{
- float tanTheta2 = (1 - sqr(cosTheta)) / sqr(cosTheta);
- return 0.5f * (safe_sqrtf(1 + alpha2 * tanTheta2) - 1);
-}
-
-ccl_device_forceinline float microfacet_ggx_lambda_aniso(const float3 w,
- const float alpha_x,
- const float alpha_y)
-{
- return 0.5f * (safe_sqrtf(1 + (sqr(w.x * alpha_x) + sqr(w.y * alpha_y)) / sqr(w.z)) - 1);
-}
-
-ccl_device_forceinline float microfacet_ggx_D(const float cosThetaM, const float alpha2)
-{
- float cosThetaM2 = sqr(cosThetaM);
- float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
- return alpha2 / (M_PI_F * sqr(cosThetaM2 * (alpha2 + tanThetaM2)));
-}
-
-ccl_device_forceinline float microfacet_ggx_D_aniso(const float3 m,
- const float alpha_x,
- const float alpha_y)
-{
- return 1 /
- (M_PI_F * alpha_x * alpha_y * sqr(sqr(m.x / alpha_x) + sqr(m.y / alpha_y) + sqr(m.z)));
-}
-
-ccl_device_forceinline float microfacet_GTR1_D(const float cosThetaM, const float alpha2)
-{
- if (alpha2 >= 1.0f)
- return M_1_PI_F;
- float t = 1.0f + (alpha2 - 1.0f) * sqr(cosThetaM);
- return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t);
-}
-
-ccl_device_forceinline float3 microfacet_ggx_sample_vndf(
- const float3 V, const float alpha_x, const float alpha_y, const float U1, const float U2)
-{
- /* Section 3.2: Transforming the view direction to the hemisphere configuration. */
- float3 Vh = normalize(make_float3(alpha_x * V.x, alpha_y * V.y, V.z));
- /* Section 4.1: Orthonormal basis (with special case if cross product is zero). */
- float lensq = sqr(Vh.x) + sqr(Vh.y);
- float3 T1 = lensq > 1e-7f ? make_float3(-Vh.y, Vh.x, 0.0f) / sqrtf(lensq) :
- make_float3(1.0f, 0.0f, 0.0f);
- float3 T2 = cross(Vh, T1);
- /* Section 4.2: Parameterization of the projected area. */
- float2 t = concentric_sample_disk(U1, U2);
- t.y = mix(safe_sqrtf(1.0f - sqr(t.x)), t.y, 0.5f * (1.0f + Vh.z));
- /* Section 4.3: Reprojection onto hemisphere. */
- float3 Mh = t.x * T1 + t.y * T2 + safe_sqrtf(1.0f - len_squared(t)) * Vh;
- /* Section 3.4: Transforming the normal back to the ellipsoid configuration. */
- return normalize(make_float3(alpha_x * Mh.x, alpha_y * Mh.y, max(0.0f, Mh.z)));
-}
-
ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
{
bsdf->extra = NULL;
@@ -218,10 +145,11 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(ccl_private const ShaderClosu
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
float alpha_x = bsdf->alpha_x;
float alpha_y = bsdf->alpha_y;
+ float alpha2 = alpha_x * alpha_y;
bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
float3 N = bsdf->N;
- if (m_refractive || alpha_x * alpha_y <= 1e-7f) {
+ if (m_refractive || alpha2 <= 1e-7f) {
*pdf = 0.0f;
return make_float3(0.0f, 0.0f, 0.0f);
}
@@ -232,76 +160,76 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(ccl_private const ShaderClosu
* Therefore, in the BSDF code, I is referred to as O and omega_in is referred to as I
* in order to be consistent with papers.
*/
+
+ /* Ensure that both direction are in the upper hemisphere */
float cosNO = dot(N, I);
float cosNI = dot(N, omega_in);
+ if (cosNI <= 0 || cosNO <= 0) {
+ *pdf = 0.0f;
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
- if (cosNI > 0 && cosNO > 0) {
- /* get half vector */
- float3 m = normalize(omega_in + I);
- float alpha2 = alpha_x * alpha_y;
- float D, lambdaO, lambdaI;
-
- if (alpha_x == alpha_y) {
- /* Isotropic case */
+ /* Compute half vector */
+ float3 m = normalize(omega_in + I);
- if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
- /* use GTR1 for clearcoat */
- D = microfacet_GTR1_D(dot(N, m), alpha2);
+ float D, lambdaO, lambdaI;
+ if (alpha_x == alpha_y) {
+ /* Isotropic case */
- /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */
- alpha2 = 0.0625f;
- }
- else {
- /* use GTR2 otherwise */
- D = microfacet_ggx_D(dot(N, m), alpha2);
- }
+ if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
+ /* use GTR1 for clearcoat */
+ D = microfacet_GTR1_D(dot(N, m), alpha2);
- lambdaO = microfacet_ggx_lambda(cosNO, alpha2);
- lambdaI = microfacet_ggx_lambda(cosNI, alpha2);
+ /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */
+ alpha2 = 0.0625f;
}
else {
- /* Anisotropic case */
- float3 X, Y, Z = N;
- make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
-
- /* Transform vectors into local coordinate space */
- float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
- float3 local_O = make_float3(dot(X, I), dot(Y, I), cosNO);
- float3 local_I = make_float3(dot(X, omega_in), dot(Y, omega_in), cosNI);
-
- D = microfacet_ggx_D_aniso(local_m, alpha_x, alpha_y);
- lambdaO = microfacet_ggx_lambda_aniso(local_O, alpha_x, alpha_y);
- lambdaI = microfacet_ggx_lambda_aniso(local_I, alpha_x, alpha_y);
+ /* use GTR2 otherwise */
+ D = microfacet_ggx_D(dot(N, m), alpha2);
}
- /* The full BSDF is (see e.g. eq. 20 in Walter et al. 2017):
- * f(i, o) = F(i, m) * G(i, o) * D(m) / (4*cosNI*cosNO).
- *
- * Here, F is the fresnel reflection term, G is the masking-shadowing term,
- * D is the microfacet distribution and cosNI/cosNO are cosines of angles.
- *
- * For G, this implementation uses the non-separable form of the Smith
- * masking-shadowing term, so G is defined in terms of a function Lambda:
- * G(i, o) = 1 / (1 + Lambda(i) + Lambda(o)).
- *
- * In Cycles, BSDF evaluation actually returns f(i, o)*cosNI, so one term
- * in the BSDFs denominator cancels out.
- *
- * The PDF of VNDF sampling is D(m) * G1(o) / (4*cosNO), where G1(o) is
- * 1 / (1 + Lambda(o)).
- */
+ lambdaO = microfacet_ggx_lambda(cosNO, alpha2);
+ lambdaI = microfacet_ggx_lambda(cosNI, alpha2);
+ }
+ else {
+ /* Anisotropic case */
+ float3 X, Y, Z = N;
+ make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
- float common = D * 0.25f / cosNO;
+ /* Transform vectors into local coordinate space */
+ float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m));
+ float3 local_O = make_float3(dot(X, I), dot(Y, I), cosNO);
+ float3 local_I = make_float3(dot(X, omega_in), dot(Y, omega_in), cosNI);
- float3 F = reflection_color(bsdf, omega_in, m);
+ D = microfacet_ggx_D_aniso(local_m, alpha_x, alpha_y);
+ lambdaO = microfacet_ggx_lambda_aniso(local_O, alpha_x, alpha_y);
+ lambdaI = microfacet_ggx_lambda_aniso(local_I, alpha_x, alpha_y);
+ }
- float3 out = F * common / (1 + lambdaO + lambdaI);
- *pdf = common / (1 + lambdaO);
+ /* The full BSDF is (see e.g. eq. 20 in Walter et al. 2007):
+ * f(i, o) = F(i, m) * G(i, o) * D(m) / (4*cosNI*cosNO).
+ *
+ * Here, F is the fresnel reflection term, G is the masking-shadowing term,
+ * D is the microfacet distribution and cosNI/cosNO are cosines of angles.
+ *
+ * For G, this implementation uses the non-separable form of the Smith
+ * masking-shadowing term, so G is defined in terms of a function Lambda:
+ * G(i, o) = 1 / (1 + Lambda(i) + Lambda(o)).
+ *
+ * In Cycles, BSDF evaluation actually returns f(i, o)*cosNI, so one term
+ * in the BSDFs denominator cancels out.
+ *
+ * The PDF of VNDF sampling is D(m) * G1(o) / (4*cosNO), where G1(o) is
+ * 1 / (1 + Lambda(o)).
+ */
- return out;
- }
+ /* Evaluate BSDF */
+ float common = D * 0.25f / cosNO;
+ float3 F = reflection_color(bsdf, omega_in, m);
+ float3 out = F * common / (1 + lambdaO + lambdaI);
+ *pdf = common / (1 + lambdaO);
- return make_float3(0.0f, 0.0f, 0.0f);
+ return out;
}
ccl_device float3 bsdf_microfacet_ggx_eval_transmit(ccl_private const ShaderClosure *sc,
@@ -312,46 +240,38 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(ccl_private const ShaderClos
ccl_private const MicrofacetBsdf *bsdf = (ccl_p
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list