Blender V4.3
COM_TonemapOperation.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
8
10
11namespace blender::compositor {
12
21
23 const rcti & /*output_area*/,
24 rcti &r_input_area)
25{
26 BLI_assert(input_idx == 0);
27 r_input_area = get_input_operation(input_idx)->get_canvas();
28}
29
30struct Luminance {
31 float sum;
32 float color_sum[3];
33 float log_sum;
34 float min;
35 float max;
37};
38
39static Luminance calc_area_luminance(const MemoryBuffer *input, const rcti &area)
40{
41 Luminance lum = {0};
42 for (const float *elem : input->get_buffer_area(area)) {
43 const float lu = IMB_colormanagement_get_luminance(elem);
44 lum.sum += lu;
45 add_v3_v3(lum.color_sum, elem);
46 lum.log_sum += logf(std::max(lu, 0.0f) + 1e-5f);
47 lum.max = std::max(lu, lum.max);
48 lum.min = std::min(lu, lum.min);
49 lum.num_pixels++;
50 }
51 return lum;
52}
53
55 const rcti & /*area*/,
57{
58 MemoryBuffer *input_img = inputs[0];
59 if (input_img->is_a_single_elem()) {
60 copy_v4_v4(output->get_elem(0, 0), input_img->get_elem(0, 0));
61 return;
62 }
63
64 if (cached_instance_ == nullptr) {
65 Luminance lum = {0};
66 const MemoryBuffer *input = inputs[0];
68 input->get_rect(),
69 [=](const rcti &split) { return calc_area_luminance(input, split); },
70 lum,
71 [](Luminance &join, const Luminance &chunk) {
72 join.sum += chunk.sum;
73 add_v3_v3(join.color_sum, chunk.color_sum);
74 join.log_sum += chunk.log_sum;
75 join.max = std::max(join.max, chunk.max);
76 join.min = std::min(join.min, chunk.min);
77 join.num_pixels += chunk.num_pixels;
78 });
79
80 AvgLogLum *avg = new AvgLogLum();
81 avg->lav = lum.sum / lum.num_pixels;
82 mul_v3_v3fl(avg->cav, lum.color_sum, 1.0f / lum.num_pixels);
83 const float max_log = log(double(lum.max) + 1e-5);
84 const float min_log = log(double(lum.min) + 1e-5);
85 const float avg_log = lum.log_sum / lum.num_pixels;
86 avg->auto_key = (max_log > min_log) ? ((max_log - avg_log) / (max_log - min_log)) : 1.0f;
87 const float al = exp(double(avg_log));
88 avg->al = (al == 0.0f) ? 0.0f : (data_->key / al);
89 avg->igm = (data_->gamma == 0.0f) ? 1 : (1.0f / data_->gamma);
90 cached_instance_ = avg;
91 }
92}
93
95 const rcti &area,
97{
98 MemoryBuffer *input_img = inputs[0];
99
100 if (input_img->is_a_single_elem()) {
101 return;
102 }
103
105 const float igm = avg->igm;
106 const float offset = data_->offset;
107 for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
108 copy_v4_v4(it.out, it.in(0));
109 mul_v3_fl(it.out, avg->al);
110 float dr = it.out[0] + offset;
111 float dg = it.out[1] + offset;
112 float db = it.out[2] + offset;
113 it.out[0] /= ((dr == 0.0f) ? 1.0f : dr);
114 it.out[1] /= ((dg == 0.0f) ? 1.0f : dg);
115 it.out[2] /= ((db == 0.0f) ? 1.0f : db);
116 if (igm != 0.0f) {
117 it.out[0] = powf(std::max(it.out[0], 0.0f), igm);
118 it.out[1] = powf(std::max(it.out[1], 0.0f), igm);
119 it.out[2] = powf(std::max(it.out[2], 0.0f), igm);
120 }
121 }
122}
123
125 const rcti &area,
127{
128 MemoryBuffer *input_img = inputs[0];
129 if (input_img->is_a_single_elem()) {
130 copy_v4_v4(output->get_elem(0, 0), input_img->get_elem(0, 0));
131 return;
132 }
133
135 const NodeTonemap *ntm = data_;
136 const float f = expf(-data_->f);
137 const float m = (ntm->m > 0.0f) ? ntm->m : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
138 const float ic = 1.0f - ntm->c;
139 const float ia = 1.0f - ntm->a;
140 for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
141 copy_v4_v4(it.out, it.in(0));
142 const float L = IMB_colormanagement_get_luminance(it.out);
143 float I_l = it.out[0] + ic * (L - it.out[0]);
144 float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
145 float I_a = I_l + ia * (I_g - I_l);
146 it.out[0] /= (it.out[0] + powf(f * I_a, m));
147 I_l = it.out[1] + ic * (L - it.out[1]);
148 I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
149 I_a = I_l + ia * (I_g - I_l);
150 it.out[1] /= (it.out[1] + powf(f * I_a, m));
151 I_l = it.out[2] + ic * (L - it.out[2]);
152 I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
153 I_a = I_l + ia * (I_g - I_l);
154 it.out[2] /= (it.out[2] + powf(f * I_a, m));
155 }
156}
157
158} // namespace blender::compositor
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
static void split(const char *text, const char *seps, char ***str, int *count)
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
void execute_work(const rcti &work_rect, std::function< void(const rcti &split_rect)> work_func)
a MemoryBuffer contains access to the data
void add_output_socket(DataType datatype)
NodeOperation * get_input_operation(int index)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
const NodeTonemap * data_
settings of the Tone-map
void update_memory_buffer_started(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
AvgLogLum * cached_instance_
temporarily cache of the execution storage
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
virtual void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
#define logf(x)
#define expf(x)
#define powf(x, y)
ccl_device_inline float3 exp(float3 v)
ccl_device_inline float3 log(float3 v)
#define L
struct blender::compositor::AvgLogLum AvgLogLum
temporarily storage during execution of Tone-map
static Luminance calc_area_luminance(const MemoryBuffer *input, const rcti &area)
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
temporarily storage during execution of Tone-map