[Bf-blender-cvs] [6109ad6cce9] master: Realtime Compositor: Add basic color nodes

Omar Emara noreply at git.blender.org
Wed Aug 10 10:00:46 CEST 2022


Commit: 6109ad6cce9186bd6e8ff4dbfb281ae8f6742119
Author: Omar Emara
Date:   Wed Aug 10 09:58:44 2022 +0200
Branches: master
https://developer.blender.org/rB6109ad6cce9186bd6e8ff4dbfb281ae8f6742119

Realtime Compositor: Add basic color nodes

This patch implements the following nodes for the realtime compositor:

- Alpha over node.
- Bright contrast node.
- Color balance node.
- Color correction node.
- Exposure node.
- Gamma node.
- Hue correct node.
- Hue saturation value node.
- Invert node.
- Mix node.
- Posterize node.
- Time curve node.
- Vector curve node.

Differential Revision: https://developer.blender.org/D15228

Reviewed By: Clement Foucault

===================================================================

M	source/blender/gpu/CMakeLists.txt
M	source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl
M	source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
M	source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
M	source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_balance.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_correction.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_exposure.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_gamma.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_correct.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_saturation_value.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_invert.glsl
A	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_posterize.glsl
M	source/blender/imbuf/IMB_colormanagement.h
M	source/blender/imbuf/intern/colormanagement_inline.c
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
M	source/blender/nodes/composite/nodes/node_composite_brightness.cc
M	source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
M	source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
M	source/blender/nodes/composite/nodes/node_composite_curves.cc
M	source/blender/nodes/composite/nodes/node_composite_exposure.cc
M	source/blender/nodes/composite/nodes/node_composite_gamma.cc
M	source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
M	source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
M	source/blender/nodes/composite/nodes/node_composite_invert.cc
M	source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
M	source/blender/nodes/composite/nodes/node_composite_posterize.cc
M	source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc

===================================================================

diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index c20fff7082e..9c7fb8f290f 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -328,7 +328,17 @@ set(GLSL_SRC
   shaders/compositor/compositor_set_alpha.glsl
   shaders/compositor/compositor_split_viewer.glsl
 
+  shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl
+  shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl
+  shaders/compositor/library/gpu_shader_compositor_color_balance.glsl
+  shaders/compositor/library/gpu_shader_compositor_color_correction.glsl
+  shaders/compositor/library/gpu_shader_compositor_exposure.glsl
+  shaders/compositor/library/gpu_shader_compositor_gamma.glsl
+  shaders/compositor/library/gpu_shader_compositor_hue_correct.glsl
+  shaders/compositor/library/gpu_shader_compositor_hue_saturation_value.glsl
+  shaders/compositor/library/gpu_shader_compositor_invert.glsl
   shaders/compositor/library/gpu_shader_compositor_main.glsl
+  shaders/compositor/library/gpu_shader_compositor_posterize.glsl
   shaders/compositor/library/gpu_shader_compositor_store_output.glsl
   shaders/compositor/library/gpu_shader_compositor_texture_utilities.glsl
   shaders/compositor/library/gpu_shader_compositor_type_conversion.glsl
diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl
index fe89985ae7f..2ac0ff8c4bb 100644
--- a/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl
@@ -140,6 +140,8 @@ void hsl_to_rgb(vec4 hsl, out vec4 outcol)
   outcol = vec4((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l, hsl.w);
 }
 
+/* ** Alpha Handling ** */
+
 void color_alpha_clear(vec4 color, out vec4 result)
 {
   result = vec4(color.rgb, 1.0);
@@ -147,15 +149,50 @@ void color_alpha_clear(vec4 color, out vec4 result)
 
 void color_alpha_premultiply(vec4 color, out vec4 result)
 {
-  result = vec4(color.rgb * color.a, 1.0);
+  result = vec4(color.rgb * color.a, color.a);
 }
 
 void color_alpha_unpremultiply(vec4 color, out vec4 result)
 {
   if (color.a == 0.0 || color.a == 1.0) {
-    result = vec4(color.rgb, 1.0);
+    result = color;
   }
   else {
-    result = vec4(color.rgb / color.a, 1.0);
+    result = vec4(color.rgb / color.a, color.a);
+  }
+}
+
+float linear_rgb_to_srgb(float color)
+{
+  if (color < 0.0031308) {
+    return (color < 0.0) ? 0.0 : color * 12.92;
+  }
+
+  return 1.055 * pow(color, 1.0 / 2.4) - 0.055;
+}
+
+vec3 linear_rgb_to_srgb(vec3 color)
+{
+  return vec3(
+      linear_rgb_to_srgb(color.r), linear_rgb_to_srgb(color.g), linear_rgb_to_srgb(color.b));
+}
+
+float srgb_to_linear_rgb(float color)
+{
+  if (color < 0.04045) {
+    return (color < 0.0) ? 0.0 : color * (1.0 / 12.92);
   }
+
+  return pow((color + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+vec3 srgb_to_linear_rgb(vec3 color)
+{
+  return vec3(
+      srgb_to_linear_rgb(color.r), srgb_to_linear_rgb(color.g), srgb_to_linear_rgb(color.b));
+}
+
+float get_luminance(vec3 color, vec3 luminance_coefficients)
+{
+  return dot(color, luminance_coefficients);
 }
diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
index 8948ed77557..db8e114ec7a 100644
--- a/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
@@ -95,6 +95,81 @@ void curves_combined_only(float factor,
   result = mix(color, result, factor);
 }
 
+/* Contrary to standard tone curve implementations, the film-like implementation tries to preserve
+ * the hue of the colors as much as possible. To understand why this might be a problem, consider
+ * the violet color (0.5, 0.0, 1.0). If this color was to be evaluated at a power curve x^4, the
+ * color will be blue (0.0625, 0.0, 1.0). So the color changes and not just its luminosity, which
+ * is what film-like tone curves tries to avoid.
+ *
+ * First, the channels with the lowest and highest values are identified and evaluated at the
+ * curve. Then, the third channel---the median---is computed while maintaining the original hue of
+ * the color. To do that, we look at the equation for deriving the hue from RGB values. Assuming
+ * the maximum, minimum, and median channels are known, and ignoring the 1/3 period offset of the
+ * hue, the equation is:
+ *
+ *   hue = (median - min) / (max - min)                                  [1]
+ *
+ * Since we have the new values for the minimum and maximum after evaluating at the curve, we also
+ * have:
+ *
+ *   hue = (new_median - new_min) / (new_max - new_min)                  [2]
+ *
+ * Since we want the hue to be equivalent, by equating [1] and [2] and rearranging:
+ *
+ *   (new_median - new_min) / (new_max - new_min) = (median - min) / (max - min)
+ *   new_median - new_min = (new_max - new_min) * (median - min) / (max - min)
+ *   new_median = new_min + (new_max - new_min) * (median - min) / (max - min)
+ *   new_median = new_min + (median - min) * ((new_max - new_min) / (max - min))  [QED]
+ *
+ * Which gives us the median color that preserves the hue. More intuitively, the median is computed
+ * such that the change in the distance from the median to the minimum is proportional to the
+ * change in the distance from the minimum to the maximum. Finally, each of the new minimum,
+ * maximum, and median values are written to the color channel that they were originally extracted
+ * from. */
+void curves_film_like(float factor,
+                      vec4 color,
+                      vec4 black_level,
+                      vec4 white_level,
+                      sampler1DArray curve_map,
+                      const float layer,
+                      float range_minimum,
+                      float range_divider,
+                      float start_slope,
+                      float end_slope,
+                      out vec4 result)
+{
+  vec4 balanced = white_balance(color, black_level, white_level);
+
+  /* Find the maximum, minimum, and median of the color channels. */
+  float minimum = min(balanced.r, min(balanced.g, balanced.b));
+  float maximum = max(balanced.r, max(balanced.g, balanced.b));
+  float median = max(min(balanced.r, balanced.g), min(balanced.b, max(balanced.r, balanced.g)));
+
+  /* Evaluate alpha curve map at the maximum and minimum channels. The alpha curve is the Combined
+   * curve in the UI. */
+  float min_parameter = NORMALIZE_PARAMETER(minimum, range_minimum, range_divider);
+  float max_parameter = NORMALIZE_PARAMETER(maximum, range_minimum, range_divider);
+  float new_min = texture(curve_map, vec2(min_parameter, layer)).a;
+  float new_max = texture(curve_map, vec2(max_parameter, layer)).a;
+
+  /* Then, extrapolate if needed. */
+  new_min = extrapolate_if_needed(min_parameter, new_min, start_slope, end_slope);
+  new_max = extrapolate_if_needed(max_parameter, new_max, start_slope, end_slope);
+
+  /* Compute the new median using the ratio between the new and the original range. */
+  float scaling_ratio = (new_max - new_min) / (maximum - minimum);
+  float new_median = new_min + (median - minimum) * scaling_ratio;
+
+  /* Write each value to its original channel. */
+  bvec3 channel_is_min = equal(balanced.rgb, vec3(minimum));
+  vec3 median_or_min = mix(vec3(new_median), vec3(new_min), channel_is_min);
+  bvec3 channel_is_max = equal(balanced.rgb, vec3(maximum));
+  result.rgb = mix(median_or_min, vec3(new_max), channel_is_max);
+  result.a = color.a;
+
+  result = mix(color, result, clamp(factor, 0.0, 1.0));
+}
+
 void curves_vector(vec3 vector,
                    sampler1DArray curve_map,
                    const float layer,
diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
index 124654963fd..a28705f158d 100644
--- a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
@@ -34,6 +34,17 @@ float compatible_pow(float x, float y)
   return pow(x, y);
 }
 
+/* A version of pow that returns a fallback value if the computation is undefined. From the spec:
+ * The result is undefined if x < 0 or if x = 0 and y is less than or equal 0. */
+float fallback_pow(float x, float y, float fallback)
+{
+  if (x < 0.0 || (x == 0.0 && y <= 0.0)) {
+    return fallback;
+  }
+
+  return pow(x, y);
+}
+
 float wrap(float a, float b, float c)
 {
   float range = b - c;
@@ -114,6 +125,13 @@ void vector_copy(vec3 normal, out vec3 outnormal)
   outnormal = normal;
 }
 
+vec3 fallback_pow(vec3 a, float b, vec3 fallback)
+{
+  return vec3(fallback_pow(a.x, b, fallback.x),
+              fallback_pow(a.y, b, fallback.y),
+              fallback_pow(a.z, b, fallback.z));
+}
+
 /* Matirx Math */
 
 mat3 euler_to_mat3(vec3 euler)
diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl
index f9652f1150b..39f3c722dd2 100644
--- a/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl
@@ -2,28 +2,24 @@
 
 void mix_blend(float fac, vec4 col1, vec4 col2, out vec4 outcol)
 {
-  fac = clamp(fac, 0.0, 1.0);
   outcol = mix(col1, col2, fac);
   outcol.a = col1.a;
 }
 
 void mix_add(float fac, vec4 col1, vec4 col2, out vec4 outcol)
 {
-  fac = clamp(fac, 0.0, 1.0);
   outcol = mix(col1, col1 + col2, fac);
   outcol.a = col1.a;
 }
 
 void mix_mult(float fac, vec4 col1, vec4 col2, out vec4 outcol)
 {
-  fac = clamp(fac, 0.0, 1.0);
   outcol = mix(col1, col1 * col2, fac);
   outcol.a = col1.a;
 }
 
 void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
 {
-  fac = clamp(fac, 0.0, 1.0);
   float facm = 1.0 - fac;
 
   outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1);
@@ -32,7 +28,6 @@ void mix_screen(float fac, vec4 col1, vec4 col2, out vec4 outcol)
 
 void mix_overlay(float fac, vec4 col

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list