37 .compositor_domain_priority(0);
43 "The luminance that will be mapped to the log average luminance, typically set to the "
45 .compositor_expects_single_value();
50 "Balances low and high luminance areas. Lower values emphasize details in shadows, "
51 "while higher values compress highlights more smoothly")
52 .compositor_expects_single_value();
56 .description(
"Gamma correction factor applied after tone mapping")
57 .compositor_expects_single_value();
62 "Controls the intensity of the image, lower values makes it darker while higher values "
64 .compositor_expects_single_value();
69 "Controls the contrast of the image. Zero automatically sets the contrast based on its "
70 "global range for better luminance distribution")
71 .compositor_expects_single_value();
78 "Specifies if tone mapping operates on the entire image or per pixel, 0 means the "
79 "entire image, 1 means it is per pixel, and values in between blends between both")
80 .compositor_expects_single_value();
87 "Specifies if tone mapping operates on the luminance or on each channel independently, "
88 "0 means it uses luminance, 1 means it is per channel, and values in between blends "
90 .compositor_expects_single_value();
123 *node,
SOCK_IN,
"Chromatic Adaptation");
164 if (this->
context().use_gpu()) {
177 const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f;
206 const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f;
212 output.allocate_texture(domain);
215 float4 input_color = image.load_pixel<float4>(texel);
218 float4 scaled_color = input_color * luminance_scale;
222 float4 denominator = luminance_scale_blend_factor + scaled_color;
223 float4 tone_mapped_color = math::safe_divide(scaled_color, denominator);
225 if (inverse_gamma != 0.0f) {
226 tone_mapped_color = math::pow(math::max(tone_mapped_color, float4(0.0f)), inverse_gamma);
229 output.store_pixel(texel,
float4(tone_mapped_color.xyz(), input_color.w));
237 return geometric_mean != 0.0 ? this->
get_key() / geometric_mean : 0.0f;
276 if (this->
context().use_gpu()) {
292 GPUShader *shader =
context().get_shader(
"compositor_tone_map_photoreceptor");
301 float luminance_coefficients[3];
328 float3 luminance_coefficients;
335 output.allocate_texture(domain);
338 float4 input_color = input.load_pixel<float4>(texel);
339 float input_luminance = math::dot(input_color.xyz(), luminance_coefficients);
342 float4 local_adaptation_level = math::interpolate(
343 float4(input_luminance), input_color, chromatic_adaptation);
344 float4 adaptation_level = math::interpolate(
345 global_adaptation_level, local_adaptation_level, light_adaptation);
348 float4 semi_saturation = math::pow(intensity * adaptation_level, contrast);
349 float4 tone_mapped_color = math::safe_divide(input_color, input_color + semi_saturation);
351 output.store_pixel(texel, float4(tone_mapped_color.xyz(), input_color.w));
387 float luminance_coefficients[3];
412 if (log_maximum_luminance == log_minimum_luminance) {
417 const float dynamic_range = log_maximum_luminance - log_minimum_luminance;
418 const float luminance_key = (log_maximum_luminance - average_log_luminance) / (dynamic_range);
420 return 0.3f + 0.7f * std::pow(luminance_key, 1.4f);
427 float luminance_coefficients[3];
430 context(), input_image, luminance_coefficients);
437 float luminance_coefficients[3];
440 return std::log(
math::max(maximum, 1e-5f));
445 float luminance_coefficients[3];
448 return std::log(
math::max(minimum, 1e-5f));
453 return this->
get_input(
"Intensity").get_single_value_default(0.0f);
464 this->
get_input(
"Chromatic Adaptation").get_single_value_default(0.0f), 0.0f, 1.0f);
470 this->
get_input(
"Light Adaptation").get_single_value_default(0.0f), 0.0f, 1.0f);
495 "Map one set of colors to another in order to approximate the appearance of high dynamic "
499 ntype.
declare = file_ns::cmp_node_tonemap_declare;
501 ntype.
draw_buttons = file_ns::node_composit_buts_tonemap;
502 ntype.
initfunc = file_ns::node_composit_init_tonemap;
#define NODE_STORAGE_FUNCS(StorageT)
#define NODE_CLASS_OP_COLOR
#define BLI_assert_unreachable()
@ CMP_NODE_TONE_MAP_PHOTORECEPTOR
@ CMP_NODE_TONE_MAP_SIMPLE
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4])
BLI_INLINE void IMB_colormanagement_get_luminance_coefficients(float r_rgb[3])
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
static T sum(const btAlignedObjectArray< T > &items)
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
const bNode & bnode() const
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Context & context() const
Result & get_input(StringRef identifier) const
virtual Domain compute_domain()
void share_data(const Result &source)
void allocate_texture(Domain domain, bool from_pool=true)
void unbind_as_texture() const
void bind_as_texture(GPUShader *shader, const char *texture_name) const
const Domain & domain() const
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
void unbind_as_image() const
bool is_single_value() const
ColorGeometry4f default_value
float compute_luminance_scale()
void execute_photoreceptor_cpu()
void execute_photoreceptor()
float compute_log_minimum_luminance()
float compute_luminance_scale_blend_factor()
float4 compute_average_color()
float compute_geometric_mean_of_luminance()
float4 compute_global_adaptation_level()
void execute_photoreceptor_gpu()
CMPNodeToneMapType get_type()
float get_chromatic_adaptation()
float get_light_adaptation()
float compute_average_luminance()
void execute_simple_cpu()
float compute_log_maximum_luminance()
float compute_intensity()
void execute_simple_gpu()
NodeOperation(Context &context, DNode node)
float compute_average_log_luminance()
void * MEM_callocN(size_t len, const char *str)
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
void node_register_type(bNodeType &ntype)
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
float4 sum_color(Context &context, const Result &result)
float maximum_luminance(Context &context, const Result &result, const float3 &luminance_coefficients)
float sum_luminance(Context &context, const Result &result, const float3 &luminance_coefficients)
float minimum_luminance(Context &context, const Result &result, const float3 &luminance_coefficients)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
float sum_log_luminance(Context &context, const Result &result, const float3 &luminance_coefficients)
void parallel_for(const int2 range, const Function &function)
T clamp(const T &a, const T &min, const T &max)
T interpolate(const T &a, const T &b, const FactorT &t)
T max(const T &a, const T &b)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void node_composit_init_tonemap(bNodeTree *, bNode *node)
static void node_composit_buts_tonemap(uiLayout *layout, bContext *, PointerRNA *ptr)
static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
static void node_update(bNodeTree *ntree, bNode *node)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
static void register_node_type_cmp_tonemap()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
std::string ui_description
NodeGetCompositorOperationFunction get_compositor_operation
void(* initfunc)(bNodeTree *ntree, bNode *node)
const char * enum_name_legacy
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeDeclareFunction declare
void(* updatefunc)(bNodeTree *ntree, bNode *node)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
static pxr::UsdShadeInput get_input(const pxr::UsdShadeShader &usd_shader, const pxr::TfToken &input_name)