Cycles: improve SSS Fresnel and retro-reflection in Principled BSDF

For details see the "Extending the Disney BRDF to a BSDF with Integrated
Subsurface Scattering" paper.

We split the diffuse BSDF into a lambertian and retro-reflection component.
The retro-reflection component is always handled as a BSDF, while the
lambertian component can be replaced by a BSSRDF.

For the BSSRDF case, we compute Fresnel separately at the entry and exit
points, which may have different normals. As the scattering radius decreases
this converges to the BSDF case.

A downside is that this increases noise for subsurface scattering in the
Principled BSDF, due to some samples going to the retro-reflection component.
However the previous logic (also in 2.93) was simple wrong, using a
non-sensical view direction vector at the exit point. We use an importance
sampling weight estimate for the retro-reflection to try to better balance
samples between the BSDF and BSSRDF.

Differential Revision: https://developer.blender.org/D12801
This commit is contained in:
Brecht Van Lommel
2021-10-08 19:44:56 +02:00
parent 73a05ff9e8
commit a94343a8af
10 changed files with 125 additions and 77 deletions

View File

@@ -159,7 +159,7 @@ ccl_device_forceinline bool _shader_bsdf_exclude(ClosureType type, uint light_sh
return false;
}
if (light_shader_flags & SHADER_EXCLUDE_DIFFUSE) {
if (CLOSURE_IS_BSDF_DIFFUSE(type) || CLOSURE_IS_BSDF_BSSRDF(type)) {
if (CLOSURE_IS_BSDF_DIFFUSE(type)) {
return true;
}
}
@@ -201,8 +201,7 @@ ccl_device_inline float _shader_bsdf_multi_eval(const KernelGlobals *kg,
float3 eval = bsdf_eval(kg, sd, sc, omega_in, is_transmission, &bsdf_pdf);
if (bsdf_pdf != 0.0f) {
const bool is_diffuse = (CLOSURE_IS_BSDF_DIFFUSE(sc->type) ||
CLOSURE_IS_BSDF_BSSRDF(sc->type));
const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type);
bsdf_eval_accum(result_eval, is_diffuse, eval * sc->weight, 1.0f);
sum_pdf += bsdf_pdf * sc->sample_weight;
}
@@ -320,8 +319,7 @@ ccl_device int shader_bsdf_sample_closure(const KernelGlobals *kg,
label = bsdf_sample(kg, sd, sc, randu, randv, &eval, omega_in, domega_in, pdf);
if (*pdf != 0.0f) {
const bool is_diffuse = (CLOSURE_IS_BSDF_DIFFUSE(sc->type) ||
CLOSURE_IS_BSDF_BSSRDF(sc->type));
const bool is_diffuse = CLOSURE_IS_BSDF_DIFFUSE(sc->type);
bsdf_eval_init(bsdf_eval, is_diffuse, eval * sc->weight);
if (sd->num_closure > 1) {
@@ -401,8 +399,7 @@ ccl_device float3 shader_bsdf_diffuse(const KernelGlobals *kg, const ShaderData
for (int i = 0; i < sd->num_closure; i++) {
const ShaderClosure *sc = &sd->closure[i];
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type) ||
CLOSURE_IS_BSDF_BSSRDF(sc->type))
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type))
eval += sc->weight;
}