Blender V4.5
node_composite_colorcorrection.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_base.hh"
10#include "BLI_math_vector.hh"
12
14
15#include "NOD_multi_function.hh"
16
18
19#include "UI_interface.hh"
20#include "UI_resources.hh"
21
22#include "GPU_material.hh"
23
25
26/* ******************* Color Correction ********************************* */
27
29
31{
32 b.use_custom_socket_order();
33
34 b.add_output<decl::Color>("Image");
35
36 b.add_input<decl::Color>("Image").default_value({1.0f, 1.0f, 1.0f, 1.0f});
37 b.add_input<decl::Float>("Mask").default_value(1.0f).min(0.0f).max(1.0f);
38
39 PanelDeclarationBuilder &master_panel = b.add_panel("Master").default_closed(true);
40 master_panel.add_input<decl::Float>("Saturation", "Master Saturation")
41 .default_value(1.0f)
43 .min(0.0f)
44 .max(4.0f)
45 .description("Controls the saturation of the entire image");
46 master_panel.add_input<decl::Float>("Contrast", "Master Contrast")
47 .default_value(1.0f)
49 .min(0.0f)
50 .max(4.0f)
51 .description("Controls the contrast of the entire image");
52 master_panel.add_input<decl::Float>("Gamma", "Master Gamma")
53 .default_value(1.0f)
55 .min(0.0f)
56 .max(4.0f)
57 .description("Controls the gamma of the entire image");
58 master_panel.add_input<decl::Float>("Gain", "Master Gain")
59 .default_value(1.0f)
61 .min(0.0f)
62 .max(4.0f)
63 .description("Controls the gain of the entire image");
64 master_panel.add_input<decl::Float>("Lift", "Master Lift")
65 .default_value(0.0f)
67 .min(-1.0f)
68 .max(1.0f)
69 .description("Controls the lift of the entire image");
70
71 PanelDeclarationBuilder &highlights_panel = b.add_panel("Highlights").default_closed(true);
72 highlights_panel.add_input<decl::Float>("Saturation", "Highlights Saturation")
73 .default_value(1.0f)
75 .min(0.0f)
76 .max(4.0f)
77 .description("Controls the saturation of the highlights");
78 highlights_panel.add_input<decl::Float>("Contrast", "Highlights Contrast")
79 .default_value(1.0f)
81 .min(0.0f)
82 .max(4.0f)
83 .description("Controls the contrast of the highlights");
84 highlights_panel.add_input<decl::Float>("Gamma", "Highlights Gamma")
85 .default_value(1.0f)
87 .min(0.0f)
88 .max(4.0f)
89 .description("Controls the gamma of the highlights");
90 highlights_panel.add_input<decl::Float>("Gain", "Highlights Gain")
91 .default_value(1.0f)
93 .min(0.0f)
94 .max(4.0f)
95 .description("Controls the gain of the highlights");
96 highlights_panel.add_input<decl::Float>("Lift", "Highlights Lift")
97 .default_value(0.0f)
99 .min(-1.0f)
100 .max(1.0f)
101 .description("Controls the lift of the highlights");
102
103 PanelDeclarationBuilder &midtones_panel = b.add_panel("Midtones").default_closed(true);
104 midtones_panel.add_input<decl::Float>("Saturation", "Midtones Saturation")
105 .default_value(1.0f)
107 .min(0.0f)
108 .max(4.0f)
109 .description("Controls the saturation of the midtones");
110 midtones_panel.add_input<decl::Float>("Contrast", "Midtones Contrast")
111 .default_value(1.0f)
113 .min(0.0f)
114 .max(4.0f)
115 .description("Controls the contrast of the midtones");
116 midtones_panel.add_input<decl::Float>("Gamma", "Midtones Gamma")
117 .default_value(1.0f)
119 .min(0.0f)
120 .max(4.0f)
121 .description("Controls the gamma of the midtones");
122 midtones_panel.add_input<decl::Float>("Gain", "Midtones Gain")
123 .default_value(1.0f)
125 .min(0.0f)
126 .max(4.0f)
127 .description("Controls the gain of the midtones");
128 midtones_panel.add_input<decl::Float>("Lift", "Midtones Lift")
129 .default_value(0.0f)
131 .min(-1.0f)
132 .max(1.0f)
133 .description("Controls the lift of the midtones");
134
135 PanelDeclarationBuilder &shadows_panel = b.add_panel("Shadows").default_closed(true);
136 shadows_panel.add_input<decl::Float>("Saturation", "Shadows Saturation")
137 .default_value(1.0f)
139 .min(0.0f)
140 .max(4.0f)
141 .description("Controls the saturation of the shadows");
142 shadows_panel.add_input<decl::Float>("Contrast", "Shadows Contrast")
143 .default_value(1.0f)
145 .min(0.0f)
146 .max(4.0f)
147 .description("Controls the contrast of the shadows");
148 shadows_panel.add_input<decl::Float>("Gamma", "Shadows Gamma")
149 .default_value(1.0f)
151 .min(0.0f)
152 .max(4.0f)
153 .description("Controls the gamma of the shadows");
154 shadows_panel.add_input<decl::Float>("Gain", "Shadows Gain")
155 .default_value(1.0f)
157 .min(0.0f)
158 .max(4.0f)
159 .description("Controls the gain of the shadows");
160 shadows_panel.add_input<decl::Float>("Lift", "Shadows Lift")
161 .default_value(0.0f)
163 .min(-1.0f)
164 .max(1.0f)
165 .description("Controls the lift of the shadows");
166
167 PanelDeclarationBuilder &tonal_range_panel = b.add_panel("Tonal Range").default_closed(true);
168 tonal_range_panel.add_input<decl::Float>("Midtones Start")
169 .default_value(0.2f)
171 .min(0.0f)
172 .max(1.0f)
173 .description(
174 "Specifies the luminance at which the midetones of the image start and the shadows end");
175 tonal_range_panel.add_input<decl::Float>("Midtones End")
176 .default_value(0.7f)
178 .min(0.0f)
179 .max(1.0f)
180 .description(
181 "Specifies the luminance at which the midetones of the image end and the highlights "
182 "start");
183
184 PanelDeclarationBuilder &tone_range_panel = b.add_panel("Channels").default_closed(true);
185 tone_range_panel.add_input<decl::Bool>("Red", "Apply On Red")
186 .default_value(true)
187 .description("If true, the correction will be applied on the red channel");
188 tone_range_panel.add_input<decl::Bool>("Green", "Apply On Green")
189 .default_value(true)
190 .description("If true, the correction will be applied on the green channel");
191 tone_range_panel.add_input<decl::Bool>("Blue", "Apply On Blue")
192 .default_value(true)
193 .description("If true, the correction will be applied on the blue channel");
194}
195
196using namespace blender::compositor;
197
198static int node_gpu_material(GPUMaterial *material,
199 bNode *node,
200 bNodeExecData * /*execdata*/,
203{
204 float luminance_coefficients[3];
206
207 return GPU_stack_link(material,
208 node,
209 "node_composite_color_correction",
210 inputs,
211 outputs,
212 GPU_constant(luminance_coefficients));
213}
214
216 const float &mask,
217 const float &master_saturation,
218 const float &master_contrast,
219 const float &master_gamma,
220 const float &master_gain,
221 const float &master_lift,
222 const float &highlights_saturation,
223 const float &highlights_contrast,
224 const float &highlights_gamma,
225 const float &highlights_gain,
226 const float &highlights_lift,
227 const float &midtones_saturation,
228 const float &midtones_contrast,
229 const float &midtones_gamma,
230 const float &midtones_gain,
231 const float &midtones_lift,
232 const float &shadows_saturation,
233 const float &shadows_contrast,
234 const float &shadows_gamma,
235 const float &shadows_gain,
236 const float &shadows_lift,
237 const float &start_midtones,
238 const float &end_midtones,
239 const bool &apply_on_red,
240 const bool &apply_on_green,
241 const bool &apply_on_blue,
242 const float3 &luminance_coefficients)
243{
244 const float margin = 0.10f;
245 const float margin_divider = 0.5f / margin;
246 float level = (color.x + color.y + color.z) / 3.0f;
247 float level_shadows = 0.0f;
248 float level_midtones = 0.0f;
249 float level_highlights = 0.0f;
250 if (level < (start_midtones - margin)) {
251 level_shadows = 1.0f;
252 }
253 else if (level < (start_midtones + margin)) {
254 level_midtones = ((level - start_midtones) * margin_divider) + 0.5f;
255 level_shadows = 1.0f - level_midtones;
256 }
257 else if (level < (end_midtones - margin)) {
258 level_midtones = 1.0f;
259 }
260 else if (level < (end_midtones + margin)) {
261 level_highlights = ((level - end_midtones) * margin_divider) + 0.5f;
262 level_midtones = 1.0f - level_highlights;
263 }
264 else {
265 level_highlights = 1.0f;
266 }
267
268 float contrast = level_shadows * shadows_contrast;
269 contrast += level_midtones * midtones_contrast;
270 contrast += level_highlights * highlights_contrast;
271 contrast *= master_contrast;
272 float saturation = level_shadows * shadows_saturation;
273 saturation += level_midtones * midtones_saturation;
274 saturation += level_highlights * highlights_saturation;
275 saturation *= master_saturation;
276 float gamma = level_shadows * shadows_gamma;
277 gamma += level_midtones * midtones_gamma;
278 gamma += level_highlights * highlights_gamma;
279 gamma *= master_gamma;
280 float gain = level_shadows * shadows_gain;
281 gain += level_midtones * midtones_gain;
282 gain += level_highlights * highlights_gain;
283 gain *= master_gain;
284 float lift = level_shadows * shadows_lift;
285 lift += level_midtones * midtones_lift;
286 lift += level_highlights * highlights_lift;
287 lift += master_lift;
288
289 float inverse_gamma = 1.0f / gamma;
290 float luma = math::dot(color.xyz(), luminance_coefficients);
291
292 float3 corrected = luma + saturation * (color.xyz() - luma);
293 corrected = 0.5f + (corrected - 0.5f) * contrast;
294 corrected = math::fallback_pow(corrected * gain + lift, inverse_gamma, corrected);
295 corrected = math::interpolate(color.xyz(), corrected, math::min(mask, 1.0f));
296
297 return float4(apply_on_red ? corrected.x : color.x,
298 apply_on_green ? corrected.y : color.y,
299 apply_on_blue ? corrected.z : color.z,
300 color.w);
301}
302
304{
305 float3 luminance_coefficients;
307
309 return mf::build::detail::build_multi_function_with_n_inputs_one_output<float4>(
310 "Color Correction",
311 [=](const float4 &color,
312 const float &mask,
313 const float &master_saturation,
314 const float &master_contrast,
315 const float &master_gamma,
316 const float &master_gain,
317 const float &master_lift,
318 const float &highlights_saturation,
319 const float &highlights_contrast,
320 const float &highlights_gamma,
321 const float &highlights_gain,
322 const float &highlights_lift,
323 const float &midtones_saturation,
324 const float &midtones_contrast,
325 const float &midtones_gamma,
326 const float &midtones_gain,
327 const float &midtones_lift,
328 const float &shadows_saturation,
329 const float &shadows_contrast,
330 const float &shadows_gamma,
331 const float &shadows_gain,
332 const float &shadows_lift,
333 const float &start_midtones,
334 const float &end_midtones,
335 const bool &apply_on_red,
336 const bool &apply_on_green,
337 const bool &apply_on_blue) -> float4 {
338 return color_correction(color,
339 mask,
340 master_saturation,
341 master_contrast,
342 master_gamma,
343 master_gain,
344 master_lift,
345 highlights_saturation,
346 highlights_contrast,
347 highlights_gamma,
348 highlights_gain,
349 highlights_lift,
350 midtones_saturation,
351 midtones_contrast,
352 midtones_gamma,
353 midtones_gain,
354 midtones_lift,
355 shadows_saturation,
356 shadows_contrast,
357 shadows_gamma,
358 shadows_gain,
359 shadows_lift,
360 start_midtones,
361 end_midtones,
362 apply_on_red,
363 apply_on_green,
364 apply_on_blue,
365 luminance_coefficients);
366 },
367 mf::build::exec_presets::SomeSpanOrSingle<0>(),
369 float,
370 float,
371 float,
372 float,
373 float,
374 float,
375 float,
376 float,
377 float,
378 float,
379 float,
380 float,
381 float,
382 float,
383 float,
384 float,
385 float,
386 float,
387 float,
388 float,
389 float,
390 float,
391 float,
392 bool,
393 bool,
394 bool>());
395 });
396}
397
398} // namespace blender::nodes::node_composite_colorcorrection_cc
399
401{
403
404 static blender::bke::bNodeType ntype;
405
406 cmp_node_type_base(&ntype, "CompositorNodeColorCorrection", CMP_NODE_COLORCORRECTION);
407 ntype.ui_name = "Color Correction";
408 ntype.ui_description =
409 "Adjust the color of an image, separately in several tonal ranges (highlights, midtones and "
410 "shadows)";
411 ntype.enum_name_legacy = "COLORCORRECTION";
413 ntype.declare = file_ns::cmp_node_colorcorrection_declare;
414 ntype.gpu_fn = file_ns::node_gpu_material;
415 ntype.build_multi_function = file_ns::node_build_multi_function;
416
418}
#define NODE_CLASS_OP_COLOR
Definition BKE_node.hh:435
#define CMP_NODE_COLORCORRECTION
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_constant(const float *num)
BLI_INLINE void IMB_colormanagement_get_luminance_coefficients(float r_rgb[3])
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ PROP_FACTOR
Definition RNA_types.hh:239
DeclType::Builder & add_input(StringRef name, StringRef identifier="")
void construct_and_set_matching_fn_cb(Fn &&create_multi_function)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T min(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T fallback_pow(const T &x, const T &power, const T &fallback)
static void node_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
static int node_gpu_material(GPUMaterial *material, bNode *node, bNodeExecData *, GPUNodeStack *inputs, GPUNodeStack *outputs)
static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
static float4 color_correction(const float4 &color, const float &mask, const float &master_saturation, const float &master_contrast, const float &master_gamma, const float &master_gain, const float &master_lift, const float &highlights_saturation, const float &highlights_contrast, const float &highlights_gamma, const float &highlights_gain, const float &highlights_lift, const float &midtones_saturation, const float &midtones_contrast, const float &midtones_gamma, const float &midtones_gain, const float &midtones_lift, const float &shadows_saturation, const float &shadows_contrast, const float &shadows_gamma, const float &shadows_gain, const float &shadows_lift, const float &start_midtones, const float &end_midtones, const bool &apply_on_red, const bool &apply_on_green, const bool &apply_on_blue, const float3 &luminance_coefficients)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
static void register_node_type_cmp_colorcorrection()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:330
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:344
const char * enum_name_legacy
Definition BKE_node.hh:235
NodeDeclareFunction declare
Definition BKE_node.hh:355