Blender V4.3
COM_BokehImageOperation.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
7#include "BLI_math_base.h"
8#include "BLI_math_base.hh"
9#include "BLI_math_numbers.hh"
10#include "BLI_math_vector.hh"
11
12namespace blender::compositor {
13
19
20/* The exterior angle is the angle between each two consecutive vertices of the regular polygon
21 * from its center. */
22static float compute_exterior_angle(int sides)
23{
24 return (math::numbers::pi * 2.0f) / sides;
25}
26
27static float compute_rotation(float angle, int sides)
28{
29 /* Offset the rotation such that the second vertex of the regular polygon lies on the positive
30 * y axis, which is 90 degrees minus the angle that it makes with the positive x axis assuming
31 * the first vertex lies on the positive x axis. */
32 const float offset = math::numbers::pi / 2.0f - compute_exterior_angle(sides);
33 return angle - offset;
34}
35
37{
38 exterior_angle_ = compute_exterior_angle(data_->flaps);
39 rotation_ = compute_rotation(data_->angle, data_->flaps);
40 roundness_ = data_->rounding;
41 catadioptric_ = data_->catadioptric;
42 lens_shift_ = data_->lensshift;
43}
44
45float2 BokehImageOperation::get_regular_polygon_vertex_position(int vertex_index)
46{
47 float angle = exterior_angle_ * vertex_index - rotation_;
49}
50
51float2 BokehImageOperation::closest_point_on_line(float2 point, float2 line_start, float2 line_end)
52{
53 float2 line_vector = line_end - line_start;
54 float2 point_vector = point - line_start;
55 float line_length_squared = math::dot(line_vector, line_vector);
56 float parameter = math::dot(point_vector, line_vector) / line_length_squared;
57 return line_start + line_vector * parameter;
58}
59
60float BokehImageOperation::bokeh(float2 point, float circumradius)
61{
62 /* Get the index of the vertex of the regular polygon whose polar angle is maximum but less than
63 * the polar angle of the given point, taking rotation into account. This essentially finds the
64 * vertex closest to the given point in the clock-wise direction. */
65 float angle = floored_fmod(math::atan2(point.y, point.x) + rotation_,
67 int vertex_index = int(angle / exterior_angle_);
68
69 /* Compute the shortest distance between the origin and the polygon edge composed from the
70 * previously selected vertex and the one following it. */
71 float2 first_vertex = this->get_regular_polygon_vertex_position(vertex_index) * circumradius;
72 float2 second_vertex = this->get_regular_polygon_vertex_position(vertex_index + 1) *
73 circumradius;
74 float2 closest_point = this->closest_point_on_line(point, first_vertex, second_vertex);
75 float distance_to_edge = math::length(closest_point);
76
77 /* Mix the distance to the edge with the circumradius, making it tend to the distance to a
78 * circle when roundness tends to 1. */
79 float distance_to_edge_round = math::interpolate(distance_to_edge, circumradius, roundness_);
80
81 /* The point is outside of the bokeh, so we return 0. */
83 if (distance > distance_to_edge_round) {
84 return 0.0f;
85 }
86
87 /* The point is inside the catadioptric hole and is not part of the bokeh, so we return 0. */
88 float catadioptric_distance = distance_to_edge_round * catadioptric_;
89 if (distance < catadioptric_distance) {
90 return 0.0f;
91 }
92
93 /* The point is very close to the edge of the bokeh, so we return the difference between the
94 * distance to the edge and the distance as a form of anti-aliasing. */
95 if (distance_to_edge_round - distance < 1.0f) {
96 return distance_to_edge_round - distance;
97 }
98
99 /* The point is very close to the edge of the catadioptric hole, so we return the difference
100 * between the distance to the hole and the distance as a form of anti-aliasing. */
101 if (catadioptric_ != 0.0f && distance - catadioptric_distance < 1.0f) {
102 return distance - catadioptric_distance;
103 }
104
105 /* Otherwise, the point is part of the bokeh and we return 1. */
106 return 1.0f;
107}
108
110 const rcti &area,
111 Span<MemoryBuffer *> /*inputs*/)
112{
113 /* Since we need the regular polygon to occupy the entirety of the output image, the circumradius
114 * of the regular polygon is half the width of the output image. */
115 float circumradius = float(resolution_) / 2.0f;
116
117 for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
118 int2 texel = int2(it.x, it.y);
119
120 /* Move the texel coordinates such that the regular polygon is centered. */
121 float2 point = float2(texel) + float2(0.5f) - circumradius;
122
123 /* Each of the color channels of the output image contains a bokeh with a different
124 * circumradius. The largest one occupies the whole image as stated above, while the other two
125 * have circumradii that are shifted by an amount that is proportional to the "lens_shift"
126 * value. The alpha channel of the output is the average of all three values. */
127 float min_shift = math::abs(lens_shift_ * circumradius);
128 float min = min_shift == circumradius ? 0.0f : this->bokeh(point, circumradius - min_shift);
129
130 float median_shift = min_shift / 2.0f;
131 float median = this->bokeh(point, circumradius - median_shift);
132
133 float max = this->bokeh(point, circumradius);
134 float4 bokeh = float4(min, median, max, (max + median + min) / 3.0f);
135
136 /* If the lens shift is negative, swap the min and max bokeh values, which are stored in the
137 * red and blue channels respectively. Note that we take the absolute value of the lens shift
138 * above, so the sign of the lens shift only controls this swap. */
139 if (lens_shift_ < 0.0f) {
140 std::swap(bokeh.x, bokeh.z);
141 }
142
143 copy_v4_v4(it.out, bokeh);
144 }
145}
146
148{
149 if (delete_data_) {
150 if (data_) {
151 delete data_;
152 data_ = nullptr;
153 }
154 }
155}
156
157void BokehImageOperation::determine_canvas(const rcti & /*preferred_area*/, rcti &r_area)
158{
159 BLI_rcti_init(&r_area, 0, resolution_, 0, resolution_);
160}
161
162} // namespace blender::compositor
MINLINE float floored_fmod(float f, float n)
MINLINE void copy_v4_v4(float r[4], const float a[4])
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
#define output
void determine_canvas(const rcti &preferred_area, rcti &r_area) override
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
a MemoryBuffer contains access to the data
void add_output_socket(DataType datatype)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float compute_exterior_angle(int sides)
static float compute_rotation(float angle, int sides)
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
T cos(const AngleRadianBase< T > &a)
T length(const VecBase< T, Size > &a)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T atan2(const T &y, const T &x)
T sin(const AngleRadianBase< T > &a)
T abs(const T &a)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
float distance(float a, float b)
#define min(a, b)
Definition sort.c:32
float max