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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user