2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
|
|
|
|
|
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
2012-12-15 10:18:42 +00:00
|
|
|
*
|
2023-06-14 16:52:36 +10:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
2012-12-15 10:18:42 +00:00
|
|
|
*
|
2023-06-14 16:52:36 +10:00
|
|
|
* Adapted code from Open Shading Language. */
|
2012-12-15 10:18:42 +00:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
#pragma once
|
2012-12-15 10:18:42 +00:00
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
/* Compute fresnel reflectance for perpendicular (aka S-) and parallel (aka P-) polarized light.
|
|
|
|
|
* If requested by the caller, r_phi is set to the phase shift on reflection.
|
|
|
|
|
* Also returns the dot product of the refracted ray and the normal as `cos_theta_t`, as it is
|
|
|
|
|
* used when computing the direction of the refracted ray. */
|
|
|
|
|
ccl_device float2 fresnel_dielectric_polarized(float cos_theta_i,
|
|
|
|
|
float eta,
|
|
|
|
|
ccl_private float *r_cos_theta_t,
|
|
|
|
|
ccl_private float2 *r_phi)
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
{
|
|
|
|
|
kernel_assert(!isnan_safe(cos_theta_i));
|
|
|
|
|
|
|
|
|
|
/* Using Snell's law, calculate the squared cosine of the angle between the surface normal and
|
|
|
|
|
* the transmitted ray. */
|
2023-09-07 18:55:48 +02:00
|
|
|
const float eta_cos_theta_t_sq = sqr(eta) - (1.0f - sqr(cos_theta_i));
|
|
|
|
|
if (eta_cos_theta_t_sq <= 0) {
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
/* Total internal reflection. */
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
if (r_phi) {
|
|
|
|
|
/* The following code would compute the proper phase shift on TIR.
|
|
|
|
|
* However, for the current user of this computation (the iridescence code),
|
|
|
|
|
* this doesn't actually affect the result, so don't bother with the computation for now.
|
|
|
|
|
*
|
2024-05-03 11:06:22 +10:00
|
|
|
* `const float fac = sqrtf(1.0f - sqr(cosThetaI) - sqr(eta));`
|
|
|
|
|
* `r_phi->x = -2.0f * atanf(fac / cosThetaI);`
|
|
|
|
|
* `r_phi->y = -2.0f * atanf(fac / (cosThetaI * sqr(eta)));`
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
*/
|
|
|
|
|
*r_phi = zero_float2();
|
|
|
|
|
}
|
|
|
|
|
return one_float2();
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cos_theta_i = fabsf(cos_theta_i);
|
|
|
|
|
/* Relative to the surface normal. */
|
2023-09-07 18:55:48 +02:00
|
|
|
const float cos_theta_t = -safe_sqrtf(eta_cos_theta_t_sq) / eta;
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
|
|
|
|
|
if (r_cos_theta_t) {
|
|
|
|
|
*r_cos_theta_t = cos_theta_t;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Amplitudes of reflected waves. */
|
|
|
|
|
const float r_s = (cos_theta_i + eta * cos_theta_t) / (cos_theta_i - eta * cos_theta_t);
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
const float r_p = (cos_theta_t + eta * cos_theta_i) / (eta * cos_theta_i - cos_theta_t);
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
if (r_phi) {
|
|
|
|
|
*r_phi = make_float2(r_s < 0.0f, r_p < 0.0f) * M_PI_F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return squared amplitude to get the fraction of reflected energy. */
|
|
|
|
|
return make_float2(sqr(r_s), sqr(r_p));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute fresnel reflectance for unpolarized light. */
|
|
|
|
|
ccl_device_forceinline float fresnel_dielectric(float cos_theta_i,
|
|
|
|
|
float eta,
|
|
|
|
|
ccl_private float *r_cos_theta_t)
|
|
|
|
|
{
|
|
|
|
|
return average(fresnel_dielectric_polarized(cos_theta_i, eta, r_cos_theta_t, nullptr));
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Refract the incident ray, given the cosine of the refraction angle and the relative refractive
|
|
|
|
|
* index of the incoming medium w.r.t. the outgoing medium. */
|
|
|
|
|
ccl_device_inline float3 refract_angle(const float3 incident,
|
|
|
|
|
const float3 normal,
|
|
|
|
|
const float cos_theta_t,
|
|
|
|
|
const float inv_eta)
|
|
|
|
|
{
|
|
|
|
|
return (inv_eta * dot(normal, incident) + cos_theta_t) * normal - inv_eta * incident;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-16 00:17:10 +01:00
|
|
|
ccl_device float fresnel_dielectric_cos(float cosi, float eta)
|
2012-12-15 10:18:42 +00:00
|
|
|
{
|
|
|
|
|
// compute fresnel reflectance without explicitly computing
|
|
|
|
|
// the refracted direction
|
|
|
|
|
float c = fabsf(cosi);
|
|
|
|
|
float g = eta * eta - 1 + c * c;
|
|
|
|
|
if (g > 0) {
|
|
|
|
|
g = sqrtf(g);
|
|
|
|
|
float A = (g - c) / (g + c);
|
|
|
|
|
float B = (c * (g + c) - 1) / (c * (g - c) + 1);
|
|
|
|
|
return 0.5f * A * A * (1 + B * B);
|
|
|
|
|
}
|
|
|
|
|
return 1.0f; // TIR(no refracted component)
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 04:23:20 +01:00
|
|
|
ccl_device Spectrum fresnel_conductor(float cosi, const Spectrum eta, const Spectrum k)
|
2012-12-15 10:18:42 +00:00
|
|
|
{
|
2023-02-06 04:23:20 +01:00
|
|
|
Spectrum cosi2 = make_spectrum(cosi * cosi);
|
|
|
|
|
Spectrum one = make_spectrum(1.0f);
|
|
|
|
|
Spectrum tmp_f = eta * eta + k * k;
|
|
|
|
|
Spectrum tmp = tmp_f * cosi2;
|
|
|
|
|
Spectrum Rparl2 = (tmp - (2.0f * eta * cosi) + one) / (tmp + (2.0f * eta * cosi) + one);
|
|
|
|
|
Spectrum Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / (tmp_f + (2.0f * eta * cosi) + cosi2);
|
2012-12-15 10:18:42 +00:00
|
|
|
return (Rparl2 + Rperp2) * 0.5f;
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
ccl_device float ior_from_F0(float f0)
|
2023-02-06 04:23:20 +01:00
|
|
|
{
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
const float sqrt_f0 = sqrtf(clamp(f0, 0.0f, 0.99f));
|
2023-02-06 04:23:20 +01:00
|
|
|
return (1.0f + sqrt_f0) / (1.0f - sqrt_f0);
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Remove MultiGGX code, replace with albedo scaling
While the multiscattering GGX code is cool and solves the darkening problem at higher roughnesses, it's also currently buggy, hard to maintain and often impractical to use due to the higher noise and render time.
In practice, though, having the exact correct directional distribution is not that important as long as the overall albedo is correct and we a) don't get the darkening effect and b) do get the saturation effect at higher roughnesses.
This can simply be achieved by adding a second lobe (https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf) or scaling the single-scattering GGX lobe (https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf). Both approaches require the same precomputation and produce outputs of comparable quality, so I went for the simple albedo scaling since it's easier to implement and more efficient.
Overall, the results are pretty good: All scenarios that I tested (Glossy BSDF, Glass BSDF, Principled BSDF with metallic or transmissive = 1) pass the white furnace test (a material with pure-white color in front of a pure-white background should be indistinguishable from the background if it preserves energy), and the overall albedo for non-white materials matches that produced by the real multi-scattering code (with the expected saturation increase as the roughness increases).
In order to produce the precomputed tables, the PR also includes a utility that computes them. This is not built by default, since there's no reason for a user to run it (it only makes sense for documentation/reproducibility purposes and when making changes to the microfacet models).
Pull Request: https://projects.blender.org/blender/blender/pulls/107958
2023-06-05 02:20:57 +02:00
|
|
|
ccl_device float F0_from_ior(float ior)
|
|
|
|
|
{
|
|
|
|
|
return sqr((ior - 1.0f) / (ior + 1.0f));
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 11:43:09 +02:00
|
|
|
ccl_device float schlick_fresnel(float u)
|
|
|
|
|
{
|
|
|
|
|
float m = clamp(1.0f - u, 0.0f, 1.0f);
|
|
|
|
|
float m2 = m * m;
|
|
|
|
|
return m2 * m2 * m; // pow(m, 5)
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-24 03:53:32 +01:00
|
|
|
/* Calculate the fresnel color, which is a blend between white and the F0 color */
|
2023-02-06 12:32:45 +11:00
|
|
|
ccl_device_forceinline Spectrum interpolate_fresnel_color(float3 L,
|
|
|
|
|
float3 H,
|
|
|
|
|
float ior,
|
|
|
|
|
Spectrum F0)
|
2017-04-18 11:43:09 +02:00
|
|
|
{
|
2023-01-24 03:53:32 +01:00
|
|
|
/* Compute the real Fresnel term and remap it from real_F0..1 to F0..1.
|
|
|
|
|
* The reason why we use this remapping instead of directly doing the
|
2023-05-12 19:55:46 +02:00
|
|
|
* Schlick approximation mix(F0, 1.0, (1.0-cosLH)^5) is that for cases
|
2023-01-24 03:53:32 +01:00
|
|
|
* with similar IORs (e.g. ice in water), the relative IOR can be close
|
|
|
|
|
* enough to 1.0 that the Schlick approximation becomes inaccurate. */
|
|
|
|
|
float real_F = fresnel_dielectric_cos(dot(L, H), ior);
|
|
|
|
|
float real_F0 = fresnel_dielectric_cos(1.0f, ior);
|
2017-04-18 11:43:09 +02:00
|
|
|
|
2023-01-24 03:53:32 +01:00
|
|
|
return mix(F0, one_spectrum(), inverse_lerp(real_F0, 1.0f, real_F));
|
2017-04-18 11:43:09 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-20 13:19:01 +01:00
|
|
|
/* If the shading normal results in specular reflection in the lower hemisphere, raise the shading
|
|
|
|
|
* normal towards the geometry normal so that the specular reflection is just above the surface.
|
|
|
|
|
* Only used for glossy materials. */
|
|
|
|
|
ccl_device float3 ensure_valid_specular_reflection(float3 Ng, float3 I, float3 N)
|
2021-10-24 14:19:19 +02:00
|
|
|
{
|
2023-03-14 12:20:15 +01:00
|
|
|
const float3 R = 2 * dot(N, I) * N - I;
|
|
|
|
|
|
|
|
|
|
const float Iz = dot(I, Ng);
|
2023-11-21 18:38:45 +01:00
|
|
|
kernel_assert(Iz >= 0);
|
2021-10-24 14:19:19 +02:00
|
|
|
|
|
|
|
|
/* Reflection rays may always be at least as shallow as the incoming ray. */
|
2023-03-14 12:20:15 +01:00
|
|
|
const float threshold = min(0.9f * Iz, 0.01f);
|
2021-10-24 14:19:19 +02:00
|
|
|
if (dot(Ng, R) >= threshold) {
|
|
|
|
|
return N;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane.
|
|
|
|
|
* The X axis is found by normalizing the component of N that's orthogonal to Ng.
|
|
|
|
|
* The Y axis isn't actually needed.
|
|
|
|
|
*/
|
2024-01-02 16:24:04 +01:00
|
|
|
const float3 X = safe_normalize_fallback(N - dot(N, Ng) * Ng, N);
|
2021-10-24 14:19:19 +02:00
|
|
|
|
|
|
|
|
/* Calculate N.z and N.x in the local coordinate system.
|
|
|
|
|
*
|
|
|
|
|
* The goal of this computation is to find a N' that is rotated towards Ng just enough
|
|
|
|
|
* to lift R' above the threshold (here called t), therefore dot(R', Ng) = t.
|
|
|
|
|
*
|
|
|
|
|
* According to the standard reflection equation,
|
|
|
|
|
* this means that we want dot(2*dot(N', I)*N' - I, Ng) = t.
|
|
|
|
|
*
|
|
|
|
|
* Since the Z axis of our local coordinate system is Ng, dot(x, Ng) is just x.z, so we get
|
|
|
|
|
* 2*dot(N', I)*N'.z - I.z = t.
|
|
|
|
|
*
|
|
|
|
|
* The rotation is simple to express in the coordinate system we formed -
|
|
|
|
|
* since N lies in the X-Z-plane, we know that N' will also lie in the X-Z-plane,
|
|
|
|
|
* so N'.y = 0 and therefore dot(N', I) = N'.x*I.x + N'.z*I.z .
|
|
|
|
|
*
|
|
|
|
|
* Furthermore, we want N' to be normalized, so N'.x = sqrt(1 - N'.z^2).
|
|
|
|
|
*
|
2023-03-14 12:20:15 +01:00
|
|
|
* With these simplifications, we get the equation
|
|
|
|
|
* 2*(sqrt(1 - N'.z^2)*I.x + N'.z*I.z)*N'.z - I.z = t,
|
|
|
|
|
* or
|
|
|
|
|
* 2*sqrt(1 - N'.z^2)*I.x*N'.z = t + I.z * (1 - 2*N'.z^2),
|
|
|
|
|
* after rearranging terms.
|
|
|
|
|
* Raise both sides to the power of two and substitute terms with
|
|
|
|
|
* a = I.x^2 + I.z^2,
|
|
|
|
|
* b = 2*(a + Iz*t),
|
|
|
|
|
* c = (Iz + t)^2,
|
|
|
|
|
* we obtain
|
|
|
|
|
* 4*a*N'.z^4 - 2*b*N'.z^2 + c = 0.
|
2021-10-24 14:19:19 +02:00
|
|
|
*
|
|
|
|
|
* The only unknown here is N'.z, so we can solve for that.
|
|
|
|
|
*
|
2023-03-14 12:20:15 +01:00
|
|
|
* The equation has four solutions in general, two can immediately be discarded because they're
|
|
|
|
|
* negative so N' would lie in the lower hemisphere; one solves
|
|
|
|
|
* 2*sqrt(1 - N'.z^2)*I.x*N'.z = -(t + I.z * (1 - 2*N'.z^2))
|
|
|
|
|
* instead of the original equation (before squaring both sides).
|
|
|
|
|
* Therefore only one root is valid.
|
2021-10-24 14:19:19 +02:00
|
|
|
*/
|
|
|
|
|
|
2023-03-14 12:20:15 +01:00
|
|
|
const float Ix = dot(I, X);
|
|
|
|
|
|
|
|
|
|
const float a = sqr(Ix) + sqr(Iz);
|
|
|
|
|
const float b = 2.0f * (a + Iz * threshold);
|
|
|
|
|
const float c = sqr(threshold + Iz);
|
|
|
|
|
|
|
|
|
|
/* In order that the root formula solves 2*sqrt(1 - N'.z^2)*I.x*N'.z = t + I.z - 2*I.z*N'.z^2,
|
|
|
|
|
* Ix and (t + I.z * (1 - 2*N'.z^2)) must have the same sign (the rest terms are non-negative by
|
|
|
|
|
* definition). */
|
|
|
|
|
const float Nz2 = (Ix < 0) ? 0.25f * (b + safe_sqrtf(sqr(b) - 4.0f * a * c)) / a :
|
|
|
|
|
0.25f * (b - safe_sqrtf(sqr(b) - 4.0f * a * c)) / a;
|
|
|
|
|
|
|
|
|
|
const float Nx = safe_sqrtf(1.0f - Nz2);
|
|
|
|
|
const float Nz = safe_sqrtf(Nz2);
|
|
|
|
|
|
|
|
|
|
return Nx * X + Nz * Ng;
|
2021-10-24 14:19:19 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-20 13:19:01 +01:00
|
|
|
/* Do not call #ensure_valid_specular_reflection if the primitive type is curve or if the geometry
|
2023-03-14 17:02:09 +01:00
|
|
|
* normal and the shading normal is the same. */
|
2023-03-20 13:19:01 +01:00
|
|
|
ccl_device float3 maybe_ensure_valid_specular_reflection(ccl_private ShaderData *sd, float3 N)
|
2023-03-14 17:02:09 +01:00
|
|
|
{
|
2023-10-11 15:07:21 +02:00
|
|
|
if ((sd->flag & SD_USE_BUMP_MAP_CORRECTION) == 0) {
|
|
|
|
|
return N;
|
|
|
|
|
}
|
2023-03-14 17:02:09 +01:00
|
|
|
if ((sd->type & PRIMITIVE_CURVE) || isequal(sd->Ng, N)) {
|
|
|
|
|
return N;
|
|
|
|
|
}
|
2023-03-20 13:19:01 +01:00
|
|
|
return ensure_valid_specular_reflection(sd->Ng, sd->wi, N);
|
2023-03-14 17:02:09 +01:00
|
|
|
}
|
|
|
|
|
|
Cycles: new Principled Hair BSDF variant with elliptical cross-section support
Implements the paper [A Microfacet-based Hair Scattering
Model](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14588) by
Weizhen Huang, Matthias B. Hullin and Johannes Hanika.
### Features:
- This is a far-field model, as opposed to the previous near-field
Principled Hair BSDF model. The hair is expected to be less noisy, but
lower roughness values takes longer to render due to numerical
integration along the hair width. The hair also appears to be flat when
viewed up-close.
- The longitudinal width of the scattering lobe differs along the
azimuth, providing a higher contrast compared to the evenly spread
scattering in the near-field Principled Hair BSDF model. For a more
detailed comparison, please refer to the original paper.
- Supports elliptical cross-sections, adding more realism as human hairs
are usually elliptical. The orientation of the cross-section is aligned
with the curve normal, which can be adjusted using geometry nodes.
Default is minimal twist. During sampling, light rays that hit outside
the hair width will continue propogating as if the material is
transparent.
- There is non-physical modulation factors for the first three
lobes (Reflection, Transmission, Secondary Reflection).
### Missing:
- A good default for cross-section orientation. There was an
attempt (9039f76928) to default the orientation to align with the curve
normal in the mathematical sense, but the stability (when animated) is
unclear and it would be a hassle to generalise to all curve types. After
the model is in main, we could experiment with the geometry nodes team
to see what works the best as a default.
Co-authored-by: Lukas Stockner <lukas.stockner@freenet.de>
Pull Request: https://projects.blender.org/blender/blender/pulls/105600
2023-08-18 12:46:13 +02:00
|
|
|
/* Principled Hair albedo and absorption coefficients. */
|
|
|
|
|
ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
|
|
|
|
|
const float azimuthal_roughness)
|
|
|
|
|
{
|
|
|
|
|
const float x = azimuthal_roughness;
|
|
|
|
|
return (((((0.245f * x) + 5.574f) * x - 10.73f) * x + 2.532f) * x - 0.215f) * x + 5.969f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccl_device_inline Spectrum
|
|
|
|
|
bsdf_principled_hair_sigma_from_reflectance(const Spectrum color, const float azimuthal_roughness)
|
|
|
|
|
{
|
|
|
|
|
const Spectrum sigma = log(color) /
|
|
|
|
|
bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness);
|
|
|
|
|
return sigma * sigma;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccl_device_inline Spectrum bsdf_principled_hair_sigma_from_concentration(const float eumelanin,
|
|
|
|
|
const float pheomelanin)
|
|
|
|
|
{
|
|
|
|
|
const float3 eumelanin_color = make_float3(0.506f, 0.841f, 1.653f);
|
|
|
|
|
const float3 pheomelanin_color = make_float3(0.343f, 0.733f, 1.924f);
|
|
|
|
|
|
|
|
|
|
return eumelanin * rgb_to_spectrum(eumelanin_color) +
|
|
|
|
|
pheomelanin * rgb_to_spectrum(pheomelanin_color);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-19 13:12:43 +02:00
|
|
|
/* Computes the weight for base closure(s) which are layered under another closure.
|
|
|
|
|
* layer_albedo is an estimate of the top layer's reflectivity, while weight is the closure weight
|
|
|
|
|
* of the entire base+top combination. */
|
|
|
|
|
ccl_device_inline Spectrum closure_layering_weight(const Spectrum layer_albedo,
|
|
|
|
|
const Spectrum weight)
|
|
|
|
|
{
|
|
|
|
|
return weight * saturatef(1.0f - reduce_max(safe_divide_color(layer_albedo, weight)));
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
/* ******** Thin-film iridescence implementation ********
|
|
|
|
|
*
|
|
|
|
|
* Based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence"
|
|
|
|
|
* by Laurent Belcour and Pascal Barla.
|
|
|
|
|
* https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html.
|
|
|
|
|
*/
|
|
|
|
|
|
2024-05-03 11:06:22 +10:00
|
|
|
/**
|
|
|
|
|
* Evaluate the sensitivity functions for the Fourier-space spectral integration.
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
* The code here uses the Gaussian fit for the CIE XYZ curves that is provided
|
|
|
|
|
* in the reference implementation.
|
|
|
|
|
* For details on what this actually represents, see the paper.
|
|
|
|
|
* In theory we should pre-compute the sensitivity functions for the working RGB
|
2024-05-03 11:06:22 +10:00
|
|
|
* color-space, remap them to be functions of (light) frequency, take their Fourier
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
* transform and store them as a LUT that gets looked up here.
|
2024-05-03 11:06:22 +10:00
|
|
|
* In practice, using the XYZ fit and converting the result from XYZ to RGB is easier.
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
*/
|
|
|
|
|
ccl_device_inline Spectrum iridescence_lookup_sensitivity(float OPD, float shift)
|
|
|
|
|
{
|
|
|
|
|
float phase = M_2PI_F * OPD * 1e-9f;
|
|
|
|
|
float3 val = make_float3(5.4856e-13f, 4.4201e-13f, 5.2481e-13f);
|
|
|
|
|
float3 pos = make_float3(1.6810e+06f, 1.7953e+06f, 2.2084e+06f);
|
|
|
|
|
float3 var = make_float3(4.3278e+09f, 9.3046e+09f, 6.6121e+09f);
|
|
|
|
|
|
|
|
|
|
float3 xyz = val * sqrt(M_2PI_F * var) * cos(pos * phase + shift) * exp(-sqr(phase) * var);
|
|
|
|
|
xyz.x += 1.64408e-8f * cosf(2.2399e+06f * phase + shift) * expf(-4.5282e+09f * sqr(phase));
|
|
|
|
|
return xyz / 1.0685e-7f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccl_device_inline float3
|
|
|
|
|
iridescence_airy_summation(float T121, float R12, float R23, float OPD, float phi)
|
|
|
|
|
{
|
|
|
|
|
if (R23 == 1.0f) {
|
|
|
|
|
/* Shortcut for TIR on the bottom interface. */
|
|
|
|
|
return one_float3();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float R123 = R12 * R23;
|
|
|
|
|
float r123 = sqrtf(R123);
|
|
|
|
|
float Rs = sqr(T121) * R23 / (1.0f - R123);
|
|
|
|
|
|
|
|
|
|
/* Perform summation over path order differences (equation 10). */
|
|
|
|
|
float3 R = make_float3(R12 + Rs); /* C0 */
|
|
|
|
|
float Cm = (Rs - T121);
|
|
|
|
|
/* Truncate after m=3, higher differences have barely any impact. */
|
|
|
|
|
for (int m = 1; m < 4; m++) {
|
|
|
|
|
Cm *= r123;
|
|
|
|
|
R += Cm * 2.0f * iridescence_lookup_sensitivity(m * OPD, m * phi);
|
|
|
|
|
}
|
|
|
|
|
return R;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccl_device Spectrum fresnel_iridescence(KernelGlobals kg,
|
|
|
|
|
float eta1,
|
|
|
|
|
float eta2,
|
|
|
|
|
float eta3,
|
|
|
|
|
float cos_theta_1,
|
|
|
|
|
float thickness,
|
|
|
|
|
ccl_private float *r_cos_theta_3)
|
|
|
|
|
{
|
|
|
|
|
/* For films below 30nm, the wave-optic-based Airy summation approach no longer applies,
|
|
|
|
|
* so blend towards the case without coating. */
|
|
|
|
|
if (thickness < 30.0f) {
|
|
|
|
|
eta2 = mix(eta1, eta2, smoothstep(0.0f, 30.0f, thickness));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float cos_theta_2;
|
|
|
|
|
float2 phi12, phi23;
|
|
|
|
|
|
|
|
|
|
/* Compute reflection at the top interface (ambient to film). */
|
|
|
|
|
float2 R12 = fresnel_dielectric_polarized(cos_theta_1, eta2 / eta1, &cos_theta_2, &phi12);
|
|
|
|
|
if (isequal(R12, one_float2())) {
|
|
|
|
|
/* TIR at the top interface. */
|
|
|
|
|
return one_spectrum();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute optical path difference inside the thin film. */
|
|
|
|
|
float OPD = -2.0f * eta2 * thickness * cos_theta_2;
|
|
|
|
|
|
|
|
|
|
/* Compute reflection at the bottom interface (film to medium). */
|
|
|
|
|
float2 R23 = fresnel_dielectric_polarized(-cos_theta_2, eta3 / eta2, r_cos_theta_3, &phi23);
|
|
|
|
|
if (isequal(R23, one_float2())) {
|
|
|
|
|
/* TIR at the bottom interface.
|
|
|
|
|
* All the Airy summation math still simplifies to 1.0 in this case. */
|
|
|
|
|
return one_spectrum();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute helper parameters. */
|
|
|
|
|
float2 T121 = one_float2() - R12;
|
|
|
|
|
float2 phi = make_float2(M_PI_F, M_PI_F) - phi12 + phi23;
|
|
|
|
|
|
|
|
|
|
/* Perform Airy summation and average the polarizations. */
|
|
|
|
|
float3 R = mix(iridescence_airy_summation(T121.x, R12.x, R23.x, OPD, phi.x),
|
|
|
|
|
iridescence_airy_summation(T121.y, R12.y, R23.y, OPD, phi.y),
|
|
|
|
|
0.5f);
|
|
|
|
|
|
|
|
|
|
/* Color space conversion here is tricky.
|
|
|
|
|
* In theory, the correct thing would be to compute the spectral color matching functions
|
|
|
|
|
* for the RGB channels, take their Fourier transform in wavelength parametrization, and
|
|
|
|
|
* then use that in iridescence_lookup_sensitivity().
|
|
|
|
|
* To avoid this complexity, the code here instead uses the reference implementation's
|
|
|
|
|
* Gaussian fit of the CIE XYZ curves. However, this means that at this point, R is in
|
|
|
|
|
* XYZ values, not RGB.
|
|
|
|
|
* Additionally, since I is a reflectivity, not a luminance, the spectral color matching
|
|
|
|
|
* functions should be multiplied by the reference illuminant. Since the fit is based on
|
|
|
|
|
* the "raw" CIE XYZ curves, the reference illuminant implicitly is a constant spectrum,
|
|
|
|
|
* meaning Illuminant E.
|
|
|
|
|
* Therefore, we can't just use the regular XYZ->RGB conversion here, we need to include
|
|
|
|
|
* a chromatic adaption from E to whatever the white point of the working color space is.
|
|
|
|
|
* The proper way to do this would be a Von Kries-style transform, but to keep it simple,
|
|
|
|
|
* we just multiply by the white point here.
|
|
|
|
|
*
|
2024-06-06 09:43:48 +10:00
|
|
|
* NOTE: The reference implementation sidesteps all this by just hard-coding a XYZ->CIE RGB
|
Cycles: Add thin film iridescence to Principled BSDF
This is an implementation of thin film iridescence in the Principled BSDF based on "A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence".
There are still several open topics that are left for future work:
- Currently, the thin film only affects dielectric Fresnel, not metallic. Properly specifying thin films on metals requires a proper conductive Fresnel term with complex IOR inputs, any attempt of trying to hack it into the F82 model we currently use for the Principled BSDF is fundamentally flawed. In the future, we'll add a node for proper conductive Fresnel, including thin films.
- The F0/F90 control is not very elegantly implemented right now. It fundamentally works, but enabling thin film while using a Specular Tint causes a jump in appearance since the models integrate it differently. Then again, thin film interference is a physical effect, so of course a non-physical tweak doesn't play nicely with it.
- The white point handling is currently quite crude. In short: The code computes XYZ values of the reflectance spectrum, but we'd need the XYZ values of the product of the reflectance spectrum and the neutral illuminant of the working color space. Currently, this is addressed by just dividing by the XYZ values of the illuminant, but it would be better to do a proper chromatic adaptation transform or to use the proper reference curves for the working space instead of the XYZ curves from the paper.
Pull Request: https://projects.blender.org/blender/blender/pulls/118477
2024-05-02 14:28:44 +02:00
|
|
|
* matrix. Since CIE RGB uses E as its white point, this sidesteps the chromatic adaption
|
|
|
|
|
* topic, but the primary colors don't match (unless you happen to actually work in CIE RGB.)
|
|
|
|
|
*/
|
|
|
|
|
R *= float4_to_float3(kernel_data.film.white_xyz);
|
|
|
|
|
return saturate(xyz_to_rgb(kg, R));
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-15 10:18:42 +00:00
|
|
|
CCL_NAMESPACE_END
|