From e6371491669b37f2f450f715303c66dca9eb7db0 Mon Sep 17 00:00:00 2001 From: Chris Eveleigh Date: Tue, 11 May 2021 22:06:10 +0200 Subject: [PATCH] Fix T72791: Cycles wrong results when mixing multiple random walk BSSRDFs Take into account the closure sample weight for the throughput. Differential Revision: https://developer.blender.org/D10936 --- intern/cycles/kernel/kernel_subsurface.h | 36 ++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index b70df747a73..dd922b86722 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -25,8 +25,9 @@ CCL_NAMESPACE_BEGIN ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, float r, bool all) { - /* this is the veach one-sample model with balance heuristic, some pdf - * factors drop out when using balance heuristic weighting */ + /* This is the Veach one-sample model with balance heuristic, some pdf + * factors drop out when using balance heuristic weighting. For branched + * path tracing (all) we sample all closure and don't use MIS. */ float3 eval_sum = zero_float3(); float pdf_sum = 0.0f; float sample_weight_inv = 0.0f; @@ -65,6 +66,30 @@ subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, f return (pdf_sum > 0.0f) ? eval_sum / pdf_sum : zero_float3(); } +ccl_device_inline float3 subsurface_scatter_walk_eval(ShaderData *sd, + const ShaderClosure *sc, + float3 throughput, + bool all) +{ + /* This is the Veach one-sample model with balance heuristic, some pdf + * factors drop out when using balance heuristic weighting. For branched + * path tracing (all) we sample all closure and don't use MIS. */ + if (!all) { + float bssrdf_weight = 0.0f; + float weight = sc->sample_weight; + + for (int i = 0; i < sd->num_closure; i++) { + sc = &sd->closure[i]; + + if (CLOSURE_IS_BSSRDF(sc->type)) { + bssrdf_weight += sc->sample_weight; + } + } + throughput *= bssrdf_weight / weight; + } + return throughput; +} + /* replace closures with a single diffuse bsdf closure after scatter step */ ccl_device void subsurface_scatter_setup_diffuse_bsdf( KernelGlobals *kg, ShaderData *sd, ClosureType type, float roughness, float3 weight, float3 N) @@ -437,7 +462,8 @@ ccl_device_noinline ccl_addr_space PathState *state, const ShaderClosure *sc, const float bssrdf_u, - const float bssrdf_v) + const float bssrdf_v, + bool all) { /* Sample diffuse surface scatter into the object. */ float3 D; @@ -669,7 +695,7 @@ ccl_device_noinline /* TODO: gain back performance lost from merging with disk BSSRDF. We * only need to return on hit so this indirect ray push/pop overhead * is not actually needed, but it does keep the code simpler. */ - ss_isect->weight[0] = throughput; + ss_isect->weight[0] = subsurface_scatter_walk_eval(sd, sc, throughput, all); #ifdef __SPLIT_KERNEL__ ss_isect->ray = *ray; #endif @@ -691,7 +717,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect(KernelGlobals *kg, return subsurface_scatter_disk(kg, ss_isect, sd, sc, lcg_state, bssrdf_u, bssrdf_v, all); } else { - return subsurface_random_walk(kg, ss_isect, sd, state, sc, bssrdf_u, bssrdf_v); + return subsurface_random_walk(kg, ss_isect, sd, state, sc, bssrdf_u, bssrdf_v, all); } }