Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmar Emara <mail@OmarEmara.dev>2022-08-10 10:58:44 +0300
committerOmar Emara <mail@OmarEmara.dev>2022-08-10 10:58:44 +0300
commit6109ad6cce9186bd6e8ff4dbfb281ae8f6742119 (patch)
tree4308957d11abb889c2dd17e931f4b97623df4098
parent865204fef06b1f4e73a3ad82202fe8221d1efae5 (diff)
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
-rw-r--r--source/blender/gpu/CMakeLists.txt10
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_color_utils.glsl43
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl75
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl18
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_mix_rgb.glsl46
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl48
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl38
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_balance.glsl34
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_correction.glsl87
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_exposure.glsl6
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_gamma.glsl7
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_correct.glsl39
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_saturation_value.glsl16
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_invert.glsl13
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_posterize.glsl6
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h2
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c5
-rw-r--r--source/blender/makesdna/DNA_node_types.h6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alpha_over.cc66
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc45
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc72
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc84
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc246
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc32
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc65
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc55
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.cc125
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_posterize.cc35
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc27
31 files changed, 1354 insertions, 77 deletions
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 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
outcol = col1;
@@ -61,14 +56,30 @@ void mix_overlay(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_sub(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_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
+ float facm = 1.0 - fac;
+
+ outcol = vec4(vec3(0.0), col1.a);
+
+ if (col2.r != 0.0) {
+ outcol.r = facm * col1.r + fac * col1.r / col2.r;
+ }
+ if (col2.g != 0.0) {
+ outcol.g = facm * col1.g + fac * col1.g / col2.g;
+ }
+ if (col2.b != 0.0) {
+ outcol.b = facm * col1.b + fac * col1.b / col2.b;
+ }
+}
+
+/* A variant of mix_div that fallback to the first color upon zero division. */
+void mix_div_fallback(float fac, vec4 col1, vec4 col2, out vec4 outcol)
+{
float facm = 1.0 - fac;
outcol = col1;
@@ -86,28 +97,24 @@ void mix_div(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_diff(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
outcol = mix(col1, abs(col1 - col2), fac);
outcol.a = col1.a;
}
void mix_dark(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac);
outcol.a = col1.a;
}
void mix_light(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac);
outcol.a = col1.a;
}
void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
outcol = col1;
if (outcol.r != 0.0) {
@@ -150,7 +157,6 @@ void mix_dodge(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
float tmp, facm = 1.0 - fac;
outcol = col1;
@@ -200,7 +206,6 @@ void mix_burn(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
outcol = col1;
@@ -220,7 +225,6 @@ void mix_hue(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
outcol = col1;
@@ -238,7 +242,6 @@ void mix_sat(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
vec4 hsv, hsv2;
@@ -251,7 +254,6 @@ void mix_val(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
outcol = col1;
@@ -272,22 +274,26 @@ void mix_color(float fac, vec4 col1, vec4 col2, out vec4 outcol)
void mix_soft(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
float facm = 1.0 - fac;
vec4 one = vec4(1.0);
vec4 scr = one - (one - col2) * (one - col1);
outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr);
+ outcol.a = col1.a;
}
void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
{
- fac = clamp(fac, 0.0, 1.0);
-
outcol = col1 + fac * (2.0 * (col2 - vec4(0.5)));
+ outcol.a = col1.a;
}
-void clamp_color(vec3 vec, vec3 min, vec3 max, out vec3 out_vec)
+void clamp_color(vec4 vec, const vec4 min, const vec4 max, out vec4 out_vec)
{
out_vec = clamp(vec, min, max);
}
+
+void multiply_by_alpha(float factor, vec4 color, out float result)
+{
+ result = factor * color.a;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl
new file mode 100644
index 00000000000..8e3e033147f
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl
@@ -0,0 +1,48 @@
+void node_composite_alpha_over_mixed(
+ float factor, vec4 color, vec4 over_color, float premultiply_factor, out vec4 result)
+{
+ if (over_color.a <= 0.0) {
+ result = color;
+ }
+ else if (factor == 1.0 && over_color.a >= 1.0) {
+ result = over_color;
+ }
+ else {
+ float add_factor = 1.0 - premultiply_factor + over_color.a * premultiply_factor;
+ float premultiplier = factor * add_factor;
+ float multiplier = 1.0 - factor * over_color.a;
+
+ result = multiplier * color + vec2(premultiplier, factor).xxxy * over_color;
+ }
+}
+
+void node_composite_alpha_over_key(float factor, vec4 color, vec4 over_color, out vec4 result)
+{
+ if (over_color.a <= 0.0) {
+ result = color;
+ }
+ else if (factor == 1.0 && over_color.a >= 1.0) {
+ result = over_color;
+ }
+ else {
+ result = mix(color, vec4(over_color.rgb, 1.0), factor * over_color.a);
+ }
+}
+
+void node_composite_alpha_over_premultiply(float factor,
+ vec4 color,
+ vec4 over_color,
+ out vec4 result)
+{
+ if (over_color.a < 0.0) {
+ result = color;
+ }
+ else if (factor == 1.0 && over_color.a >= 1.0) {
+ result = over_color;
+ }
+ else {
+ float multiplier = 1.0 - factor * over_color.a;
+
+ result = multiplier * color + factor * over_color;
+ }
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl
new file mode 100644
index 00000000000..ce71b4fd8a4
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl
@@ -0,0 +1,38 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+/* The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+
+#define FLT_EPSILON 1.192092896e-07F
+
+void node_composite_bright_contrast(
+ vec4 color, float brightness, float contrast, const float use_premultiply, out vec4 result)
+{
+ brightness /= 100.0;
+ float delta = contrast / 200.0;
+
+ float multiplier, offset;
+ if (contrast > 0.0) {
+ multiplier = 1.0 - delta * 2.0;
+ multiplier = 1.0 / max(multiplier, FLT_EPSILON);
+ offset = multiplier * (brightness - delta);
+ }
+ else {
+ delta *= -1.0;
+ multiplier = max(1.0 - delta * 2.0, 0.0);
+ offset = multiplier * brightness + delta;
+ }
+
+ if (use_premultiply != 0.0) {
+ color_alpha_unpremultiply(color, color);
+ }
+
+ result.rgb = color.rgb * multiplier + offset;
+ result.a = color.a;
+
+ if (use_premultiply != 0.0) {
+ color_alpha_premultiply(result, result);
+ }
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_balance.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_balance.glsl
new file mode 100644
index 00000000000..bffb94cdedb
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_balance.glsl
@@ -0,0 +1,34 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_composite_color_balance_lgg(
+ float factor, vec4 color, vec3 lift, vec3 gamma, vec3 gain, out vec4 result)
+{
+ lift = 2.0 - lift;
+ vec3 srgb_color = linear_rgb_to_srgb(color.rgb);
+ vec3 lift_balanced = ((srgb_color - 1.0) * lift) + 1.0;
+
+ vec3 gain_balanced = lift_balanced * gain;
+ gain_balanced = max(gain_balanced, vec3(0.0));
+
+ vec3 linear_color = srgb_to_linear_rgb(gain_balanced);
+ gamma = mix(gamma, vec3(1e-6), equal(gamma, vec3(0.0)));
+ vec3 gamma_balanced = pow(linear_color, 1.0 / gamma);
+
+ result.rgb = mix(color.rgb, gamma_balanced, min(factor, 1.0));
+ result.a = color.a;
+}
+
+void node_composite_color_balance_asc_cdl(float factor,
+ vec4 color,
+ vec3 offset,
+ vec3 power,
+ vec3 slope,
+ float offset_basis,
+ out vec4 result)
+{
+ offset += offset_basis;
+ vec3 balanced = color.rgb * slope + offset;
+ balanced = pow(max(balanced, vec3(0.0)), power);
+ result.rgb = mix(color.rgb, balanced, min(factor, 1.0));
+ result.a = color.a;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_correction.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_correction.glsl
new file mode 100644
index 00000000000..9b4858f03be
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_correction.glsl
@@ -0,0 +1,87 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_composite_color_correction(vec4 color,
+ float mask,
+ const vec3 enabled_channels,
+ float start_midtones,
+ float end_midtones,
+ float master_saturation,
+ float master_contrast,
+ float master_gamma,
+ float master_gain,
+ float master_lift,
+ float shadows_saturation,
+ float shadows_contrast,
+ float shadows_gamma,
+ float shadows_gain,
+ float shadows_lift,
+ float midtones_saturation,
+ float midtones_contrast,
+ float midtones_gamma,
+ float midtones_gain,
+ float midtones_lift,
+ float highlights_saturation,
+ float highlights_contrast,
+ float highlights_gamma,
+ float highlights_gain,
+ float highlights_lift,
+ const vec3 luminance_coefficients,
+ out vec4 result)
+{
+ const float margin = 0.10;
+ const float margin_divider = 0.5 / margin;
+ float level = (color.r + color.g + color.b) / 3.0;
+ float level_shadows = 0.0;
+ float level_midtones = 0.0;
+ float level_highlights = 0.0;
+ if (level < (start_midtones - margin)) {
+ level_shadows = 1.0;
+ }
+ else if (level < (start_midtones + margin)) {
+ level_midtones = ((level - start_midtones) * margin_divider) + 0.5;
+ level_shadows = 1.0 - level_midtones;
+ }
+ else if (level < (end_midtones - margin)) {
+ level_midtones = 1.0;
+ }
+ else if (level < (end_midtones + margin)) {
+ level_highlights = ((level - end_midtones) * margin_divider) + 0.5;
+ level_midtones = 1.0 - level_highlights;
+ }
+ else {
+ level_highlights = 1.0;
+ }
+
+ float contrast = level_shadows * shadows_contrast;
+ contrast += level_midtones * midtones_contrast;
+ contrast += level_highlights * highlights_contrast;
+ contrast *= master_contrast;
+ float saturation = level_shadows * shadows_saturation;
+ saturation += level_midtones * midtones_saturation;
+ saturation += level_highlights * highlights_saturation;
+ saturation *= master_saturation;
+ float gamma = level_shadows * shadows_gamma;
+ gamma += level_midtones * midtones_gamma;
+ gamma += level_highlights * highlights_gamma;
+ gamma *= master_gamma;
+ float gain = level_shadows * shadows_gain;
+ gain += level_midtones * midtones_gain;
+ gain += level_highlights * highlights_gain;
+ gain *= master_gain;
+ float lift = level_shadows * shadows_lift;
+ lift += level_midtones * midtones_lift;
+ lift += level_highlights * highlights_lift;
+ lift += master_lift;
+
+ float inverse_gamma = 1.0 / gamma;
+ float luma = get_luminance(color.rgb, luminance_coefficients);
+
+ vec3 corrected = luma + saturation * (color.rgb - luma);
+ corrected = 0.5 + (corrected - 0.5) * contrast;
+ corrected = fallback_pow(corrected * gain + lift, inverse_gamma, corrected);
+ corrected = mix(color.rgb, corrected, min(mask, 1.0));
+
+ result.rgb = mix(corrected, color.rgb, equal(enabled_channels, vec3(0.0)));
+ result.a = color.a;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_exposure.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_exposure.glsl
new file mode 100644
index 00000000000..f246635a91e
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_exposure.glsl
@@ -0,0 +1,6 @@
+void node_composite_exposure(vec4 color, float exposure, out vec4 result)
+{
+ float multiplier = exp2(exposure);
+ result.rgb = color.rgb * multiplier;
+ result.a = color.a;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_gamma.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_gamma.glsl
new file mode 100644
index 00000000000..53070d4b0e2
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_gamma.glsl
@@ -0,0 +1,7 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
+
+void node_composite_gamma(vec4 color, float gamma, out vec4 result)
+{
+ result.rgb = fallback_pow(color.rgb, gamma, color.rgb);
+ result.a = color.a;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_correct.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_correct.glsl
new file mode 100644
index 00000000000..99eb125cdf2
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_correct.glsl
@@ -0,0 +1,39 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+/* Curve maps are stored in sampler objects that are evaluated in the [0, 1] range, so normalize
+ * parameters accordingly. */
+#define NORMALIZE_PARAMETER(parameter, minimum, range) ((parameter - minimum) * range)
+
+void node_composite_hue_correct(float factor,
+ vec4 color,
+ sampler1DArray curve_map,
+ const float layer,
+ vec3 minimums,
+ vec3 range_dividers,
+ out vec4 result)
+{
+ vec4 hsv;
+ rgb_to_hsv(color, hsv);
+
+ /* First, adjust the hue channel on its own, since corrections in the saturation and value
+ * channels depends on the new value of the hue, not its original value. A curve map value of 0.5
+ * means no change in hue, so adjust the value to get an identity at 0.5. Since the identity of
+ * addition is 0, we subtract 0.5 (0.5 - 0.5 = 0). */
+ const float hue_parameter = NORMALIZE_PARAMETER(hsv.x, minimums.x, range_dividers.x);
+ hsv.x += texture(curve_map, vec2(hue_parameter, layer)).x - 0.5;
+
+ /* Second, adjust the saturation and value based on the new value of the hue. A curve map value
+ * of 0.5 means no change in hue, so adjust the value to get an identity at 0.5. Since the
+ * identity of duplication is 1, we multiply by 2 (0.5 * 2 = 1). */
+ vec2 parameters = NORMALIZE_PARAMETER(hsv.x, minimums.yz, range_dividers.yz);
+ hsv.y *= texture(curve_map, vec2(parameters.x, layer)).y * 2.0;
+ hsv.z *= texture(curve_map, vec2(parameters.y, layer)).z * 2.0;
+
+ /* Sanitize the new hue and saturation values. */
+ hsv.x = fract(hsv.x);
+ hsv.y = clamp(hsv.y, 0.0, 1.0);
+
+ hsv_to_rgb(hsv, result);
+
+ result = mix(color, result, factor);
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_saturation_value.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_saturation_value.glsl
new file mode 100644
index 00000000000..dd5eb33d318
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_hue_saturation_value.glsl
@@ -0,0 +1,16 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_composite_hue_saturation_value(
+ vec4 color, float hue, float saturation, float value, float factor, out vec4 result)
+{
+ vec4 hsv;
+ rgb_to_hsv(color, hsv);
+
+ hsv.x = fract(hsv.x + hue + 0.5);
+ hsv.y = clamp(hsv.y * saturation, 0.0, 1.0);
+ hsv.z = hsv.z * value;
+
+ hsv_to_rgb(hsv, result);
+
+ result = mix(color, result, factor);
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_invert.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_invert.glsl
new file mode 100644
index 00000000000..59be746da7f
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_invert.glsl
@@ -0,0 +1,13 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_composite_invert(float fac, vec4 color, float do_rgb, float do_alpha, out vec4 result)
+{
+ result = color;
+ if (do_rgb != 0.0) {
+ result.rgb = 1.0 - result.rgb;
+ }
+ if (do_alpha != 0.0) {
+ result.a = 1.0 - result.a;
+ }
+ result = mix(color, result, fac);
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_posterize.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_posterize.glsl
new file mode 100644
index 00000000000..ee8ae234abe
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_posterize.glsl
@@ -0,0 +1,6 @@
+void node_composite_posterize(vec4 color, float steps, out vec4 result)
+{
+ steps = clamp(steps, 2.0, 1024.0);
+ result = floor(color * steps) / steps;
+ result.a = color.a;
+}
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 0818dd653a1..2fb1d814c83 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -56,6 +56,8 @@ bool IMB_colormanagement_space_name_is_data(const char *name);
bool IMB_colormanagement_space_name_is_scene_linear(const char *name);
bool IMB_colormanagement_space_name_is_srgb(const char *name);
+BLI_INLINE void IMB_colormanagement_get_luminance_coefficients(float r_rgb[3]);
+
/**
* Convert a float RGB triplet to the correct luminance weighted average.
*
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index 668307ec802..3c6c0f5fd0a 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -11,6 +11,11 @@
#include "BLI_math_vector.h"
#include "IMB_colormanagement_intern.h"
+void IMB_colormanagement_get_luminance_coefficients(float r_rgb[3])
+{
+ copy_v3_v3(r_rgb, imbuf_luma_coefficients);
+}
+
float IMB_colormanagement_get_luminance(const float rgb[3])
{
return dot_v3v3(imbuf_luma_coefficients, rgb);
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index d3c3b70808d..a0e08267efe 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1844,6 +1844,12 @@ typedef enum CMPNodeSplitViewerAxis {
CMP_NODE_SPLIT_VIEWER_VERTICAL = 1,
} CMPNodeSplitViewerAxis;
+/* Color Balance Node. Stored in custom1. */
+typedef enum CMPNodeColorBalanceMethod {
+ CMP_NODE_COLOR_BALANCE_LGG = 0,
+ CMP_NODE_COLOR_BALANCE_ASC_CDL = 1,
+} CMPNodeColorBalanceMethod;
+
/* Plane track deform node. */
enum {
diff --git a/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc b/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
index d392b810bc1..64c59eb24e3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
@@ -8,6 +8,10 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** ALPHAOVER ******************** */
@@ -16,9 +20,18 @@ namespace blender::nodes::node_composite_alpha_over_cc {
static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(2);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Color>(N_("Image"), "Image_001")
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(1);
b.add_output<decl::Color>(N_("Image"));
}
@@ -36,6 +49,52 @@ static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C),
uiItemR(col, ptr, "premul", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
+using namespace blender::realtime_compositor;
+
+class AlphaOverShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ const float premultiply_factor = get_premultiply_factor();
+ if (premultiply_factor != 0.0f) {
+ GPU_stack_link(material,
+ &bnode(),
+ "node_composite_alpha_over_mixed",
+ inputs,
+ outputs,
+ GPU_uniform(&premultiply_factor));
+ return;
+ }
+
+ if (get_use_premultiply()) {
+ GPU_stack_link(material, &bnode(), "node_composite_alpha_over_key", inputs, outputs);
+ return;
+ }
+
+ GPU_stack_link(material, &bnode(), "node_composite_alpha_over_premultiply", inputs, outputs);
+ }
+
+ bool get_use_premultiply()
+ {
+ return bnode().custom1;
+ }
+
+ float get_premultiply_factor()
+ {
+ return ((NodeTwoFloats *)bnode().storage)->x;
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new AlphaOverShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_alpha_over_cc
void register_node_type_cmp_alphaover()
@@ -50,6 +109,7 @@ void register_node_type_cmp_alphaover()
node_type_init(&ntype, file_ns::node_alphaover_init);
node_type_storage(
&ntype, "NodeTwoFloats", node_free_standard_storage, node_copy_standard_storage);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index 65ed2885d9b..fa22f551de6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -8,6 +8,10 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** Bright and Contrast ******************** */
@@ -16,9 +20,11 @@ namespace blender::nodes::node_composite_brightness_cc {
static void cmp_node_brightcontrast_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Bright")).min(-100.0f).max(100.0f);
- b.add_input<decl::Float>(N_("Contrast")).min(-100.0f).max(100.0f);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Float>(N_("Bright")).min(-100.0f).max(100.0f).compositor_domain_priority(1);
+ b.add_input<decl::Float>(N_("Contrast")).min(-100.0f).max(100.0f).compositor_domain_priority(2);
b.add_output<decl::Color>(N_("Image"));
}
@@ -34,6 +40,38 @@ static void node_composit_buts_brightcontrast(uiLayout *layout,
uiItemR(layout, ptr, "use_premultiply", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
+using namespace blender::realtime_compositor;
+
+class BrightContrastShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ const float use_premultiply = get_use_premultiply();
+
+ GPU_stack_link(material,
+ &bnode(),
+ "node_composite_bright_contrast",
+ inputs,
+ outputs,
+ GPU_constant(&use_premultiply));
+ }
+
+ bool get_use_premultiply()
+ {
+ return bnode().custom1;
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new BrightContrastShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_brightness_cc
void register_node_type_cmp_brightcontrast()
@@ -46,6 +84,7 @@ void register_node_type_cmp_brightcontrast()
ntype.declare = file_ns::cmp_node_brightcontrast_declare;
ntype.draw_buttons = file_ns::node_composit_buts_brightcontrast;
node_type_init(&ntype, file_ns::node_composit_init_brightcontrast);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index dd081c8fc12..95675169c76 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -10,6 +10,10 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* ******************* Color Balance ********************************* */
@@ -46,8 +50,15 @@ namespace blender::nodes::node_composite_colorbalance_cc {
static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(1);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
b.add_output<decl::Color>(N_("Image"));
}
@@ -71,7 +82,7 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "correction_method") == 0) {
+ if (RNA_enum_get(ptr, "correction_method") == CMP_NODE_COLOR_BALANCE_LGG) {
split = uiLayoutSplit(layout, 0.0f, false);
col = uiLayoutColumn(split, false);
@@ -116,7 +127,7 @@ static void node_composit_buts_colorbalance_ex(uiLayout *layout,
{
uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
- if (RNA_enum_get(ptr, "correction_method") == 0) {
+ if (RNA_enum_get(ptr, "correction_method") == CMP_NODE_COLOR_BALANCE_LGG) {
uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
uiItemR(layout, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
@@ -139,6 +150,58 @@ static void node_composit_buts_colorbalance_ex(uiLayout *layout,
}
}
+using namespace blender::realtime_compositor;
+
+class ColorBalanceShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ const NodeColorBalance *node_color_balance = get_node_color_balance();
+
+ if (get_color_balance_method() == CMP_NODE_COLOR_BALANCE_LGG) {
+ GPU_stack_link(material,
+ &bnode(),
+ "node_composite_color_balance_lgg",
+ inputs,
+ outputs,
+ GPU_uniform(node_color_balance->lift),
+ GPU_uniform(node_color_balance->gamma),
+ GPU_uniform(node_color_balance->gain));
+ return;
+ }
+
+ GPU_stack_link(material,
+ &bnode(),
+ "node_composite_color_balance_asc_cdl",
+ inputs,
+ outputs,
+ GPU_uniform(node_color_balance->offset),
+ GPU_uniform(node_color_balance->power),
+ GPU_uniform(node_color_balance->slope),
+ GPU_uniform(&node_color_balance->offset_basis));
+ }
+
+ CMPNodeColorBalanceMethod get_color_balance_method()
+ {
+ return (CMPNodeColorBalanceMethod)bnode().custom1;
+ }
+
+ NodeColorBalance *get_node_color_balance()
+ {
+ return static_cast<NodeColorBalance *>(bnode().storage);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new ColorBalanceShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_colorbalance_cc
void register_node_type_cmp_colorbalance()
@@ -155,6 +218,7 @@ void register_node_type_cmp_colorbalance()
node_type_init(&ntype, file_ns::node_composit_init_colorbalance);
node_type_storage(
&ntype, "NodeColorBalance", node_free_standard_storage, node_copy_standard_storage);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index 39ecd277cec..36e6672ce1c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -5,9 +5,15 @@
* \ingroup cmpnodes
*/
+#include "IMB_colormanagement.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* ******************* Color Correction ********************************* */
@@ -16,8 +22,14 @@ namespace blender::nodes::node_composite_colorcorrection_cc {
static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Mask")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Float>(N_("Mask"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .compositor_domain_priority(1);
b.add_output<decl::Color>(N_("Image"));
}
@@ -266,6 +278,73 @@ static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
+using namespace blender::realtime_compositor;
+
+class ColorCorrectionShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ float enabled_channels[3];
+ get_enabled_channels(enabled_channels);
+ float luminance_coefficients[3];
+ IMB_colormanagement_get_luminance_coefficients(luminance_coefficients);
+
+ const NodeColorCorrection *node_color_correction = get_node_color_correction();
+
+ GPU_stack_link(material,
+ &bnode(),
+ "node_composite_color_correction",
+ inputs,
+ outputs,
+ GPU_constant(enabled_channels),
+ GPU_uniform(&node_color_correction->startmidtones),
+ GPU_uniform(&node_color_correction->endmidtones),
+ GPU_uniform(&node_color_correction->master.saturation),
+ GPU_uniform(&node_color_correction->master.contrast),
+ GPU_uniform(&node_color_correction->master.gamma),
+ GPU_uniform(&node_color_correction->master.gain),
+ GPU_uniform(&node_color_correction->master.lift),
+ GPU_uniform(&node_color_correction->shadows.saturation),
+ GPU_uniform(&node_color_correction->shadows.contrast),
+ GPU_uniform(&node_color_correction->shadows.gamma),
+ GPU_uniform(&node_color_correction->shadows.gain),
+ GPU_uniform(&node_color_correction->shadows.lift),
+ GPU_uniform(&node_color_correction->midtones.saturation),
+ GPU_uniform(&node_color_correction->midtones.contrast),
+ GPU_uniform(&node_color_correction->midtones.gamma),
+ GPU_uniform(&node_color_correction->midtones.gain),
+ GPU_uniform(&node_color_correction->midtones.lift),
+ GPU_uniform(&node_color_correction->highlights.saturation),
+ GPU_uniform(&node_color_correction->highlights.contrast),
+ GPU_uniform(&node_color_correction->highlights.gamma),
+ GPU_uniform(&node_color_correction->highlights.gain),
+ GPU_uniform(&node_color_correction->highlights.lift),
+ GPU_constant(luminance_coefficients));
+ }
+
+ void get_enabled_channels(float enabled_channels[3])
+ {
+ for (int i = 0; i < 3; i++) {
+ enabled_channels[i] = (bnode().custom1 & (1 << i)) ? 1.0f : 0.0f;
+ }
+ }
+
+ NodeColorCorrection *get_node_color_correction()
+ {
+ return static_cast<NodeColorCorrection *>(bnode().storage);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new ColorCorrectionShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_colorcorrection_cc
void register_node_type_cmp_colorcorrection()
@@ -282,6 +361,7 @@ void register_node_type_cmp_colorcorrection()
node_type_init(&ntype, file_ns::node_composit_init_colorcorrection);
node_type_storage(
&ntype, "NodeColorCorrection", node_free_standard_storage, node_copy_standard_storage);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 802664d7934..c5d303c576a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -5,16 +5,23 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_base.h"
+
#include "BKE_colortools.h"
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_material.h"
+
+#include "COM_node_operation.hh"
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** CURVE Time ******************** */
-namespace blender::nodes::node_composite_curves_cc {
+namespace blender::nodes::node_composite_time_curves_cc {
static void cmp_node_time_declare(NodeDeclarationBuilder &b)
{
@@ -29,11 +36,65 @@ static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node
node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
-} // namespace blender::nodes::node_composite_curves_cc
+using namespace blender::realtime_compositor;
+
+class TimeCurveOperation : public NodeOperation {
+ public:
+ using NodeOperation::NodeOperation;
+
+ void execute() override
+ {
+ Result &result = get_result("Fac");
+ result.allocate_single_value();
+
+ CurveMapping *curve_mapping = get_curve_mapping();
+ BKE_curvemapping_init(curve_mapping);
+ const float time = BKE_curvemapping_evaluateF(curve_mapping, 0, compute_normalized_time());
+ result.set_float_value(clamp_f(time, 0.0f, 1.0f));
+ }
+
+ CurveMapping *get_curve_mapping()
+ {
+ return static_cast<CurveMapping *>(bnode().storage);
+ }
+
+ int get_start_time()
+ {
+ return bnode().custom1;
+ }
+
+ int get_end_time()
+ {
+ return bnode().custom2;
+ }
+
+ float compute_normalized_time()
+ {
+ const int frame_number = context().get_frame_number();
+ if (frame_number < get_start_time()) {
+ return 0.0f;
+ }
+ if (frame_number > get_end_time()) {
+ return 1.0f;
+ }
+ if (get_start_time() == get_end_time()) {
+ return 0.0f;
+ }
+ return static_cast<float>(frame_number - get_start_time()) /
+ static_cast<float>(get_end_time() - get_start_time());
+ }
+};
+
+static NodeOperation *get_compositor_operation(Context &context, DNode node)
+{
+ return new TimeCurveOperation(context, node);
+}
+
+} // namespace blender::nodes::node_composite_time_curves_cc
void register_node_type_cmp_curve_time()
{
- namespace file_ns = blender::nodes::node_composite_curves_cc;
+ namespace file_ns = blender::nodes::node_composite_time_curves_cc;
static bNodeType ntype;
@@ -42,17 +103,22 @@ void register_node_type_cmp_curve_time()
node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, file_ns::node_composit_init_curves_time);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ ntype.get_compositor_operation = file_ns::get_compositor_operation;
nodeRegisterType(&ntype);
}
/* **************** CURVE VEC ******************** */
-namespace blender::nodes::node_composite_curves_cc {
+namespace blender::nodes::node_composite_vector_curves_cc {
static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Vector>(N_("Vector")).default_value({0.0f, 0.0f, 0.0f}).min(-1.0f).max(1.0f);
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .compositor_domain_priority(0);
b.add_output<decl::Vector>(N_("Vector"));
}
@@ -66,11 +132,63 @@ static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA
uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
}
-} // namespace blender::nodes::node_composite_curves_cc
+using namespace blender::realtime_compositor;
+
+class VectorCurvesShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ CurveMapping *curve_mapping = get_curve_mapping();
+
+ BKE_curvemapping_init(curve_mapping);
+ float *band_values;
+ int band_size;
+ BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
+ float band_layer;
+ GPUNodeLink *band_texture = GPU_color_band(material, band_size, band_values, &band_layer);
+
+ float start_slopes[CM_TOT];
+ float end_slopes[CM_TOT];
+ BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes);
+ float range_minimums[CM_TOT];
+ BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
+ float range_dividers[CM_TOT];
+ BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
+
+ GPU_stack_link(material,
+ &bnode(),
+ "curves_vector",
+ inputs,
+ outputs,
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(range_minimums),
+ GPU_uniform(range_dividers),
+ GPU_uniform(start_slopes),
+ GPU_uniform(end_slopes));
+ }
+
+ CurveMapping *get_curve_mapping()
+ {
+ return static_cast<CurveMapping *>(bnode().storage);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new VectorCurvesShaderNode(node);
+}
+
+} // namespace blender::nodes::node_composite_vector_curves_cc
void register_node_type_cmp_curve_vec()
{
- namespace file_ns = blender::nodes::node_composite_curves_cc;
+ namespace file_ns = blender::nodes::node_composite_vector_curves_cc;
static bNodeType ntype;
@@ -80,19 +198,26 @@ void register_node_type_cmp_curve_vec()
node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, file_ns::node_composit_init_curve_vec);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
/* **************** CURVE RGB ******************** */
-namespace blender::nodes::node_composite_curves_cc {
+namespace blender::nodes::node_composite_rgb_curves_cc {
static void cmp_node_rgbcurves_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(-1.0f).max(1.0f).subtype(
- PROP_FACTOR);
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac"))
+ .default_value(1.0f)
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(1);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
b.add_input<decl::Color>(N_("Black Level")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
b.add_input<decl::Color>(N_("White Level")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_output<decl::Color>(N_("Image"));
@@ -103,11 +228,105 @@ static void node_composit_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
}
-} // namespace blender::nodes::node_composite_curves_cc
+using namespace blender::realtime_compositor;
+
+class RGBCurvesShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ CurveMapping *curve_mapping = get_curve_mapping();
+
+ BKE_curvemapping_init(curve_mapping);
+ float *band_values;
+ int band_size;
+ BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
+ float band_layer;
+ GPUNodeLink *band_texture = GPU_color_band(material, band_size, band_values, &band_layer);
+
+ float start_slopes[CM_TOT];
+ float end_slopes[CM_TOT];
+ BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes);
+ float range_minimums[CM_TOT];
+ BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
+ float range_dividers[CM_TOT];
+ BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
+
+ if (curve_mapping->tone == CURVE_TONE_FILMLIKE) {
+ GPU_stack_link(material,
+ &bnode(),
+ "curves_film_like",
+ inputs,
+ outputs,
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(&range_minimums[3]),
+ GPU_uniform(&range_dividers[3]),
+ GPU_uniform(&start_slopes[3]),
+ GPU_uniform(&end_slopes[3]));
+ return;
+ }
+
+ const float min = 0.0f;
+ const float max = 1.0f;
+ GPU_link(material,
+ "clamp_value",
+ get_input_link("Fac"),
+ GPU_constant(&min),
+ GPU_constant(&max),
+ &get_input("Fac").link);
+
+ /* If the RGB curves do nothing, use a function that skips RGB computations. */
+ if (BKE_curvemapping_is_map_identity(curve_mapping, 0) &&
+ BKE_curvemapping_is_map_identity(curve_mapping, 1) &&
+ BKE_curvemapping_is_map_identity(curve_mapping, 2)) {
+ GPU_stack_link(material,
+ &bnode(),
+ "curves_combined_only",
+ inputs,
+ outputs,
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(&range_minimums[3]),
+ GPU_uniform(&range_dividers[3]),
+ GPU_uniform(&start_slopes[3]),
+ GPU_uniform(&end_slopes[3]));
+ return;
+ }
+
+ GPU_stack_link(material,
+ &bnode(),
+ "curves_combined_rgb",
+ inputs,
+ outputs,
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(range_minimums),
+ GPU_uniform(range_dividers),
+ GPU_uniform(start_slopes),
+ GPU_uniform(end_slopes));
+ }
+
+ CurveMapping *get_curve_mapping()
+ {
+ return static_cast<CurveMapping *>(bnode().storage);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new RGBCurvesShaderNode(node);
+}
+
+} // namespace blender::nodes::node_composite_rgb_curves_cc
void register_node_type_cmp_curve_rgb()
{
- namespace file_ns = blender::nodes::node_composite_curves_cc;
+ namespace file_ns = blender::nodes::node_composite_rgb_curves_cc;
static bNodeType ntype;
@@ -116,6 +335,7 @@ void register_node_type_cmp_curve_rgb()
node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, file_ns::node_composit_init_curve_rgb);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index 881cfc11058..19b93680ff6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -5,6 +5,10 @@
* \ingroup cmpnodes
*/
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** Exposure ******************** */
@@ -13,11 +17,33 @@ namespace blender::nodes::node_composite_exposure_cc {
static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Exposure")).min(-10.0f).max(10.0f);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Float>(N_("Exposure")).min(-10.0f).max(10.0f).compositor_domain_priority(1);
b.add_output<decl::Color>(N_("Image"));
}
+using namespace blender::realtime_compositor;
+
+class ExposureShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ GPU_stack_link(material, &bnode(), "node_composite_exposure", inputs, outputs);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new ExposureShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_exposure_cc
void register_node_type_cmp_exposure()
@@ -28,6 +54,7 @@ void register_node_type_cmp_exposure()
cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::cmp_node_exposure_declare;
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
index b4b8502e915..660d8068231 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -5,6 +5,10 @@
* \ingroup cmpnodes
*/
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** Gamma Tools ******************** */
@@ -13,15 +17,38 @@ namespace blender::nodes::node_composite_gamma_cc {
static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
b.add_input<decl::Float>(N_("Gamma"))
.default_value(1.0f)
.min(0.001f)
.max(10.0f)
- .subtype(PROP_UNSIGNED);
+ .subtype(PROP_UNSIGNED)
+ .compositor_domain_priority(1);
b.add_output<decl::Color>(N_("Image"));
}
+using namespace blender::realtime_compositor;
+
+class GammaShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ GPU_stack_link(material, &bnode(), "node_composite_gamma", inputs, outputs);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new GammaShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_gamma_cc
void register_node_type_cmp_gamma()
@@ -32,6 +59,7 @@ void register_node_type_cmp_gamma()
cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::cmp_node_gamma_declare;
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc b/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
index 08a048829df..091864a06f7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
@@ -5,6 +5,10 @@
* \ingroup cmpnodes
*/
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** Hue Saturation ******************** */
@@ -13,22 +17,56 @@ namespace blender::nodes::node_composite_hue_sat_val_cc {
static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Hue")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Float>(N_("Hue"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(1);
b.add_input<decl::Float>(N_("Saturation"))
.default_value(1.0f)
.min(0.0f)
.max(2.0f)
- .subtype(PROP_FACTOR);
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(2);
b.add_input<decl::Float>(N_("Value"))
.default_value(1.0f)
.min(0.0f)
.max(2.0f)
- .subtype(PROP_FACTOR);
- b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(3);
+ b.add_input<decl::Float>(N_("Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(4);
b.add_output<decl::Color>(N_("Image"));
}
+using namespace blender::realtime_compositor;
+
+class HueSaturationValueShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ GPU_stack_link(material, &bnode(), "node_composite_hue_saturation_value", inputs, outputs);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new HueSaturationValueShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_hue_sat_val_cc
void register_node_type_cmp_hue_sat()
@@ -39,6 +77,7 @@ void register_node_type_cmp_hue_sat()
cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::cmp_node_huesatval_declare;
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index d252d96f8c3..a84420231aa 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -5,6 +5,12 @@
* \ingroup cmpnodes
*/
+#include "BKE_colortools.h"
+
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
#include "BKE_colortools.h"
@@ -13,8 +19,15 @@ namespace blender::nodes::node_composite_huecorrect_cc {
static void cmp_node_huecorrect_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(1);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
b.add_output<decl::Color>(N_("Image"));
}
@@ -35,6 +48,53 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
cumapping->cur = 1;
}
+using namespace blender::realtime_compositor;
+
+class HueCorrectShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ CurveMapping *curve_mapping = get_curve_mapping();
+
+ BKE_curvemapping_init(curve_mapping);
+ float *band_values;
+ int band_size;
+ BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size);
+ float band_layer;
+ GPUNodeLink *band_texture = GPU_color_band(material, band_size, band_values, &band_layer);
+
+ float range_minimums[CM_TOT];
+ BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums);
+ float range_dividers[CM_TOT];
+ BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
+
+ GPU_stack_link(material,
+ &bnode(),
+ "node_composite_hue_correct",
+ inputs,
+ outputs,
+ band_texture,
+ GPU_constant(&band_layer),
+ GPU_uniform(range_minimums),
+ GPU_uniform(range_dividers));
+ }
+
+ CurveMapping *get_curve_mapping()
+ {
+ return static_cast<CurveMapping *>(bnode().storage);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new HueCorrectShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_huecorrect_cc
void register_node_type_cmp_huecorrect()
@@ -48,6 +108,7 @@ void register_node_type_cmp_huecorrect()
node_type_size(&ntype, 320, 140, 500);
node_type_init(&ntype, file_ns::node_composit_init_huecorrect);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc
index 6dff043537a..4bfcc7b6b9c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -8,6 +8,10 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** INVERT ******************** */
@@ -16,8 +20,15 @@ namespace blender::nodes::node_composite_invert_cc {
static void cmp_node_invert_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(1);
+ b.add_input<decl::Color>(N_("Color"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
b.add_output<decl::Color>(N_("Color"));
}
@@ -35,6 +46,45 @@ static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), Poi
uiItemR(col, ptr, "invert_alpha", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
+using namespace blender::realtime_compositor;
+
+class InvertShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ const float do_rgb = get_do_rgb();
+ const float do_alpha = get_do_alpha();
+
+ GPU_stack_link(material,
+ &bnode(),
+ "node_composite_invert",
+ inputs,
+ outputs,
+ GPU_constant(&do_rgb),
+ GPU_constant(&do_alpha));
+ }
+
+ bool get_do_rgb()
+ {
+ return bnode().custom1 & CMP_CHAN_RGB;
+ }
+
+ bool get_do_alpha()
+ {
+ return bnode().custom1 & CMP_CHAN_A;
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new InvertShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_invert_cc
void register_node_type_cmp_invert()
@@ -47,6 +97,7 @@ void register_node_type_cmp_invert()
ntype.declare = file_ns::cmp_node_invert_declare;
ntype.draw_buttons = file_ns::node_composit_buts_invert;
node_type_init(&ntype, file_ns::node_composit_init_invert);
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
index fc11aa188b0..a1fbbfe7d40 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
@@ -5,6 +5,14 @@
* \ingroup cmpnodes
*/
+#include "BLI_assert.h"
+
+#include "DNA_material_types.h"
+
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** MIX RGB ******************** */
@@ -13,12 +21,122 @@ namespace blender::nodes::node_composite_mixrgb_cc {
static void cmp_node_mixrgb_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Color>(N_("Image"), "Image_001").default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR)
+ .compositor_domain_priority(2);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Color>(N_("Image"), "Image_001")
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(1);
b.add_output<decl::Color>(N_("Image"));
}
+using namespace blender::realtime_compositor;
+
+class MixRGBShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ if (get_use_alpha()) {
+ GPU_link(material,
+ "multiply_by_alpha",
+ get_input_link("Fac"),
+ get_input_link("Image_001"),
+ &get_input("Fac").link);
+ }
+
+ GPU_stack_link(material, &bnode(), get_shader_function_name(), inputs, outputs);
+
+ if (!get_should_clamp()) {
+ return;
+ }
+
+ const float min[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float max[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ GPU_link(material,
+ "clamp_color",
+ get_output("Image").link,
+ GPU_constant(min),
+ GPU_constant(max),
+ &get_output("Image").link);
+ }
+
+ int get_mode()
+ {
+ return bnode().custom1;
+ }
+
+ const char *get_shader_function_name()
+ {
+ switch (get_mode()) {
+ case MA_RAMP_BLEND:
+ return "mix_blend";
+ case MA_RAMP_ADD:
+ return "mix_add";
+ case MA_RAMP_MULT:
+ return "mix_mult";
+ case MA_RAMP_SUB:
+ return "mix_sub";
+ case MA_RAMP_SCREEN:
+ return "mix_screen";
+ case MA_RAMP_DIV:
+ return "mix_div";
+ case MA_RAMP_DIFF:
+ return "mix_diff";
+ case MA_RAMP_DARK:
+ return "mix_dark";
+ case MA_RAMP_LIGHT:
+ return "mix_light";
+ case MA_RAMP_OVERLAY:
+ return "mix_overlay";
+ case MA_RAMP_DODGE:
+ return "mix_dodge";
+ case MA_RAMP_BURN:
+ return "mix_burn";
+ case MA_RAMP_HUE:
+ return "mix_hue";
+ case MA_RAMP_SAT:
+ return "mix_sat";
+ case MA_RAMP_VAL:
+ return "mix_val";
+ case MA_RAMP_COLOR:
+ return "mix_color";
+ case MA_RAMP_SOFT:
+ return "mix_soft";
+ case MA_RAMP_LINEAR:
+ return "mix_linear";
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+ }
+
+ bool get_use_alpha()
+ {
+ return bnode().custom2 & SHD_MIXRGB_USE_ALPHA;
+ }
+
+ bool get_should_clamp()
+ {
+ return bnode().custom2 & SHD_MIXRGB_CLAMP;
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new MixRGBShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_mixrgb_cc
void register_node_type_cmp_mix_rgb()
@@ -31,6 +149,7 @@ void register_node_type_cmp_mix_rgb()
ntype.flag |= NODE_PREVIEW;
ntype.declare = file_ns::cmp_node_mixrgb_declare;
ntype.labelfunc = node_blend_label;
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.cc b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
index c97035d55ea..1268219e7e2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
@@ -5,6 +5,10 @@
* \ingroup cmpnodes
*/
+#include "GPU_material.h"
+
+#include "COM_shader_node.hh"
+
#include "node_composite_util.hh"
/* **************** Posterize ******************** */
@@ -13,11 +17,37 @@ namespace blender::nodes::node_composite_posterize_cc {
static void cmp_node_posterize_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Steps")).default_value(8.0f).min(2.0f).max(1024.0f);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Float>(N_("Steps"))
+ .default_value(8.0f)
+ .min(2.0f)
+ .max(1024.0f)
+ .compositor_domain_priority(1);
b.add_output<decl::Color>(N_("Image"));
}
+using namespace blender::realtime_compositor;
+
+class PosterizeShaderNode : public ShaderNode {
+ public:
+ using ShaderNode::ShaderNode;
+
+ void compile(GPUMaterial *material) override
+ {
+ GPUNodeStack *inputs = get_inputs_array();
+ GPUNodeStack *outputs = get_outputs_array();
+
+ GPU_stack_link(material, &bnode(), "node_composite_posterize", inputs, outputs);
+ }
+};
+
+static ShaderNode *get_compositor_shader_node(DNode node)
+{
+ return new PosterizeShaderNode(node);
+}
+
} // namespace blender::nodes::node_composite_posterize_cc
void register_node_type_cmp_posterize()
@@ -28,6 +58,7 @@ void register_node_type_cmp_posterize()
cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR);
ntype.declare = file_ns::cmp_node_posterize_declare;
+ ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index 12707623049..478a6812c36 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -32,7 +32,7 @@ static const char *gpu_shader_get_name(int mode)
case MA_RAMP_SCREEN:
return "mix_screen";
case MA_RAMP_DIV:
- return "mix_div";
+ return "mix_div_fallback";
case MA_RAMP_DIFF:
return "mix_diff";
case MA_RAMP_DARK:
@@ -70,18 +70,23 @@ static int gpu_shader_mix_rgb(GPUMaterial *mat,
{
const char *name = gpu_shader_get_name(node->custom1);
- if (name != nullptr) {
- int ret = GPU_stack_link(mat, node, name, in, out);
- if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
- const float min[3] = {0.0f, 0.0f, 0.0f};
- const float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(
- mat, "clamp_color", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
- }
- return ret;
+ if (name == nullptr) {
+ return 0;
}
- return 0;
+ const float min = 0.0f;
+ const float max = 1.0f;
+ const GPUNodeLink *factor_link = in[0].link ? in[0].link : GPU_uniform(in[0].vec);
+ GPU_link(mat, "clamp_value", factor_link, GPU_constant(&min), GPU_constant(&max), &in[0].link);
+
+ int ret = GPU_stack_link(mat, node, name, in, out);
+
+ if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
+ const float min[3] = {0.0f, 0.0f, 0.0f};
+ const float max[3] = {1.0f, 1.0f, 1.0f};
+ GPU_link(mat, "clamp_color", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
+ }
+ return ret;
}
class MixRGBFunction : public fn::MultiFunction {