Cycles: Add thin film iridescence to Principled BSDF #118477

Merged
Lukas Stockner merged 18 commits from LukasStockner/blender:iridescence into main 2024-05-02 14:28:57 +02:00
3 changed files with 22 additions and 18 deletions
Showing only changes of commit 1c210468c6 - Show all commits

View File

@ -30,7 +30,7 @@ enum MicrofacetFresnel {
};
typedef struct FresnelThinFilm {
float d;
float thickness;
float ior;
} FresnelThinFilm;
@ -268,13 +268,22 @@ ccl_device_forceinline void microfacet_fresnel(KernelGlobals kg,
else if (bsdf->fresnel_type == MicrofacetFresnel::GENERALIZED_SCHLICK) {
ccl_private FresnelGeneralizedSchlick *fresnel = (ccl_private FresnelGeneralizedSchlick *)
bsdf->fresnel;
float s;
if (fresnel->exponent < 0.0f) {
Spectrum F;
if (fresnel->thin_film.thickness > 0.1f) {
/* Iridescence doesn't combine well with the general case. We only expose it through the
* Principled BSDF for now, so it's fine to not support custom exponents and F90. */
kernel_assert(fresnel->exponent < 0.0f);
kernel_assert(fresnel->f90 == one_spectrum());
F = fresnel_iridescence(
kg, 1.0f, fresnel->thin_film.ior, bsdf->ior, cos_theta_i, fresnel->thin_film.thickness);
}
else if (fresnel->exponent < 0.0f) {
/* Special case: Use real Fresnel curve to determine the interpolation between F0 and F90.
* Used by Principled v1. */
* Used by Principled BSDF. */
const float F_real = fresnel_dielectric(cos_theta_i, bsdf->ior, r_cos_theta_t);
const float F0_real = F0_from_ior(bsdf->ior);
s = saturatef(inverse_lerp(F0_real, 1.0f, F_real));
const float s = saturatef(inverse_lerp(F0_real, 1.0f, F_real));
F = mix(fresnel->f0, fresnel->f90, s);
}
else {
/* Regular case: Generalized Schlick term. */
@ -292,14 +301,9 @@ ccl_device_forceinline void microfacet_fresnel(KernelGlobals kg,
/* TODO(lukas): Is a special case for exponent==5 worth it? */
/* When going from a higher to a lower IOR, we must use the transmitted angle. */
s = powf(1.0f - ((bsdf->ior < 1.0f) ? cos_theta_t : cos_theta_i), fresnel->exponent);
}
Spectrum F = mix(fresnel->f0, fresnel->f90, s);
if (fresnel->thin_film.d > 1e-5f) {
/* TODO: Integrate this properly.
* Hard to combine with F0/F90 - maybe split out the "Special case" above into a separate
* Fresnel type and only apply thin film there (since Principled doesn't use F90). */
F = fresnel_iridescence(kg, 1.0f, fresnel->thin_film.ior, bsdf->ior, cos_theta_i, fresnel->thin_film.d);
const float fresnel_angle = ((bsdf->ior < 1.0f) ? cos_theta_t : cos_theta_i);
const float s = powf(1.0f - fresnel_angle, fresnel->exponent);
F = mix(fresnel->f0, fresnel->f90, s);
}
*r_reflectance = F * fresnel->reflection_tint;
*r_transmittance = (one_spectrum() - F) * fresnel->transmission_tint;

View File

@ -274,7 +274,7 @@ ccl_device void osl_closure_dielectric_bsdf_setup(KernelGlobals kg,
fresnel->reflection_tint = rgb_to_spectrum(closure->reflection_tint);
fresnel->transmission_tint = rgb_to_spectrum(closure->transmission_tint);
fresnel->thin_film.d = 0.0f;
fresnel->thin_film.thickness = 0.0f;
fresnel->thin_film.ior = 0.0f;
bsdf_microfacet_setup_fresnel_dielectric_tint(kg, bsdf, sd, fresnel, preserve_energy);
@ -425,7 +425,7 @@ ccl_device void osl_closure_generalized_schlick_bsdf_setup(
fresnel->f0 = rgb_to_spectrum(closure->f0);
fresnel->f90 = rgb_to_spectrum(closure->f90);
fresnel->exponent = closure->exponent;
fresnel->thin_film.d = 0.0f;
fresnel->thin_film.thickness = 0.0f;
fresnel->thin_film.ior = 0.0f;
bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, preserve_energy);

View File

@ -326,7 +326,7 @@ ccl_device
fresnel->transmission_tint = refractive_caustics ?
sqrt(rgb_to_spectrum(clamped_base_color)) :
zero_spectrum();
fresnel->thin_film.d = thinfilm_thickness;
fresnel->thin_film.thickness = thinfilm_thickness;
fresnel->thin_film.ior = thinfilm_ior;
/* setup bsdf */
@ -371,7 +371,7 @@ ccl_device
fresnel->exponent = -eta;
fresnel->reflection_tint = one_spectrum();
fresnel->transmission_tint = zero_spectrum();
fresnel->thin_film.d = thinfilm_thickness;
fresnel->thin_film.thickness = thinfilm_thickness;
fresnel->thin_film.ior = thinfilm_ior;
/* setup bsdf */
@ -608,7 +608,7 @@ ccl_device
fresnel->reflection_tint = reflective_caustics ? rgb_to_spectrum(color) : zero_spectrum();
fresnel->transmission_tint = refractive_caustics ? rgb_to_spectrum(color) :
zero_spectrum();
fresnel->thin_film.d = 0.0f;
fresnel->thin_film.thickness = 0.0f;
fresnel->thin_film.ior = 0.0f;
/* setup bsdf */