diff options
author | Brecht Van Lommel <brecht@blender.org> | 2021-10-08 20:44:56 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2021-10-11 19:22:54 +0300 |
commit | a94343a8afcac5d6db09c8461e67ad1ba5a85d35 (patch) | |
tree | f56b8e6a956ca87f25b01f94b6f6421636448402 /intern/cycles/kernel/closure/bssrdf.h | |
parent | 73a05ff9e83a31be34d32a92cd5fb4d17994e342 (diff) |
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
Diffstat (limited to 'intern/cycles/kernel/closure/bssrdf.h')
-rw-r--r-- | intern/cycles/kernel/closure/bssrdf.h | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h index db183887018..d2f8af7910c 100644 --- a/intern/cycles/kernel/closure/bssrdf.h +++ b/intern/cycles/kernel/closure/bssrdf.h @@ -277,10 +277,27 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight) ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type, const float ior) { int flag = 0; + + /* Add retro-reflection component as separate diffuse BSDF. */ + if (bssrdf->roughness != FLT_MAX) { + PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf *)bsdf_alloc( + sd, sizeof(PrincipledDiffuseBsdf), bssrdf->weight); + + if (bsdf) { + bsdf->N = bssrdf->N; + bsdf->roughness = bssrdf->roughness; + flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_RETRO_REFLECTION); + + /* Ad-hoc weight adjusment to avoid retro-reflection taking away half the + * samples from BSSRDF. */ + bsdf->sample_weight *= bsdf_principled_diffuse_retro_reflection_sample_weight(bsdf, sd->I); + } + } + + /* Verify if the radii are large enough to sample without precision issues. */ int bssrdf_channels = 3; float3 diffuse_weight = make_float3(0.0f, 0.0f, 0.0f); - /* Verify if the radii are large enough to sample without precision issues. */ if (bssrdf->radius.x < BSSRDF_MIN_RADIUS) { diffuse_weight.x = bssrdf->weight.x; bssrdf->weight.x = 0.0f; @@ -304,17 +321,13 @@ ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type, co /* Add diffuse BSDF if any radius too small. */ #ifdef __PRINCIPLED__ if (bssrdf->roughness != FLT_MAX) { - float roughness = bssrdf->roughness; - float3 N = bssrdf->N; - PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf *)bsdf_alloc( sd, sizeof(PrincipledDiffuseBsdf), diffuse_weight); if (bsdf) { - bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID; - bsdf->N = N; - bsdf->roughness = roughness; - flag |= bsdf_principled_diffuse_setup(bsdf); + bsdf->N = bssrdf->N; + bsdf->roughness = bssrdf->roughness; + flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_LAMBERT); } } else @@ -323,7 +336,6 @@ ccl_device int bssrdf_setup(ShaderData *sd, Bssrdf *bssrdf, ClosureType type, co DiffuseBsdf *bsdf = (DiffuseBsdf *)bsdf_alloc(sd, sizeof(DiffuseBsdf), diffuse_weight); if (bsdf) { - bsdf->type = CLOSURE_BSDF_BSSRDF_ID; bsdf->N = bssrdf->N; flag |= bsdf_diffuse_setup(bsdf); } |