Compositor: Turn Tone Map node options into inputs
This patch turns the options of the Tone Map node into inputs. In the process, a few changes were made. Input ranges were adjusted to remove artificial limits. The papers indeed mention those limits, but they were only mentioned as typical values, not valid ranges. - The Key option is no longer limited to 1. - Gamma is no longer limited to a value of 3. - Intensity is no longer limited to [-8, 8]. - Contrast is no longer limited to [0, 1]. A few renames were done to clarify options and match the reference papers. - Offset was renamed to Balance, since it is not really an offset, but balances between shadows and highlights. This can be looked up in the paper. - Correction was renamed to Chromatic Adaptation, since it doesn't really correct anything. - Adaptation was renamed to Light Adaptation to distinguish from Chromatic Adaptation and now default to global tone mapping, since this is more useful by default. Reference #137223. Pull Request: https://projects.blender.org/blender/blender/pulls/137589
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 28
|
||||
#define BLENDER_FILE_SUBVERSION 29
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -757,6 +757,17 @@ static void write_compositor_legacy_properties(bNodeTree &node_tree)
|
||||
write_input_to_property_bool_int16_flag("Use Alpha", node->custom1, 1 << 0);
|
||||
write_input_to_property_bool_int16_flag("Anti-Alias", node->custom2, 1 << 0, true);
|
||||
}
|
||||
|
||||
if (node->type_legacy == CMP_NODE_TONEMAP) {
|
||||
NodeTonemap *storage = static_cast<NodeTonemap *>(node->storage);
|
||||
write_input_to_property_float("Key", storage->key);
|
||||
write_input_to_property_float("Balance", storage->offset);
|
||||
write_input_to_property_float("Gamma", storage->gamma);
|
||||
write_input_to_property_float("Intensity", storage->f);
|
||||
write_input_to_property_float("Contrast", storage->m);
|
||||
write_input_to_property_float("Light Adaptation", storage->a);
|
||||
write_input_to_property_float("Chromatic Adaptation", storage->c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2216,6 +2216,114 @@ static void do_version_z_combine_node_options_to_inputs_animation(bNodeTree *nod
|
||||
});
|
||||
}
|
||||
|
||||
/* The options were converted into inputs. */
|
||||
static void do_version_tone_map_node_options_to_inputs(bNodeTree *node_tree, bNode *node)
|
||||
{
|
||||
NodeTonemap *storage = static_cast<NodeTonemap *>(node->storage);
|
||||
if (!storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Key")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(
|
||||
*node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Key", "Key");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = storage->key;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Balance")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(
|
||||
*node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Balance", "Balance");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = storage->offset;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Gamma")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(
|
||||
*node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Gamma", "Gamma");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = storage->gamma;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Intensity")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(
|
||||
*node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Intensity", "Intensity");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = storage->f;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Contrast")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(
|
||||
*node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Contrast", "Contrast");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = storage->m;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Light Adaptation")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(*node_tree,
|
||||
*node,
|
||||
SOCK_IN,
|
||||
SOCK_FLOAT,
|
||||
PROP_FACTOR,
|
||||
"Light Adaptation",
|
||||
"Light Adaptation");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = storage->a;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Chromatic Adaptation")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(*node_tree,
|
||||
*node,
|
||||
SOCK_IN,
|
||||
SOCK_FLOAT,
|
||||
PROP_FACTOR,
|
||||
"Chromatic Adaptation",
|
||||
"Chromatic Adaptation");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = storage->c;
|
||||
}
|
||||
}
|
||||
|
||||
/* The options were converted into inputs. */
|
||||
static void do_version_tone_map_node_options_to_inputs_animation(bNodeTree *node_tree, bNode *node)
|
||||
{
|
||||
/* Compute the RNA path of the node. */
|
||||
char escaped_node_name[sizeof(node->name) * 2 + 1];
|
||||
BLI_str_escape(escaped_node_name, node->name, sizeof(escaped_node_name));
|
||||
const std::string node_rna_path = fmt::format("nodes[\"{}\"]", escaped_node_name);
|
||||
|
||||
BKE_fcurves_id_cb(&node_tree->id, [&](ID * /*id*/, FCurve *fcurve) {
|
||||
/* The FCurve does not belong to the node since its RNA path doesn't start with the node's RNA
|
||||
* path. */
|
||||
if (!blender::StringRef(fcurve->rna_path).startswith(node_rna_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Change the RNA path of the FCurve from the old properties to the new inputs, adjusting the
|
||||
* values of the FCurves frames when needed. */
|
||||
char *old_rna_path = fcurve->rna_path;
|
||||
if (BLI_str_endswith(fcurve->rna_path, "key")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[1].default_value");
|
||||
}
|
||||
else if (BLI_str_endswith(fcurve->rna_path, "offset")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[2].default_value");
|
||||
}
|
||||
else if (BLI_str_endswith(fcurve->rna_path, "gamma")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[3].default_value");
|
||||
}
|
||||
else if (BLI_str_endswith(fcurve->rna_path, "intensity")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[4].default_value");
|
||||
}
|
||||
else if (BLI_str_endswith(fcurve->rna_path, "contrast")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[5].default_value");
|
||||
}
|
||||
else if (BLI_str_endswith(fcurve->rna_path, "adaptation")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[6].default_value");
|
||||
}
|
||||
else if (BLI_str_endswith(fcurve->rna_path, "correction")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[7].default_value");
|
||||
}
|
||||
|
||||
/* The RNA path was changed, free the old path. */
|
||||
if (fcurve->rna_path != old_rna_path) {
|
||||
MEM_freeN(old_rna_path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void do_version_viewer_shortcut(bNodeTree *node_tree)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_tree->nodes) {
|
||||
@@ -2748,6 +2856,19 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 29)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
|
||||
if (node_tree->type == NTREE_COMPOSIT) {
|
||||
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
|
||||
if (node->type_legacy == CMP_NODE_TONEMAP) {
|
||||
do_version_tone_map_node_options_to_inputs_animation(node_tree, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
@@ -7398,6 +7519,19 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 29)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
|
||||
if (node_tree->type == NTREE_COMPOSIT) {
|
||||
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
|
||||
if (node->type_legacy == CMP_NODE_TONEMAP) {
|
||||
do_version_tone_map_node_options_to_inputs(node_tree, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/* Always run this versioning (keep at the bottom of the function). Meshes are written with the
|
||||
* legacy format which always needs to be converted to the new format on file load. To be moved
|
||||
* to a subversion check in 5.0. */
|
||||
|
||||
@@ -1274,8 +1274,13 @@ typedef struct NodeGlare {
|
||||
|
||||
/** Tone-map node. */
|
||||
typedef struct NodeTonemap {
|
||||
float key, offset, gamma;
|
||||
float f, m, a, c;
|
||||
float key DNA_DEPRECATED;
|
||||
float offset DNA_DEPRECATED;
|
||||
float gamma DNA_DEPRECATED;
|
||||
float f DNA_DEPRECATED;
|
||||
float m DNA_DEPRECATED;
|
||||
float a DNA_DEPRECATED;
|
||||
float c DNA_DEPRECATED;
|
||||
int type;
|
||||
} NodeTonemap;
|
||||
|
||||
|
||||
@@ -3889,6 +3889,15 @@ static const char node_input_invert_alpha[] = "Invert Alpha";
|
||||
static const char node_input_use_alpha[] = "Use Alpha";
|
||||
static const char node_input_anti_alias[] = "Anti-Alias";
|
||||
|
||||
/* Tone Map node. */
|
||||
static const char node_input_key[] = "Key";
|
||||
static const char node_input_balance[] = "Balance";
|
||||
static const char node_input_gamma[] = "Gamma";
|
||||
static const char node_input_intensity[] = "Intensity";
|
||||
static const char node_input_contrast[] = "Contrast";
|
||||
static const char node_input_light_adaptation[] = "Light Adaptation";
|
||||
static const char node_input_chromatic_adaptation[] = "Chromatic Adaptation";
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* White Balance Node.
|
||||
*/
|
||||
@@ -8487,50 +8496,87 @@ static void def_cmp_tonemap(BlenderRNA * /*brna*/, StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "key", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "key");
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_key>",
|
||||
"rna_node_property_to_input_setter<float, node_input_key>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Key", "The value the average luminance is mapped to");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Key",
|
||||
"The value the average luminance is mapped to. (Deprecated: Use Key input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "offset");
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_balance>",
|
||||
"rna_node_property_to_input_setter<float, node_input_balance>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, 0.001f, 10.0f);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Offset",
|
||||
"Normally always 1, but can be used as an extra control to alter the brightness curve");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Offset",
|
||||
"Normally always 1, but can be used as an extra control to alter the "
|
||||
"brightness curve. (Deprecated: Use Balance input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "gamma");
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_gamma>",
|
||||
"rna_node_property_to_input_setter<float, node_input_gamma>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, 0.001f, 3.0f);
|
||||
RNA_def_property_ui_text(prop, "Gamma", "If not used, set to 1");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Gamma", "If not used, set to 1. (Deprecated: Use Gamma input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "f");
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_intensity>",
|
||||
"rna_node_property_to_input_setter<float, node_input_intensity>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, -8.0f, 8.0f);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Intensity", "If less than zero, darkens image; otherwise, makes it brighter");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Intensity",
|
||||
"If less than zero, darkens image; otherwise, makes it brighter. "
|
||||
"(Deprecated: Use Intensity input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "m");
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_contrast>",
|
||||
"rna_node_property_to_input_setter<float, node_input_contrast>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Contrast", "Set to 0 to use estimate from input image");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Contrast",
|
||||
"Set to 0 to use estimate from input image. (Deprecated: Use Contrast input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "adaptation", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "a");
|
||||
RNA_def_property_float_funcs(
|
||||
prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_light_adaptation>",
|
||||
"rna_node_property_to_input_setter<float, node_input_light_adaptation>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Adaptation", "If 0, global; if 1, based on pixel intensity");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Adaptation",
|
||||
"If 0, global; if 1, based on pixel intensity. (Deprecated: Use Light "
|
||||
"Adaptation input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "correction", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "c");
|
||||
RNA_def_property_float_funcs(
|
||||
prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_chromatic_adaptation>",
|
||||
"rna_node_property_to_input_setter<float, node_input_chromatic_adaptation>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Color Correction", "If 0, same for all channels; if 1, each independent");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Color Correction",
|
||||
"If 0, same for all channels; if 1, each independent (Deprecated: Use "
|
||||
"Chromatic Adaptation input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
|
||||
@@ -35,58 +35,97 @@ static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
|
||||
b.add_input<decl::Color>("Image")
|
||||
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
|
||||
.compositor_domain_priority(0);
|
||||
|
||||
b.add_input<decl::Float>("Key")
|
||||
.default_value(0.18f)
|
||||
.min(0.0f)
|
||||
.description(
|
||||
"The luminance that will be mapped to the log average luminance, typically set to the "
|
||||
"middle gray value")
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Float>("Balance")
|
||||
.default_value(1.0f)
|
||||
.min(0.0f)
|
||||
.description(
|
||||
"Balances low and high luminance areas. Lower values emphasize details in shadows, "
|
||||
"while higher values compress highlights more smoothly")
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Float>("Gamma")
|
||||
.default_value(1.0f)
|
||||
.min(0.0f)
|
||||
.description("Gamma correction factor applied after tone mapping")
|
||||
.compositor_expects_single_value();
|
||||
|
||||
b.add_input<decl::Float>("Intensity")
|
||||
.default_value(0.0f)
|
||||
.description(
|
||||
"Controls the intensity of the image, lower values makes it darker while higher values "
|
||||
"makes it lighter")
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Float>("Contrast")
|
||||
.default_value(0.0f)
|
||||
.min(0.0f)
|
||||
.description(
|
||||
"Controls the contrast of the image. Zero automatically sets the contrast based on its "
|
||||
"global range for better luminance distribution")
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Float>("Light Adaptation")
|
||||
.default_value(0.0f)
|
||||
.subtype(PROP_FACTOR)
|
||||
.min(0.0f)
|
||||
.max(1.0f)
|
||||
.description(
|
||||
"Specifies if tone mapping operates on the entire image or per pixel, 0 means the "
|
||||
"entire image, 1 means it is per pixel, and values in between blends between both")
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Float>("Chromatic Adaptation")
|
||||
.default_value(0.0f)
|
||||
.subtype(PROP_FACTOR)
|
||||
.min(0.0f)
|
||||
.max(1.0f)
|
||||
.description(
|
||||
"Specifies if tone mapping operates on the luminance or on each channel independently, "
|
||||
"0 means it uses luminance, 1 means it is per channel, and values in between blends "
|
||||
"between both")
|
||||
.compositor_expects_single_value();
|
||||
|
||||
b.add_output<decl::Color>("Image");
|
||||
}
|
||||
|
||||
static void node_composit_init_tonemap(bNodeTree * /*ntree*/, bNode *node)
|
||||
{
|
||||
NodeTonemap *ntm = MEM_callocN<NodeTonemap>(__func__);
|
||||
ntm->type = 1;
|
||||
ntm->key = 0.18;
|
||||
ntm->offset = 1;
|
||||
ntm->gamma = 1;
|
||||
ntm->f = 0;
|
||||
ntm->m = 0; /* Actual value is set according to input. */
|
||||
/* Default a of 1 works well with natural HDR images, but not always so for CGI.
|
||||
* Maybe should use 0 or at least lower initial value instead. */
|
||||
ntm->a = 1;
|
||||
ntm->c = 0;
|
||||
ntm->type = CMP_NODE_TONE_MAP_PHOTORECEPTOR;
|
||||
node->storage = ntm;
|
||||
}
|
||||
|
||||
static void node_composit_buts_tonemap(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiLayout *col;
|
||||
uiItemR(layout, ptr, "tonemap_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
}
|
||||
|
||||
col = uiLayoutColumn(layout, false);
|
||||
uiItemR(col, ptr, "tonemap_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
if (RNA_enum_get(ptr, "tonemap_type") == 0) {
|
||||
uiItemR(
|
||||
col, ptr, "key", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, std::nullopt, ICON_NONE);
|
||||
uiItemR(col, ptr, "offset", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
uiItemR(col, ptr, "gamma", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
}
|
||||
else {
|
||||
uiItemR(col, ptr, "intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
uiItemR(col,
|
||||
ptr,
|
||||
"contrast",
|
||||
UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
|
||||
std::nullopt,
|
||||
ICON_NONE);
|
||||
uiItemR(col,
|
||||
ptr,
|
||||
"adaptation",
|
||||
UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
|
||||
std::nullopt,
|
||||
ICON_NONE);
|
||||
uiItemR(col,
|
||||
ptr,
|
||||
"correction",
|
||||
UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
|
||||
std::nullopt,
|
||||
ICON_NONE);
|
||||
}
|
||||
static void node_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
const bool is_simple = node_storage(*node).type == CMP_NODE_TONE_MAP_SIMPLE;
|
||||
|
||||
bNodeSocket *key_input = bke::node_find_socket(*node, SOCK_IN, "Key");
|
||||
bNodeSocket *balance_input = bke::node_find_socket(*node, SOCK_IN, "Balance");
|
||||
bNodeSocket *gamma_input = bke::node_find_socket(*node, SOCK_IN, "Gamma");
|
||||
|
||||
blender::bke::node_set_socket_availability(*ntree, *key_input, is_simple);
|
||||
blender::bke::node_set_socket_availability(*ntree, *balance_input, is_simple);
|
||||
blender::bke::node_set_socket_availability(*ntree, *gamma_input, is_simple);
|
||||
|
||||
bNodeSocket *intensity_input = bke::node_find_socket(*node, SOCK_IN, "Intensity");
|
||||
bNodeSocket *contrast_input = bke::node_find_socket(*node, SOCK_IN, "Contrast");
|
||||
bNodeSocket *light_adaptation_input = bke::node_find_socket(*node, SOCK_IN, "Light Adaptation");
|
||||
bNodeSocket *chromatic_adaptation_input = bke::node_find_socket(
|
||||
*node, SOCK_IN, "Chromatic Adaptation");
|
||||
|
||||
blender::bke::node_set_socket_availability(*ntree, *intensity_input, !is_simple);
|
||||
blender::bke::node_set_socket_availability(*ntree, *contrast_input, !is_simple);
|
||||
blender::bke::node_set_socket_availability(*ntree, *light_adaptation_input, !is_simple);
|
||||
blender::bke::node_set_socket_availability(*ntree, *chromatic_adaptation_input, !is_simple);
|
||||
}
|
||||
|
||||
using namespace blender::compositor;
|
||||
@@ -134,7 +173,7 @@ class ToneMapOperation : public NodeOperation {
|
||||
{
|
||||
const float luminance_scale = compute_luminance_scale();
|
||||
const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor();
|
||||
const float gamma = node_storage(bnode()).gamma;
|
||||
const float gamma = this->get_gamma();
|
||||
const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f;
|
||||
|
||||
GPUShader *shader = context().get_shader("compositor_tone_map_simple");
|
||||
@@ -163,7 +202,7 @@ class ToneMapOperation : public NodeOperation {
|
||||
{
|
||||
const float luminance_scale = compute_luminance_scale();
|
||||
const float luminance_scale_blend_factor = compute_luminance_scale_blend_factor();
|
||||
const float gamma = node_storage(bnode()).gamma;
|
||||
const float gamma = this->get_gamma();
|
||||
const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f;
|
||||
|
||||
const Result &image = get_input("Image");
|
||||
@@ -195,7 +234,7 @@ class ToneMapOperation : public NodeOperation {
|
||||
float compute_luminance_scale()
|
||||
{
|
||||
const float geometric_mean = compute_geometric_mean_of_luminance();
|
||||
return geometric_mean != 0.0 ? node_storage(bnode()).key / geometric_mean : 0.0f;
|
||||
return geometric_mean != 0.0 ? this->get_key() / geometric_mean : 0.0f;
|
||||
}
|
||||
|
||||
/* Computes equation (1) from Reinhard's 2002 paper. However, note that the equation in the paper
|
||||
@@ -208,6 +247,11 @@ class ToneMapOperation : public NodeOperation {
|
||||
return std::exp(compute_average_log_luminance());
|
||||
}
|
||||
|
||||
float get_key()
|
||||
{
|
||||
return math::max(0.0f, this->get_input("Key").get_single_value_default(0.18f));
|
||||
}
|
||||
|
||||
/* Equation (3) from Reinhard's 2002 paper blends between high luminance scaling for high
|
||||
* luminance values and low luminance scaling for low luminance values. This is done by adding 1
|
||||
* to the denominator, since for low luminance values, the denominator will be close to 1 and for
|
||||
@@ -216,7 +260,12 @@ class ToneMapOperation : public NodeOperation {
|
||||
* a parameter to the user for more flexibility. */
|
||||
float compute_luminance_scale_blend_factor()
|
||||
{
|
||||
return node_storage(bnode()).offset;
|
||||
return math::max(0.0f, this->get_input("Balance").get_single_value_default(1.0f));
|
||||
}
|
||||
|
||||
float get_gamma()
|
||||
{
|
||||
return math::max(0.0f, this->get_input("Gamma").get_single_value_default(1.0f));
|
||||
}
|
||||
|
||||
/* Tone mapping based on equation (1) and the trilinear interpolation between equations (6) and
|
||||
@@ -345,15 +394,15 @@ class ToneMapOperation : public NodeOperation {
|
||||
/* Computes equation (5) from Reinhard's 2005 paper. */
|
||||
float compute_intensity()
|
||||
{
|
||||
return std::exp(-node_storage(bnode()).f);
|
||||
return std::exp(-this->get_intensity());
|
||||
}
|
||||
|
||||
/* If the contrast is not zero, return it, otherwise, a zero contrast denote automatic derivation
|
||||
* of the contrast value based on equations (2) and (4) from Reinhard's 2005 paper. */
|
||||
float compute_contrast()
|
||||
{
|
||||
if (node_storage(bnode()).m != 0.0f) {
|
||||
return node_storage(bnode()).m;
|
||||
if (this->get_contrast() != 0.0f) {
|
||||
return this->get_contrast();
|
||||
}
|
||||
|
||||
const float log_maximum_luminance = compute_log_maximum_luminance();
|
||||
@@ -399,14 +448,26 @@ class ToneMapOperation : public NodeOperation {
|
||||
return std::log(math::max(minimum, 1e-5f));
|
||||
}
|
||||
|
||||
float get_intensity()
|
||||
{
|
||||
return this->get_input("Intensity").get_single_value_default(0.0f);
|
||||
}
|
||||
|
||||
float get_contrast()
|
||||
{
|
||||
return math::max(0.0f, this->get_input("Contrast").get_single_value_default(0.0f));
|
||||
}
|
||||
|
||||
float get_chromatic_adaptation()
|
||||
{
|
||||
return node_storage(bnode()).c;
|
||||
return math::clamp(
|
||||
this->get_input("Chromatic Adaptation").get_single_value_default(0.0f), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
float get_light_adaptation()
|
||||
{
|
||||
return node_storage(bnode()).a;
|
||||
return math::clamp(
|
||||
this->get_input("Light Adaptation").get_single_value_default(0.0f), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
CMPNodeToneMapType get_type()
|
||||
@@ -436,6 +497,7 @@ void register_node_type_cmp_tonemap()
|
||||
ntype.enum_name_legacy = "TONEMAP";
|
||||
ntype.nclass = NODE_CLASS_OP_COLOR;
|
||||
ntype.declare = file_ns::cmp_node_tonemap_declare;
|
||||
ntype.updatefunc = file_ns::node_update;
|
||||
ntype.draw_buttons = file_ns::node_composit_buts_tonemap;
|
||||
ntype.initfunc = file_ns::node_composit_init_tonemap;
|
||||
blender::bke::node_type_storage(
|
||||
|
||||
Reference in New Issue
Block a user