Blender V4.3
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_array.hh"
10#include "BLI_hash.hh"
11#include "BLI_index_range.hh"
12
13#include "RE_pipeline.h"
14
15#include "DNA_scene_types.h"
16
17#include "GPU_shader.hh"
18#include "GPU_texture.hh"
19
20#include "COM_context.hh"
22#include "COM_result.hh"
23
25
26/* --------------------------------------------------------------------
27 * Morphological Distance Feather Weights Key.
28 */
29
31 float radius)
32 : type(type), radius(radius)
33{
34}
35
40
43{
44 return a.type == b.type && a.radius == b.radius;
45}
46
47/* --------------------------------------------------------------------
48 * Morphological Distance Feather Weights.
49 */
50
52 int type,
53 int radius)
54{
55 compute_weights(context, radius);
56 compute_distance_falloffs(context, type, radius);
57}
58
64
66{
67 /* The size of filter is double the radius plus 1, but since the filter is symmetric, we only
68 * compute half of it and no doubling happens. We add 1 to make sure the filter size is always
69 * odd and there is a center weight. */
70 const int size = radius + 1;
71 Array<float> weights(size);
72
73 float sum = 0.0f;
74
75 /* First, compute the center weight. */
76 const float center_weight = RE_filter_value(R_FILTER_GAUSS, 0.0f);
77 weights[0] = center_weight;
78 sum += center_weight;
79
80 /* Second, compute the other weights in the positive direction, making sure to add double the
81 * weight to the sum of weights because the filter is symmetric and we only loop over half of
82 * it. Skip the center weight already computed by dropping the front index. */
83 const float scale = radius > 0.0f ? 1.0f / radius : 0.0f;
84 for (const int i : weights.index_range().drop_front(1)) {
85 const float weight = RE_filter_value(R_FILTER_GAUSS, i * scale);
86 weights[i] = weight;
87 sum += weight * 2.0f;
88 }
89
90 /* Finally, normalize the weights. */
91 for (const int i : weights.index_range()) {
92 weights[i] /= sum;
93 }
94
95 weights_texture_ = GPU_texture_create_1d(
96 "Weights",
97 size,
98 1,
99 Result::gpu_texture_format(ResultType::Float, context.get_precision()),
101 weights.data());
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
130 int type,
131 int radius)
132{
133 /* The size of the distance falloffs is double the radius plus 1, but since the falloffs are
134 * symmetric, we only compute half of them and no doubling happens. We add 1 to make sure the
135 * falloffs size is always odd and there is a center falloff. */
136 const int size = radius + 1;
137 Array<float> falloffs(size);
138
139 /* Compute the distance falloffs in the positive direction only, because the falloffs are
140 * symmetric. */
141 const float scale = radius > 0.0f ? 1.0f / radius : 0.0f;
142 for (const int i : falloffs.index_range()) {
143 falloffs[i] = compute_distance_falloff(type, i * scale);
144 }
145
146 distance_falloffs_texture_ = GPU_texture_create_1d(
147 "Distance Factors",
148 size,
149 1,
150 Result::gpu_texture_format(ResultType::Float, context.get_precision()),
152 falloffs.data());
153}
154
156 const char *texture_name) const
157{
158 const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
159 GPU_texture_bind(weights_texture_, texture_image_unit);
160}
161
166
168 GPUShader *shader, const char *texture_name) const
169{
170 const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
171 GPU_texture_bind(distance_falloffs_texture_, texture_image_unit);
172}
173
178
179/* --------------------------------------------------------------------
180 * Morphological Distance Feather Weights Container.
181 */
182
184{
185 /* First, delete all resources that are no longer needed. */
186 map_.remove_if([](auto item) { return !item.value->needed; });
187
188 /* Second, reset the needed status of the remaining resources to false to ready them to track
189 * their needed status for the next evaluation. */
190 for (auto &value : map_.values()) {
191 value->needed = false;
192 }
193}
194
196 Context &context, int type, int radius)
197{
198 const MorphologicalDistanceFeatherWeightsKey key(type, radius);
199
200 auto &weights = *map_.lookup_or_add_cb(key, [&]() {
201 return std::make_unique<MorphologicalDistanceFeatherWeights>(context, type, radius);
202 });
203
204 weights.needed = true;
205 return weights;
206}
207
208} // namespace blender::realtime_compositor
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
@ R_FILTER_GAUSS
@ PROP_SMOOTH
@ PROP_ROOT
@ PROP_SHARP
@ PROP_LIN
@ PROP_INVSQUARE
@ PROP_SPHERE
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
void GPU_texture_bind(GPUTexture *texture, int unit)
GPUTexture * GPU_texture_create_1d(const char *name, int width, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_TEXTURE_USAGE_GENERAL
struct GPUShader GPUShader
static T sum(const btAlignedObjectArray< T > &items)
const T * data() const
Definition BLI_array.hh:301
IndexRange index_range() const
Definition BLI_array.hh:349
constexpr IndexRange drop_front(int64_t n) const
MorphologicalDistanceFeatherWeights & get(Context &context, int type, int radius)
void bind_distance_falloffs_as_texture(GPUShader *shader, const char *texture_name) const
void bind_weights_as_texture(GPUShader *shader, const char *texture_name) const
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:29
local_group_size(16, 16) .push_constant(Type b
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)
Definition BLI_hash.hh:219
unsigned __int64 uint64_t
Definition stdint.h:90