From dfe7b839bca6a66c3eefa2b5968c061b425e2df1 Mon Sep 17 00:00:00 2001 From: Weizhen Huang Date: Tue, 14 Mar 2023 17:02:09 +0100 Subject: [PATCH] Cycles: only apply function #ensure_valid_reflection to glossy materials This function checks if the shading normal would result in an invalid reflection into the lower hemisphere; if it is the case, the function raises the shading normal just enough so that the specular reflection lies above the surface. This is a trick to prevent dark regions at grazing angles caused by normal/bump maps. However, the specular direction is not a good representation for a diffuse material, applying this function sometimes brightens the result too much and causes unexpected results. This patch applies the function to only glossy materials instead. Pull Request: #105776 --- intern/cycles/kernel/closure/bsdf_util.h | 10 ++++++ intern/cycles/kernel/osl/closures_setup.h | 14 ++++---- .../cycles/kernel/osl/shaders/node_bump.osl | 2 -- intern/cycles/kernel/osl/shaders/stdcycles.h | 34 ------------------- intern/cycles/kernel/svm/closure.h | 34 ++++++++----------- intern/cycles/kernel/svm/displace.h | 1 - 6 files changed, 32 insertions(+), 63 deletions(-) diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 154f281b4b6..24195a3b5a0 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -180,4 +180,14 @@ ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N) return Nx * X + Nz * Ng; } +/* Do not call #ensure_valid_reflection if the primitive type is curve or if the geometry + * normal and the shading normal is the same. */ +ccl_device float3 maybe_ensure_valid_reflection(ccl_private ShaderData *sd, float3 N) +{ + if ((sd->type & PRIMITIVE_CURVE) || isequal(sd->Ng, N)) { + return N; + } + return ensure_valid_reflection(sd->Ng, sd->wi, N); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/closures_setup.h b/intern/cycles/kernel/osl/closures_setup.h index 01d2c7408b5..e496a70e36e 100644 --- a/intern/cycles/kernel/osl/closures_setup.h +++ b/intern/cycles/kernel/osl/closures_setup.h @@ -78,7 +78,7 @@ ccl_device void osl_closure_diffuse_setup(KernelGlobals kg, return; } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N); + bsdf->N = closure->N; sd->flag |= bsdf_diffuse_setup(bsdf); } @@ -99,7 +99,7 @@ ccl_device void osl_closure_oren_nayar_setup(KernelGlobals kg, return; } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N); + bsdf->N = closure->N; bsdf->roughness = closure->roughness; sd->flag |= bsdf_oren_nayar_setup(bsdf); @@ -121,7 +121,7 @@ ccl_device void osl_closure_translucent_setup(KernelGlobals kg, return; } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N); + bsdf->N = closure->N; sd->flag |= bsdf_translucent_setup(bsdf); } @@ -999,7 +999,7 @@ ccl_device void osl_closure_principled_diffuse_setup( return; } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N); + bsdf->N = closure->N; bsdf->roughness = closure->roughness; sd->flag |= bsdf_principled_diffuse_setup(bsdf); @@ -1022,7 +1022,7 @@ ccl_device void osl_closure_principled_sheen_setup( return; } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N); + bsdf->N = closure->N; bsdf->avg_value = 0.0f; sd->flag |= bsdf_principled_sheen_setup(sd, bsdf); @@ -1109,7 +1109,7 @@ ccl_device void osl_closure_diffuse_ramp_setup(KernelGlobals kg, return; } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N); + bsdf->N = closure->N; bsdf->colors = (float3 *)closure_alloc_extra(sd, sizeof(float3) * 8); if (!bsdf->colors) { @@ -1185,7 +1185,7 @@ ccl_device void osl_closure_bssrdf_setup(KernelGlobals kg, /* create one closure per color channel */ bssrdf->albedo = closure->albedo; - bssrdf->N = ensure_valid_reflection(sd->Ng, sd->wi, closure->N); + bssrdf->N = closure->N; bssrdf->roughness = closure->roughness; bssrdf->anisotropy = clamp(closure->anisotropy, 0.0f, 0.9f); diff --git a/intern/cycles/kernel/osl/shaders/node_bump.osl b/intern/cycles/kernel/osl/shaders/node_bump.osl index 4f830d79ee5..86e9b683fd0 100644 --- a/intern/cycles/kernel/osl/shaders/node_bump.osl +++ b/intern/cycles/kernel/osl/shaders/node_bump.osl @@ -50,6 +50,4 @@ surface node_bump(int invert = 0, if (use_object_space) { NormalOut = normalize(transform("object", "world", NormalOut)); } - - NormalOut = ensure_valid_reflection(Ng, I, NormalOut); } diff --git a/intern/cycles/kernel/osl/shaders/stdcycles.h b/intern/cycles/kernel/osl/shaders/stdcycles.h index d877613f483..6fe0e5987fa 100644 --- a/intern/cycles/kernel/osl/shaders/stdcycles.h +++ b/intern/cycles/kernel/osl/shaders/stdcycles.h @@ -65,38 +65,4 @@ closure color principled_hair(normal N, closure color henyey_greenstein(float g) BUILTIN; closure color absorption() BUILTIN; -normal ensure_valid_reflection(normal Ng, vector I, normal N) -{ - /* The implementation here mirrors the one in bsdf_util.h, - * check there for an explanation of the algorithm. */ - - float sqr(float x) - { - return x * x; - } - - vector R = 2 * dot(N, I) * N - I; - - float Iz = dot(I, Ng); - - float threshold = min(0.9 * Iz, 0.01); - if (dot(Ng, R) >= threshold) { - return N; - } - - vector X = normalize(N - dot(N, Ng) * Ng); - float Ix = dot(I, X); - - float a = sqr(Ix) + sqr(Iz); - float b = 2.0 * (a + Iz * threshold); - float c = sqr(threshold + Iz); - - float Nz2 = (Ix < 0) ? 0.25 * (b + sqrt(sqr(b) - 4.0 * a * c)) / a : - 0.25 * (b - sqrt(sqr(b) - 4.0 * a * c)) / a; - float Nx = sqrt(1.0 - Nz2); - float Nz = sqrt(Nz2); - - return Nx * X + Nz * Ng; -} - #endif /* CCL_STDOSL_H */ diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index a8886d8c99c..f48fe8e86f0 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -59,9 +59,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, float3 N = stack_valid(data_node.x) ? safe_normalize(stack_load_float3(stack, data_node.x)) : sd->N; - if (!(sd->type & PRIMITIVE_CURVE)) { - N = ensure_valid_reflection(sd->Ng, sd->wi, N); - } float param1 = (stack_valid(param1_offset)) ? stack_load_float(stack, param1_offset) : __uint_as_float(node.z); @@ -119,8 +116,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, /* calculate ior */ float ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; - // calculate fresnel for refraction - float cosNI = dot(N, sd->wi); + /* Calculate fresnel for refraction. */ + float3 valid_reflection_N = maybe_ensure_valid_reflection(sd, N); + float cosNI = dot(valid_reflection_N, sd->wi); float fresnel = fresnel_dielectric_cos(cosNI, ior); // calculate weights of the diffuse and specular part @@ -142,9 +140,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ? stack_load_float3(stack, data_cn_ssr.x) : sd->N; - if (!(sd->type & PRIMITIVE_CURVE)) { - clearcoat_normal = ensure_valid_reflection(sd->Ng, sd->wi, clearcoat_normal); - } + clearcoat_normal = maybe_ensure_valid_reflection(sd, clearcoat_normal); float3 subsurface_radius = stack_valid(data_cn_ssr.y) ? stack_load_float3(stack, data_cn_ssr.y) : one_float3(); @@ -271,7 +267,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, NULL; if (bsdf && fresnel) { - bsdf->N = N; + bsdf->N = valid_reflection_N; bsdf->ior = (2.0f / (1.0f - safe_sqrtf(0.08f * specular))) - 1.0f; bsdf->T = T; @@ -333,7 +329,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, NULL; if (bsdf && fresnel) { - bsdf->N = N; + bsdf->N = valid_reflection_N; bsdf->T = zero_float3(); bsdf->fresnel = fresnel; @@ -362,7 +358,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sizeof(MicrofacetBsdf), rgb_to_spectrum(base_color) * glass_weight * refraction_fresnel); if (bsdf) { - bsdf->N = N; + bsdf->N = valid_reflection_N; bsdf->T = zero_float3(); bsdf->fresnel = NULL; @@ -390,7 +386,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, NULL; if (bsdf && fresnel) { - bsdf->N = N; + bsdf->N = valid_reflection_N; bsdf->fresnel = fresnel; bsdf->T = zero_float3(); @@ -461,7 +457,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd, sizeof(DiffuseBsdf), weight); if (bsdf) { - bsdf->N = N; + bsdf->N = maybe_ensure_valid_reflection(sd, N); sd->flag |= bsdf_translucent_setup(bsdf); } break; @@ -490,7 +486,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, float roughness = sqr(param1); - bsdf->N = N; + bsdf->N = maybe_ensure_valid_reflection(sd, N); bsdf->ior = 1.0f; bsdf->fresnel = NULL; @@ -554,7 +550,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd, sizeof(MicrofacetBsdf), weight); if (bsdf) { - bsdf->N = N; + bsdf->N = maybe_ensure_valid_reflection(sd, N); bsdf->T = zero_float3(); bsdf->fresnel = NULL; @@ -597,7 +593,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd, sizeof(MicrofacetBsdf), weight); if (bsdf) { - bsdf->N = N; + bsdf->N = maybe_ensure_valid_reflection(sd, N); bsdf->T = zero_float3(); bsdf->fresnel = NULL; @@ -646,7 +642,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, break; } - bsdf->N = N; + bsdf->N = maybe_ensure_valid_reflection(sd, N); bsdf->fresnel = fresnel; bsdf->T = zero_float3(); @@ -752,7 +748,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, float coat = stack_load_float_default(stack, coat_ofs, data_node2.y); float m0_roughness = 1.0f - clamp(coat, 0.0f, 1.0f); - bsdf->N = N; + bsdf->N = maybe_ensure_valid_reflection(sd, N); bsdf->v = roughness; bsdf->s = radial_roughness; bsdf->m0_roughness = m0_roughness; @@ -820,7 +816,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd, sizeof(HairBsdf), weight); if (bsdf) { - bsdf->N = N; + bsdf->N = maybe_ensure_valid_reflection(sd, N); bsdf->roughness1 = param1; bsdf->roughness2 = param2; bsdf->offset = -stack_load_float(stack, data_node.z); diff --git a/intern/cycles/kernel/svm/displace.h b/intern/cycles/kernel/svm/displace.h index d2be8c4844b..844f7afa90b 100644 --- a/intern/cycles/kernel/svm/displace.h +++ b/intern/cycles/kernel/svm/displace.h @@ -71,7 +71,6 @@ ccl_device_noinline void svm_node_set_bump(KernelGlobals kg, object_normal_transform(kg, sd, &normal_out); } - normal_out = ensure_valid_reflection(sd->Ng, sd->wi, normal_out); stack_store_float3(stack, node.w, normal_out); } else