Fix #109868: Keying node differ between GPU and CPU

The Keying node produces different mattes between the GPU and CPU
evaluators.

That's because the CPU implementation doesn't use the full argmax to
determine indices, rather, it only considers the first argmax and uses
the minimum and maximum of the other two as a form of determinism or
stability.

The algorithm seems arbitrary and makes little sense to me, so for now,
the CPU implementation was ported for consistent results.
This commit is contained in:
Omar Emara
2023-07-19 21:02:20 +03:00
parent ece704af45
commit bdb042c243

View File

@@ -2,10 +2,19 @@
#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
float compute_saturation(vec4 color, ivec3 argmax)
ivec3 compute_saturation_indices(vec3 v)
{
float weighted_average = mix(color[argmax.y], color[argmax.z], key_balance);
return (color[argmax.x] - weighted_average) * abs(1.0 - weighted_average);
int index_of_max = ((v.x > v.y) ? ((v.x > v.z) ? 0 : 2) : ((v.y > v.z) ? 1 : 2));
ivec2 other_indices = ivec2(mod(ivec2(index_of_max) + ivec2(1, 2), ivec2(3)));
int min_index = min(other_indices.x, other_indices.y);
int max_index = max(other_indices.x, other_indices.y);
return ivec3(index_of_max, max_index, min_index);
}
float compute_saturation(vec4 color, ivec3 indices)
{
float weighted_average = mix(color[indices.y], color[indices.z], key_balance);
return (color[indices.x] - weighted_average) * abs(1.0 - weighted_average);
}
void main()
@@ -22,9 +31,9 @@ void main()
}
vec4 key_color = texture_load(key_tx, texel);
ivec3 key_argmax = argmax(key_color.rgb);
float input_saturation = compute_saturation(input_color, key_argmax);
float key_saturation = compute_saturation(key_color, key_argmax);
ivec3 key_saturation_indices = compute_saturation_indices(key_color.rgb);
float input_saturation = compute_saturation(input_color, key_saturation_indices);
float key_saturation = compute_saturation(key_color, key_saturation_indices);
float matte = 1.0f - clamp(input_saturation / key_saturation, 0.0, 1.0);