Blender V4.3
node_composite_colorbalance.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
9#include "RNA_access.hh"
10
11#include "UI_interface.hh"
12#include "UI_resources.hh"
13
14#include "GPU_material.hh"
15
16#include "COM_shader_node.hh"
17
19
20#include "BLI_math_color.hh"
21
23
24/* ******************* Color Balance ********************************* */
25
26/* Sync functions update formula parameters for other modes, such that the result is comparable.
27 * Note that the results are not exactly the same due to differences in color handling
28 * (sRGB conversion happens for LGG),
29 * but this keeps settings comparable. */
30
32{
33 NodeColorBalance *n = (NodeColorBalance *)node->storage;
34
35 for (int c = 0; c < 3; c++) {
36 n->slope[c] = (2.0f - n->lift[c]) * n->gain[c];
37 n->offset[c] = (n->lift[c] - 1.0f) * n->gain[c];
38 n->power[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f;
39 }
40}
41
43{
44 NodeColorBalance *n = (NodeColorBalance *)node->storage;
45
46 for (int c = 0; c < 3; c++) {
47 float d = n->slope[c] + n->offset[c];
48 n->lift[c] = (d != 0.0f ? n->slope[c] + 2.0f * n->offset[c] / d : 0.0f);
49 n->gain[c] = d;
50 n->gamma[c] = (n->power[c] != 0.0f) ? 1.0f / n->power[c] : 1000000.0f;
51 }
52}
53
55
57
59{
60 b.add_input<decl::Float>("Fac")
61 .default_value(1.0f)
62 .min(0.0f)
63 .max(1.0f)
65 .compositor_domain_priority(1);
66 b.add_input<decl::Color>("Image")
67 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
68 .compositor_domain_priority(0);
69 b.add_output<decl::Color>("Image");
70}
71
72static void node_composit_init_colorbalance(bNodeTree * /*ntree*/, bNode *node)
73{
74 NodeColorBalance *n = MEM_cnew<NodeColorBalance>(__func__);
75
76 n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
77 n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
78 n->gain[0] = n->gain[1] = n->gain[2] = 1.0f;
79
80 n->slope[0] = n->slope[1] = n->slope[2] = 1.0f;
81 n->offset[0] = n->offset[1] = n->offset[2] = 0.0f;
82 n->power[0] = n->power[1] = n->power[2] = 1.0f;
83
84 n->input_temperature = n->output_temperature = 6500.0f;
85 n->input_tint = n->output_tint = 10.0f;
86 node->storage = n;
87}
88
90{
91 uiLayout *split, *col, *row;
92
93 uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
94
95 const int method = RNA_enum_get(ptr, "correction_method");
96
97 if (method == CMP_NODE_COLOR_BALANCE_LGG) {
98 split = uiLayoutSplit(layout, 0.0f, false);
99 col = uiLayoutColumn(split, false);
100 uiTemplateColorPicker(col, ptr, "lift", true, true, false, true);
101 row = uiLayoutRow(col, false);
102 uiItemR(row, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
103
104 col = uiLayoutColumn(split, false);
105 uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true);
106 row = uiLayoutRow(col, false);
107 uiItemR(row, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
108
109 col = uiLayoutColumn(split, false);
110 uiTemplateColorPicker(col, ptr, "gain", true, true, true, true);
111 row = uiLayoutRow(col, false);
112 uiItemR(row, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
113 }
114 else if (method == CMP_NODE_COLOR_BALANCE_ASC_CDL) {
115 split = uiLayoutSplit(layout, 0.0f, false);
116 col = uiLayoutColumn(split, false);
117 uiTemplateColorPicker(col, ptr, "offset", true, true, false, true);
118 row = uiLayoutRow(col, false);
119 uiItemR(row, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
120 uiItemR(col, ptr, "offset_basis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
121
122 col = uiLayoutColumn(split, false);
123 uiTemplateColorPicker(col, ptr, "power", true, true, false, true);
124 row = uiLayoutRow(col, false);
125 uiItemR(row, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
126
127 col = uiLayoutColumn(split, false);
128 uiTemplateColorPicker(col, ptr, "slope", true, true, false, true);
129 row = uiLayoutRow(col, false);
130 uiItemR(row, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
131 }
132 else if (method == CMP_NODE_COLOR_BALANCE_WHITEPOINT) {
133 split = uiLayoutSplit(layout, 0.0f, false);
134
135 col = uiLayoutColumn(split, false);
136 row = uiLayoutRow(col, true);
137 uiItemL(row, IFACE_("Input"), ICON_NONE);
138 uiTemplateCryptoPicker(row, ptr, "input_whitepoint", ICON_EYEDROPPER);
139 uiItemR(col,
140 ptr,
141 "input_temperature",
143 IFACE_("Temperature"),
144 ICON_NONE);
145 uiItemR(col, ptr, "input_tint", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Tint"), ICON_NONE);
146
147 col = uiLayoutColumn(split, false);
148 row = uiLayoutRow(col, true);
149 uiItemL(row, IFACE_("Output"), ICON_NONE);
150 uiTemplateCryptoPicker(row, ptr, "output_whitepoint", ICON_EYEDROPPER);
151 uiItemR(col,
152 ptr,
153 "output_temperature",
155 IFACE_("Temperature"),
156 ICON_NONE);
157 uiItemR(col, ptr, "output_tint", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Tint"), ICON_NONE);
158 }
159 else {
160 BLI_assert(false);
161 }
162}
163
165{
166 uiItemR(layout, ptr, "correction_method", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
167
168 const int method = RNA_enum_get(ptr, "correction_method");
169
170 if (method == CMP_NODE_COLOR_BALANCE_LGG) {
171 uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true);
172 uiItemR(layout, ptr, "lift", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
173
174 uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true);
175 uiItemR(layout, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
176
177 uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true);
178 uiItemR(layout, ptr, "gain", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
179 }
180 else if (method == CMP_NODE_COLOR_BALANCE_ASC_CDL) {
181 uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true);
182 uiItemR(layout, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
183
184 uiTemplateColorPicker(layout, ptr, "power", true, true, false, true);
185 uiItemR(layout, ptr, "power", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
186
187 uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true);
188 uiItemR(layout, ptr, "slope", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
189 }
190 else if (method == CMP_NODE_COLOR_BALANCE_WHITEPOINT) {
191 uiItemR(layout, ptr, "input_temperature", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
192 uiItemR(layout, ptr, "input_tint", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
193 uiItemR(layout, ptr, "output_temperature", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
194 uiItemR(layout, ptr, "output_tint", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
195 }
196 else {
197 BLI_assert(false);
198 }
199}
200
201using namespace blender::realtime_compositor;
202
204 public:
206
207 void compile(GPUMaterial *material) override
208 {
209 GPUNodeStack *inputs = get_inputs_array();
210 GPUNodeStack *outputs = get_outputs_array();
211
212 const NodeColorBalance &node_color_balance = node_storage(bnode());
213
215 GPU_stack_link(material,
216 &bnode(),
217 "node_composite_color_balance_lgg",
218 inputs,
219 outputs,
220 GPU_uniform(node_color_balance.lift),
221 GPU_uniform(node_color_balance.gamma),
222 GPU_uniform(node_color_balance.gain));
223 }
225 GPU_stack_link(material,
226 &bnode(),
227 "node_composite_color_balance_asc_cdl",
228 inputs,
229 outputs,
230 GPU_uniform(node_color_balance.offset),
231 GPU_uniform(node_color_balance.power),
232 GPU_uniform(node_color_balance.slope),
233 GPU_uniform(&node_color_balance.offset_basis));
234 }
239 node_color_balance.input_tint);
241 node_color_balance.output_temperature, node_color_balance.output_tint);
242 float3x3 adaption = blender::math::chromatic_adaption_matrix(input, output);
243 float3x3 matrix = xyz_to_scene * adaption * scene_to_xyz;
244
245 GPU_stack_link(material,
246 &bnode(),
247 "node_composite_color_balance_whitepoint",
248 inputs,
249 outputs,
250 GPU_uniform(blender::float4x4(matrix).base_ptr()));
251 }
252 }
253
258};
259
261{
262 return new ColorBalanceShaderNode(node);
263}
264
265} // namespace blender::nodes::node_composite_colorbalance_cc
266
268{
270
271 static blender::bke::bNodeType ntype;
272
273 cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR);
274 ntype.declare = file_ns::cmp_node_colorbalance_declare;
275 ntype.draw_buttons = file_ns::node_composit_buts_colorbalance;
276 ntype.draw_buttons_ex = file_ns::node_composit_buts_colorbalance_ex;
277 blender::bke::node_type_size(&ntype, 400, 200, 400);
278 ntype.initfunc = file_ns::node_composit_init_colorbalance;
280 &ntype, "NodeColorBalance", node_free_standard_storage, node_copy_standard_storage);
281 ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node;
282
284}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_OP_COLOR
Definition BKE_node.hh:406
#define BLI_assert(a)
Definition BLI_assert.h:50
#define IFACE_(msgid)
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()
@ PROP_FACTOR
Definition RNA_types.hh:154
void uiItemL(uiLayout *layout, const char *name, int icon)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int icon)
void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
local_group_size(16, 16) .push_constant(Type b
uint col
void node_type_size(bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition node.cc:4602
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
float3 whitepoint_from_temp_tint(float temperature, float tint)
float3x3 chromatic_adaption_matrix(const float3 &from_XYZ, const float3 &to_XYZ)
static void cmp_node_colorbalance_declare(NodeDeclarationBuilder &b)
static void node_composit_buts_colorbalance_ex(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_composit_buts_colorbalance(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_composit_init_colorbalance(bNodeTree *, bNode *node)
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *, bNode *node)
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *, bNode *node)
void register_node_type_cmp_colorbalance()
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
int RNA_enum_get(PointerRNA *ptr, const char *name)
int16_t custom1
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:240
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
NodeGetCompositorShaderNodeFunction get_compositor_shader_node
Definition BKE_node.hh:328
PointerRNA * ptr
Definition wm_files.cc:4126