Blender V5.0
morphological_distance_feather_weights.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <cmath>
6#include <cstdint>
7#include <memory>
8
9#include "BLI_hash.hh"
10#include "BLI_index_range.hh"
11
12#include "RE_pipeline.h"
13
14#include "DNA_scene_types.h"
15
16#include "COM_context.hh"
18#include "COM_result.hh"
19
20namespace blender::compositor {
21
22/* --------------------------------------------------------------------
23 * Morphological Distance Feather Weights Key.
24 */
25
31
36
39{
40 return a.type == b.type && a.radius == b.radius;
41}
42
43/* --------------------------------------------------------------------
44 * Morphological Distance Feather Weights.
45 */
46
48 int type,
49 int radius)
50 : weights_result(context.create_result(ResultType::Float)),
51 falloffs_result(context.create_result(ResultType::Float))
52{
53 this->compute_weights(radius);
54 this->compute_distance_falloffs(type, radius);
55
56 if (context.use_gpu()) {
57 const Result weights_gpu_result = this->weights_result.upload_to_gpu(false);
58 const Result falloffs_gpu_result = this->falloffs_result.upload_to_gpu(false);
59 this->weights_result.release();
60 this->falloffs_result.release();
61 this->weights_result = weights_gpu_result;
62 this->falloffs_result = falloffs_gpu_result;
63 }
64}
65
71
72void MorphologicalDistanceFeatherWeights::compute_weights(int radius)
73{
74 /* The size of filter is double the radius plus 1, but since the filter is symmetric, we only
75 * compute half of it and no doubling happens. We add 1 to make sure the filter size is always
76 * odd and there is a center weight. */
77 const int size = radius + 1;
79
80 float sum = 0.0f;
81
82 /* First, compute the center weight. */
83 const float center_weight = RE_filter_value(R_FILTER_GAUSS, 0.0f);
84 this->weights_result.store_pixel(int2(0, 0), center_weight);
85 sum += center_weight;
86
87 /* Second, compute the other weights in the positive direction, making sure to add double the
88 * weight to the sum of weights because the filter is symmetric and we only loop over half of
89 * it. Skip the center weight already computed by dropping the front index. */
90 const float scale = radius > 0.0f ? 1.0f / radius : 0.0f;
91 for (const int i : IndexRange(size).drop_front(1)) {
92 const float weight = RE_filter_value(R_FILTER_GAUSS, i * scale);
93 this->weights_result.store_pixel(int2(i, 0), weight);
94 sum += weight * 2.0f;
95 }
96
97 /* Finally, normalize the weights. */
98 for (const int i : IndexRange(size)) {
99 const int2 texel = int2(i, 0);
100 this->weights_result.store_pixel(texel, this->weights_result.load_pixel<float>(texel) / sum);
101 }
102}
103
104/* Computes a falloff that is equal to 1 at an input of zero and decrease to zero at an input of 1,
105 * with the rate of decrease depending on the falloff type. */
106static float compute_distance_falloff(int type, float x)
107{
108 x = 1.0f - x;
109
110 switch (type) {
111 case PROP_SMOOTH:
112 return 3.0f * x * x - 2.0f * x * x * x;
113 case PROP_SPHERE:
114 return std::sqrt(2.0f * x - x * x);
115 case PROP_ROOT:
116 return std::sqrt(x);
117 case PROP_SHARP:
118 return x * x;
119 case PROP_INVSQUARE:
120 return x * (2.0f - x);
121 case PROP_LIN:
122 return x;
123 default:
125 return x;
126 }
127}
128
129void MorphologicalDistanceFeatherWeights::compute_distance_falloffs(int type, int radius)
130{
131 /* The size of the distance falloffs is double the radius plus 1, but since the falloffs are
132 * symmetric, we only compute half of them and no doubling happens. We add 1 to make sure the
133 * falloffs size is always odd and there is a center falloff. */
134 const int size = radius + 1;
136
137 /* Compute the distance falloffs in the positive direction only, because the falloffs are
138 * symmetric. */
139 const float scale = radius > 0.0f ? 1.0f / radius : 0.0f;
140 for (const int i : IndexRange(size)) {
141 this->falloffs_result.store_pixel(int2(i, 0), compute_distance_falloff(type, i * scale));
142 }
143}
144
145/* --------------------------------------------------------------------
146 * Morphological Distance Feather Weights Container.
147 */
148
150{
151 /* First, delete all resources that are no longer needed. */
152 map_.remove_if([](auto item) { return !item.value->needed; });
153
154 /* Second, reset the needed status of the remaining resources to false to ready them to track
155 * their needed status for the next evaluation. */
156 for (auto &value : map_.values()) {
157 value->needed = false;
158 }
159}
160
162 Context &context, int type, int radius)
163{
164 const MorphologicalDistanceFeatherWeightsKey key(type, radius);
165
166 auto &weights = *map_.lookup_or_add_cb(key, [&]() {
167 return std::make_unique<MorphologicalDistanceFeatherWeights>(context, type, radius);
168 });
169
170 weights.needed = true;
171 return weights;
172}
173
174} // namespace blender::compositor
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
@ PROP_SMOOTH
@ PROP_ROOT
@ PROP_SHARP
@ PROP_LIN
@ PROP_INVSQUARE
@ PROP_SPHERE
@ R_FILTER_GAUSS
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static T sum(const btAlignedObjectArray< T > &items)
MorphologicalDistanceFeatherWeights & get(Context &context, int type, int radius)
void store_pixel(const int2 &texel, const T &pixel_value)
void allocate_texture(const Domain domain, const bool from_pool=true, const std::optional< ResultStorageType > storage_type=std::nullopt)
Definition result.cc:389
T load_pixel(const int2 &texel) const
float RE_filter_value(int type, float x)
bool operator==(const BokehKernelKey &a, const BokehKernelKey &b)
static float compute_distance_falloff(int type, float x)
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
VecBase< int32_t, 2 > int2
i
Definition text_draw.cc:230