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
This commit is contained in:
Weizhen Huang 2024-06-25 18:49:26 +02:00 committed by Weizhen Huang
parent 9b61673b46
commit 02e6985c62
6 changed files with 23 additions and 17 deletions

@ -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;
}

@ -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++) {

@ -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(

@ -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);
}

@ -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)

@ -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. */