Compositor: Perform LGG Color Balance in linear space

This patch adjusts the LGG Color Balance mode to operate in linear space
as opposed to sRGB space, which is more inline with other software and
is more expected to the user.

Versioning was added using pre and post gamma correction, but it is
very slightly different in the blacks because the gamma node only does
power correction.

Pull Request: https://projects.blender.org/blender/blender/pulls/147533
This commit is contained in:
Omar Emara
2025-10-07 17:04:34 +02:00
committed by Omar Emara
parent d343889930
commit a113121562
7 changed files with 105 additions and 27 deletions

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 102
#define BLENDER_FILE_SUBVERSION 103
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -2498,6 +2498,85 @@ static void sequencer_substitute_transform_effects(Scene *scene)
});
}
/* The LGG mode of the Color Balance node was being done in sRGB space, while now it is done in
* linear space. So a Gamma node will be added before and after the node to perform the adjustment
* in sRGB space. */
static void do_version_lift_gamma_gain_srgb_to_linear(bNodeTree &node_tree, bNode &node)
{
bNodeSocket *image_input = blender::bke::node_find_socket(node, SOCK_IN, "Image");
bNodeSocket *type_input = blender::bke::node_find_socket(node, SOCK_IN, "Type");
bNodeSocket *image_output = blender::bke::node_find_socket(node, SOCK_OUT, "Image");
/* Find the links going into and out of of the node. */
bNodeLink *image_input_link = nullptr;
bNodeLink *type_input_link = nullptr;
LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
if (link->tosock == image_input) {
image_input_link = link;
}
if (link->tosock == type_input) {
type_input_link = link;
}
}
if (type_input_link || !type_input ||
type_input->default_value_typed<bNodeSocketValueMenu>()->value != CMP_NODE_COLOR_BALANCE_LGG)
{
return;
}
bNode *inverse_gamma_node = blender::bke::node_add_static_node(
nullptr, node_tree, SH_NODE_GAMMA);
inverse_gamma_node->parent = node.parent;
inverse_gamma_node->location[0] = node.location[0];
inverse_gamma_node->location[1] = node.location[1];
bNodeSocket *inverse_gamma_color_input = blender::bke::node_find_socket(
*inverse_gamma_node, SOCK_IN, "Color");
copy_v4_v4(inverse_gamma_color_input->default_value_typed<bNodeSocketValueRGBA>()->value,
image_input->default_value_typed<bNodeSocketValueRGBA>()->value);
bNodeSocket *inverse_gamma_color_output = blender::bke::node_find_socket(
*inverse_gamma_node, SOCK_OUT, "Color");
bNodeSocket *inverse_gamma_input = blender::bke::node_find_socket(
*inverse_gamma_node, SOCK_IN, "Gamma");
inverse_gamma_input->default_value_typed<bNodeSocketValueFloat>()->value = 1.0f / 2.2f;
version_node_add_link(
node_tree, *inverse_gamma_node, *inverse_gamma_color_output, node, *image_input);
if (image_input_link) {
version_node_add_link(node_tree,
*image_input_link->fromnode,
*image_input_link->fromsock,
*inverse_gamma_node,
*inverse_gamma_color_input);
blender::bke::node_remove_link(&node_tree, *image_input_link);
}
bNode *gamma_node = blender::bke::node_add_static_node(nullptr, node_tree, SH_NODE_GAMMA);
gamma_node->parent = node.parent;
gamma_node->location[0] = node.location[0];
gamma_node->location[1] = node.location[1];
bNodeSocket *gamma_color_input = blender::bke::node_find_socket(*gamma_node, SOCK_IN, "Color");
bNodeSocket *gamma_color_output = blender::bke::node_find_socket(*gamma_node, SOCK_OUT, "Color");
bNodeSocket *gamma_input = blender::bke::node_find_socket(*gamma_node, SOCK_IN, "Gamma");
gamma_input->default_value_typed<bNodeSocketValueFloat>()->value = 2.2f;
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &node_tree.links) {
if (link->fromsock != image_output) {
continue;
}
version_node_add_link(
node_tree, *gamma_node, *gamma_color_output, *link->tonode, *link->tosock);
blender::bke::node_remove_link(&node_tree, *link);
}
version_node_add_link(node_tree, node, *image_output, *gamma_node, *gamma_color_input);
}
void do_versions_after_linking_500(FileData *fd, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 9)) {
@@ -3826,6 +3905,19 @@ void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 103)) {
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
if (node_tree->type == NTREE_COMPOSIT) {
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
if (node->type_legacy == CMP_NODE_COLORBALANCE) {
do_version_lift_gamma_gain_srgb_to_linear(*node_tree, *node);
}
}
}
}
FOREACH_NODETREE_END;
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@@ -2,7 +2,6 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_common_color_utils.glsl"
#include "gpu_shader_math_matrix_construct_lib.glsl"
#define CMP_NODE_COLOR_BALANCE_LGG 0
@@ -17,19 +16,14 @@ float4 lift_gamma_gain(const float4 color,
const float base_gain,
const float4 color_gain)
{
const float3 srgb_color = linear_rgb_to_srgb(color.rgb);
const float3 lift = base_lift + color_lift.xyz();
const float3 lift_balanced = ((srgb_color - 1.0f) * (2.0f - lift)) + 1.0f;
const float3 lift_balanced = ((color.xyz() - 1.0f) * (2.0f - lift)) + 1.0f;
const float3 gain = base_gain * color_gain.xyz();
float3 gain_balanced = lift_balanced * gain;
gain_balanced = max(gain_balanced, float3(0.0f));
float3 linear_color = srgb_to_linear_rgb(gain_balanced);
const float3 gain_balanced = max(float3(0.0f), lift_balanced * gain);
const float3 gamma = base_gamma * color_gamma.xyz();
float3 gamma_balanced = pow(linear_color, 1.0f / max(gamma, float3(1e-6)));
const float3 gamma_balanced = pow(gain_balanced, 1.0f / max(gamma, float3(1e-6)));
return float4(gamma_balanced, color.w);
}

View File

@@ -7,7 +7,6 @@
*/
#include "BLI_math_base.hh"
#include "BLI_math_color.h"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector.hh"
#include "BLI_math_vector_types.hh"
@@ -245,21 +244,14 @@ static float4 lift_gamma_gain(const float4 color,
const float base_gain,
const float4 color_gain)
{
float3 srgb_color;
linearrgb_to_srgb_v3_v3(srgb_color, color);
const float3 lift = base_lift + color_lift.xyz();
const float3 lift_balanced = ((srgb_color - 1.0f) * (2.0f - lift)) + 1.0f;
const float3 lift_balanced = ((color.xyz() - 1.0f) * (2.0f - lift)) + 1.0f;
const float3 gain = base_gain * color_gain.xyz();
float3 gain_balanced = lift_balanced * gain;
gain_balanced = math::max(gain_balanced, float3(0.0f));
float3 linear_color;
srgb_to_linearrgb_v3_v3(linear_color, gain_balanced);
const float3 gain_balanced = math::max(float3(0.0f), lift_balanced * gain);
const float3 gamma = base_gamma * color_gamma.xyz();
float3 gamma_balanced = math::pow(linear_color, 1.0f / math::max(gamma, float3(1e-6f)));
const float3 gamma_balanced = math::pow(gain_balanced, 1.0f / math::max(gamma, float3(1e-6f)));
return float4(gamma_balanced, color.w);
}