From bdb042c243a6cea13dc341be92c619298023a6f8 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Wed, 19 Jul 2023 21:02:20 +0300 Subject: [PATCH] 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. --- .../compositor_keying_compute_matte.glsl | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/source/blender/compositor/realtime_compositor/shaders/compositor_keying_compute_matte.glsl b/source/blender/compositor/realtime_compositor/shaders/compositor_keying_compute_matte.glsl index e3e6ab654ed..9f566508ed9 100644 --- a/source/blender/compositor/realtime_compositor/shaders/compositor_keying_compute_matte.glsl +++ b/source/blender/compositor/realtime_compositor/shaders/compositor_keying_compute_matte.glsl @@ -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);