From 02e6985c628bbf7802c54ee5c55666ed57d058bc Mon Sep 17 00:00:00 2001 From: Weizhen Huang Date: Tue, 25 Jun 2024 18:49:26 +0200 Subject: [PATCH] Fix #94323: Cycles blocky artifacts in overlapping volumes due to scale difference when computing coefficients in volume, the volume density of the object at the top of the stack is used, which leads to wrong result if overlapping volumes have different scales. This commit fixes the problem by pre-multiplying the volume density per object when evaluating the shader. Pull Request: https://projects.blender.org/blender/blender/pulls/123733 --- intern/cycles/kernel/integrator/shade_volume.h | 8 +------- intern/cycles/kernel/integrator/volume_shader.h | 2 +- intern/cycles/kernel/osl/closures_setup.h | 6 +++++- intern/cycles/kernel/svm/closure.h | 16 +++++++++++----- intern/cycles/kernel/svm/svm.h | 2 +- intern/cycles/kernel/types.h | 6 ++++-- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 963da894f76..14d7d317914 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -82,8 +82,7 @@ ccl_device_inline bool shadow_volume_shader_sample(KernelGlobals kg, return false; } - const float density = object_volume_density(kg, sd->object); - *extinction = sd->closure_transparent_extinction * density; + *extinction = sd->closure_transparent_extinction; return true; } @@ -116,11 +115,6 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals kg, } } - const float density = object_volume_density(kg, sd->object); - coeff->sigma_s *= density; - coeff->sigma_t *= density; - coeff->emission *= density; - return true; } diff --git a/intern/cycles/kernel/integrator/volume_shader.h b/intern/cycles/kernel/integrator/volume_shader.h index 23493562fe8..ca36df1b95f 100644 --- a/intern/cycles/kernel/integrator/volume_shader.h +++ b/intern/cycles/kernel/integrator/volume_shader.h @@ -465,7 +465,7 @@ ccl_device_inline void volume_shader_eval(KernelGlobals kg, * for all volumes in the stack into a single array of closures */ sd->num_closure = 0; sd->num_closure_left = max_closures; - sd->flag = 0; + sd->flag = SD_IS_VOLUME_SHADER_EVAL; sd->object_flag = 0; for (int i = 0;; i++) { diff --git a/intern/cycles/kernel/osl/closures_setup.h b/intern/cycles/kernel/osl/closures_setup.h index 970e4d8916c..764abc96ac8 100644 --- a/intern/cycles/kernel/osl/closures_setup.h +++ b/intern/cycles/kernel/osl/closures_setup.h @@ -749,6 +749,9 @@ ccl_device void osl_closure_emission_setup(KernelGlobals kg, ccl_private const GenericEmissiveClosure *closure, float3 *layer_albedo) { + if (sd->flag & SD_IS_VOLUME_SHADER_EVAL) { + weight *= object_volume_density(kg, sd->object); + } emission_setup(sd, rgb_to_spectrum(weight)); } @@ -1031,7 +1034,7 @@ ccl_device void osl_closure_absorption_setup(KernelGlobals kg, ccl_private const VolumeAbsorptionClosure *closure, float3 *layer_albedo) { - volume_extinction_setup(sd, rgb_to_spectrum(weight)); + volume_extinction_setup(sd, rgb_to_spectrum(weight * object_volume_density(kg, sd->object))); } ccl_device void osl_closure_henyey_greenstein_setup( @@ -1042,6 +1045,7 @@ ccl_device void osl_closure_henyey_greenstein_setup( ccl_private const VolumeHenyeyGreensteinClosure *closure, float3 *layer_albedo) { + weight *= object_volume_density(kg, sd->object); volume_extinction_setup(sd, rgb_to_spectrum(weight)); ccl_private HenyeyGreensteinVolume *volume = (ccl_private HenyeyGreensteinVolume *)bsdf_alloc( diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index 24da8869a4d..ac494366928 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -935,7 +935,7 @@ ccl_device_noinline void svm_node_closure_volume(KernelGlobals kg, float density = (stack_valid(density_offset)) ? stack_load_float(stack, density_offset) : __uint_as_float(node.z); - density = mix_weight * fmaxf(density, 0.0f); + density = mix_weight * fmaxf(density, 0.0f) * object_volume_density(kg, sd->object); /* Compute scattering coefficient. */ Spectrum weight = closure_weight; @@ -997,7 +997,7 @@ ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg, float primitive_density = 1.0f; float density = (stack_valid(density_offset)) ? stack_load_float(stack, density_offset) : __uint_as_float(value_node.x); - density = mix_weight * fmaxf(density, 0.0f); + density = mix_weight * fmaxf(density, 0.0f) * object_volume_density(kg, sd->object); if (density > CLOSURE_WEIGHT_CUTOFF) { /* Density and color attribute lookup if available. */ @@ -1055,7 +1055,8 @@ ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg, if (emission > CLOSURE_WEIGHT_CUTOFF) { float3 emission_color = stack_load_float3(stack, emission_color_offset); - emission_setup(sd, rgb_to_spectrum(emission * emission_color)); + emission_setup( + sd, rgb_to_spectrum(emission * emission_color * object_volume_density(kg, sd->object))); } if (blackbody > CLOSURE_WEIGHT_CUTOFF) { @@ -1079,14 +1080,15 @@ ccl_device_noinline int svm_node_principled_volume(KernelGlobals kg, float3 blackbody_tint = stack_load_float3(stack, node.w); float3 bb = blackbody_tint * intensity * rec709_to_rgb(kg, svm_math_blackbody_color_rec709(T)); - emission_setup(sd, rgb_to_spectrum(bb)); + emission_setup(sd, rgb_to_spectrum(bb * object_volume_density(kg, sd->object))); } } #endif return offset; } -ccl_device_noinline void svm_node_closure_emission(ccl_private ShaderData *sd, +ccl_device_noinline void svm_node_closure_emission(KernelGlobals kg, + ccl_private ShaderData *sd, ccl_private float *stack, Spectrum closure_weight, uint4 node) @@ -1104,6 +1106,10 @@ ccl_device_noinline void svm_node_closure_emission(ccl_private ShaderData *sd, weight *= mix_weight; } + if (sd->flag & SD_IS_VOLUME_SHADER_EVAL) { + weight *= object_volume_density(kg, sd->object); + } + emission_setup(sd, weight); } diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index df95cef8b5e..c13d20596f9 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -254,7 +254,7 @@ ccl_device void svm_eval_nodes(KernelGlobals kg, SVM_CASE(NODE_CLOSURE_EMISSION) IF_KERNEL_NODES_FEATURE(EMISSION) { - svm_node_closure_emission(sd, stack, closure_weight, node); + svm_node_closure_emission(kg, sd, stack, closure_weight, node); } break; SVM_CASE(NODE_CLOSURE_BACKGROUND) diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 1693d685799..a7790e74837 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -1024,6 +1024,8 @@ enum ShaderDataFlag { SD_EXTINCTION = (1 << 6), /* Shader has have volume phase (scatter) closure. */ SD_SCATTER = (1 << 7), + /* Shader is being evaluated in a volume. */ + SD_IS_VOLUME_SHADER_EVAL = (1 << 8), /* Shader has transparent closure. */ SD_TRANSPARENT = (1 << 9), /* BSDF requires LCG for evaluation. */ @@ -1034,8 +1036,8 @@ enum ShaderDataFlag { SD_RAY_PORTAL = (1 << 12), SD_CLOSURE_FLAGS = (SD_EMISSION | SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSSRDF | SD_HOLDOUT | - SD_EXTINCTION | SD_SCATTER | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION | - SD_RAY_PORTAL), + SD_EXTINCTION | SD_SCATTER | SD_IS_VOLUME_SHADER_EVAL | SD_BSDF_NEEDS_LCG | + SD_BSDF_HAS_TRANSMISSION | SD_RAY_PORTAL), /* Shader flags. */