40 N_(
"Offset/Power/Slope (ASC-CDL)"),
41 N_(
"ASC-CDL standard color correction")},
46 N_(
"Chromatic adaption from a different white point")},
47 {0,
nullptr, 0,
nullptr,
nullptr},
53 b.use_custom_socket_order();
54 b.allow_any_socket_order();
56 b.add_input<
decl::Color>(
"Image").default_value({1.0f, 1.0f, 1.0f, 1.0f}).hide_value();
57 b.add_output<
decl::Color>(
"Image").align_with_previous();
76 .description(
"Correction for shadows");
78 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
87 .description(
"Correction for midtones");
89 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
98 .description(
"Correction for highlights");
100 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
110 .description(
"Correction for shadows");
112 .default_value({0.0f, 0.0f, 0.0f, 1.0f})
121 .description(
"Correction for midtones");
123 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
132 .description(
"Correction for highlights");
134 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
140 .default_value(6500.0f)
145 .description(
"Color temperature of the input's white point");
147 .default_value(10.0f)
152 .description(
"Color tint of the input's white point (the default of 10 matches daylight)");
160 .default_value(6500.0f)
165 .description(
"Color temperature of the output's white point");
167 .default_value(10.0f)
172 .description(
"Color tint of the output's white point (the default of 10 matches daylight)");
180 const float input_tint,
181 const float output_temperature,
182 const float output_tint)
189 return xyz_to_scene * adaption * scene_to_xyz;
198 const bNodeSocket &type = *node->input_by_identifier(
"Type");
199 const bool is_white_point = !type.is_directly_linked() &&
203 const bNodeSocket &input_temperature = *node->input_by_identifier(
"Input Temperature");
204 const bNodeSocket &input_tint = *node->input_by_identifier(
"Input Tint");
205 const bNodeSocket &output_temperature = *node->input_by_identifier(
"Output Temperature");
206 const bNodeSocket &output_tint = *node->input_by_identifier(
"Output Tint");
210 if (is_white_point && !input_temperature.is_directly_linked() &&
211 !input_tint.is_directly_linked() && !output_temperature.is_directly_linked() &&
212 !output_tint.is_directly_linked())
222 "node_composite_color_balance_white_point_constant",
232 "node_composite_color_balance",
240 const float base_lift,
242 const float base_gamma,
244 const float base_gain,
247 const float3 lift = base_lift + color_lift.
xyz();
248 const float3 lift_balanced = ((
color.xyz() - 1.0f) * (2.0f - lift)) + 1.0f;
250 const float3 gain = base_gain * color_gain.
xyz();
253 const float3 gamma = base_gamma * color_gamma.
xyz();
260 const float base_offset,
261 const float4 color_offset,
262 const float base_power,
264 const float base_slope,
267 const float3 slope = base_slope * color_slope.
xyz();
270 const float3 offset = base_offset + color_offset.
xyz();
271 const float3 offset_balanced = slope_balanced + offset;
283 const float3 balanced = white_point_matrix *
color.xyz();
288 const float input_temperature,
289 const float input_tint,
290 const float output_temperature,
291 const float output_tint,
298 const float3x3 white_point_matrix = xyz_to_scene * adaption * scene_to_xyz;
300 const float3 balanced = white_point_matrix *
color.xyz();
307 const float base_lift,
309 const float base_gamma,
311 const float base_gain,
313 const float base_offset,
314 const float4 color_offset,
315 const float base_power,
317 const float base_slope,
319 const float input_temperature,
320 const float input_tint,
321 const float output_temperature,
322 const float output_tint,
330 color, base_lift, color_lift, base_gamma, color_gamma, base_gain, color_gain);
334 color, base_offset, color_offset, base_power, color_power, base_slope, color_slope);
354 static const mf::Signature
signature = []() {
356 mf::SignatureBuilder builder{
"Color Balance",
signature};
357 builder.single_input<
float4>(
"Color");
358 builder.single_input<
float>(
"Factor");
361 builder.single_input<
float>(
"Base Lift");
362 builder.single_input<
float4>(
"Color Lift");
363 builder.single_input<
float>(
"Base Gamma");
364 builder.single_input<
float4>(
"Color Gamma");
365 builder.single_input<
float>(
"Base Gain");
366 builder.single_input<
float4>(
"Color Gain");
368 builder.single_input<
float>(
"Base Offset");
369 builder.single_input<
float4>(
"Color Offset");
370 builder.single_input<
float>(
"Base Power");
371 builder.single_input<
float4>(
"Color Power");
372 builder.single_input<
float>(
"Base Slope");
373 builder.single_input<
float4>(
"Color Slope");
375 builder.single_input<
float>(
"Input Temperature");
376 builder.single_input<
float>(
"Input Tint");
377 builder.single_input<
float>(
"Output Temperature");
378 builder.single_input<
float>(
"Output Tint");
380 builder.single_output<
float4>(
"Result");
394 const VArray<float> base_gamma_array =
params.readonly_single_input<
float>(5,
"Base Gamma");
400 const VArray<float> base_offset_array =
params.readonly_single_input<
float>(9,
"Base Offset");
403 const VArray<float> base_power_array =
params.readonly_single_input<
float>(11,
"Base Power");
406 const VArray<float> base_slope_array =
params.readonly_single_input<
float>(13,
"Base Slope");
411 15,
"Input Temperature");
412 const VArray<float> input_tint_array =
params.readonly_single_input<
float>(16,
"Input Tint");
414 17,
"Output Temperature");
415 const VArray<float> output_tint_array =
params.readonly_single_input<
float>(18,
"Output Tint");
419 const std::optional<MenuValue> type_single = type_array.get_if_single();
420 const std::optional<float> input_temperature_single = input_temperature_array.get_if_single();
421 const std::optional<float> input_tint_single = input_tint_array.get_if_single();
422 const std::optional<float> output_temperature_single =
423 output_temperature_array.get_if_single();
424 const std::optional<float> output_tint_single = output_tint_array.get_if_single();
426 const bool is_white_point = type_single.has_value() &&
431 if (is_white_point && input_temperature_single.has_value() && input_tint_single.has_value() &&
432 output_temperature_single.has_value() && output_tint_single.has_value())
435 input_tint_single.value(),
436 output_temperature_single.value(),
437 output_tint_single.value());
446 bool all_but_color_single_value =
true;
447 for (
int i = 0;
i < 19;
i++) {
451 if (!
params.readonly_single_input(
i).is_single()) {
452 all_but_color_single_value =
false;
457 if (all_but_color_single_value) {
458 const float factor = factor_array.get_internal_single();
460 const float base_lift = base_lift_array.get_internal_single();
461 const float4 color_lift = color_lift_array.get_internal_single();
462 const float base_gamma = base_gamma_array.get_internal_single();
463 const float4 color_gamma = color_gamma_array.get_internal_single();
464 const float base_gain = base_gain_array.get_internal_single();
465 const float4 color_gain = color_gain_array.get_internal_single();
466 const float base_offset = base_offset_array.get_internal_single();
467 const float4 color_offset = color_offset_array.get_internal_single();
468 const float base_power = base_power_array.get_internal_single();
469 const float4 color_power = color_power_array.get_internal_single();
470 const float base_slope = base_slope_array.get_internal_single();
471 const float4 color_slope = color_slope_array.get_internal_single();
472 const float input_temperature = input_temperature_array.get_internal_single();
473 const float input_tint = input_tint_array.get_internal_single();
474 const float output_temperature = output_temperature_array.get_internal_single();
475 const float output_tint = output_tint_array.get_internal_single();
509 color_gamma_array[
i],
512 base_offset_array[
i],
513 color_offset_array[
i],
515 color_power_array[
i],
517 color_slope_array[
i],
518 input_temperature_array[
i],
520 output_temperature_array[
i],
521 output_tint_array[
i],
545 ntype.
ui_name =
"Color Balance";
549 ntype.
declare = file_ns::cmp_node_colorbalance_declare;
550 ntype.
gpu_fn = file_ns::node_gpu_material;
#define NODE_CLASS_OP_COLOR
#define CMP_NODE_COLORBALANCE
CMPNodeColorBalanceMethod
@ CMP_NODE_COLOR_BALANCE_LGG
@ CMP_NODE_COLOR_BALANCE_ASC_CDL
@ CMP_NODE_COLOR_BALANCE_WHITEPOINT
static void split(const char *text, const char *seps, char ***str, int *count)
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_uniform(const float *num)
blender::float3x3 IMB_colormanagement_get_scene_linear_to_xyz()
blender::float3x3 IMB_colormanagement_get_xyz_to_scene_linear()
#define NOD_REGISTER_NODE(REGISTER_FUNC)
void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, int icon)
const Signature & signature() const
void set_signature(const Signature *signature)
void add_layout(std::function< void(uiLayout *, bContext *, PointerRNA *)> draw)
DeclType::Builder & add_input(StringRef name, StringRef identifier="")
void set_matching_fn(const mf::MultiFunction *fn)
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
ccl_device_inline float2 power(const float2 v, const float e)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void node_register_type(bNodeType &ntype)
T pow(const T &x, const T &power)
float3 whitepoint_from_temp_tint(float temperature, float tint)
T min(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
float3x3 chromatic_adaption_matrix(const float3 &from_XYZ, const float3 &to_XYZ)
T max(const T &a, const T &b)
static float4 lift_gamma_gain(const float4 color, const float base_lift, const float4 color_lift, const float base_gamma, const float4 color_gamma, const float base_gain, const float4 color_gain)
static float4 offset_power_slope(const float4 color, const float base_offset, const float4 color_offset, const float base_power, const float4 color_power, const float base_slope, const float4 color_slope)
static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
static float4 white_point_constant(const float4 color, const float factor, const float3x3 white_point_matrix)
static float4 white_point_variable(const float4 color, const float input_temperature, const float input_tint, const float output_temperature, const float output_tint, const float3x3 &scene_to_xyz, const float3x3 &xyz_to_scene)
static float4 color_balance(const float4 color, const float factor, const CMPNodeColorBalanceMethod type, const float base_lift, const float4 color_lift, const float base_gamma, const float4 color_gamma, const float base_gain, const float4 color_gain, const float base_offset, const float4 color_offset, const float base_power, const float4 color_power, const float base_slope, const float4 color_slope, const float input_temperature, const float input_tint, const float output_temperature, const float output_tint, const float3x3 scene_to_xyz, const float3x3 xyz_to_scene)
static void node_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
static const EnumPropertyItem type_items[]
static float3x3 get_white_point_matrix(const float input_temperature, const float input_tint, const float output_temperature, const float output_tint)
static int node_gpu_material(GPUMaterial *material, bNode *node, bNodeExecData *, GPUNodeStack *inputs, GPUNodeStack *outputs)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
static void register_node_type_cmp_colorbalance()
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[]
const T * base_ptr() const
VecBase< T, 3 > xyz() const
std::string ui_description
NodeGPUExecFunction gpu_fn
NodeMultiFunctionBuildFunction build_multi_function
const char * enum_name_legacy
NodeDeclareFunction declare
uiLayout & split(float percentage, bool align)