Blender V4.3
smooth_mask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "DNA_brush_types.h"
8
9#include "BKE_attribute.hh"
10#include "BKE_mesh.hh"
11#include "BKE_subdiv_ccg.hh"
12
14#include "BLI_math_base.hh"
15
23
25
26inline namespace smooth_mask_cc {
27
36
37/* TODO: Extract this and the similarly named smooth.cc function
38 * to a common location. */
39static Vector<float> iteration_strengths(const float strength)
40{
41 constexpr int max_iterations = 4;
42
43 BLI_assert_msg(strength >= 0.0f,
44 "The smooth brush expects a non-negative strength to behave properly");
45 const float clamped_strength = std::min(strength, 1.0f);
46
47 const int count = int(clamped_strength * max_iterations);
48 const float last = max_iterations * (clamped_strength - float(count) / max_iterations);
50 result.append_n_times(1.0f, count);
51 result.append(last);
52 return result;
53}
54
56 const Span<int> corner_verts,
57 const GroupedSpan<int> vert_to_face_map,
58 const Span<bool> hide_poly,
59 const Span<int> verts,
60 const Span<float> masks,
61 LocalData &tls,
62 const MutableSpan<float> new_masks)
63{
64 tls.vert_neighbors.resize(verts.size());
65 calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, tls.vert_neighbors);
66 const Span<Vector<int>> vert_neighbors = tls.vert_neighbors;
67 smooth::neighbor_data_average_mesh(masks, vert_neighbors, new_masks);
68}
69
70static void apply_masks_faces(const Depsgraph &depsgraph,
71 const Brush &brush,
72 const Span<float3> positions_eval,
73 const Span<float3> vert_normals,
74 const Span<bool> hide_vert,
75 const bke::pbvh::MeshNode &node,
76 const float strength,
77 Object &object,
78 LocalData &tls,
79 const Span<float> mask_averages,
81{
82 SculptSession &ss = *object.sculpt;
83 const StrokeCache &cache = *ss.cache;
84
85 const Span<int> verts = node.verts();
86
87 tls.factors.resize(verts.size());
88 const MutableSpan<float> factors = tls.factors;
89 fill_factor_from_hide(hide_vert, verts, factors);
90 filter_region_clip_factors(ss, positions_eval, verts, factors);
91 if (brush.flag & BRUSH_FRONTFACE) {
92 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
93 }
94
95 tls.distances.resize(verts.size());
96 const MutableSpan<float> distances = tls.distances;
98 ss, positions_eval, verts, eBrushFalloffShape(brush.falloff_shape), distances);
99 filter_distances_with_radius(cache.radius, distances, factors);
100 apply_hardness_to_distances(cache, distances);
101 calc_brush_strength_factors(cache, brush, distances, factors);
102
104 depsgraph, object, ss.cache->automasking.get(), node, verts, factors);
105
106 scale_factors(factors, strength);
107
108 calc_brush_texture_factors(ss, brush, positions_eval, verts, factors);
109
110 tls.new_masks.resize(verts.size());
111 const MutableSpan<float> new_masks = tls.new_masks;
112 gather_data_mesh(mask.as_span(), verts, new_masks);
113
114 mask::mix_new_masks(mask_averages, factors, new_masks);
115 mask::clamp_mask(new_masks);
116
117 scatter_data_mesh(new_masks.as_span(), verts, mask);
118}
119
120static void do_smooth_brush_mesh(const Depsgraph &depsgraph,
121 const Brush &brush,
122 Object &object,
123 const IndexMask &node_mask,
124 const float brush_strength)
125{
126 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
128 Mesh &mesh = *static_cast<Mesh *>(object.data);
129 const OffsetIndices faces = mesh.faces();
130 const Span<int> corner_verts = mesh.corner_verts();
131 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
132 const bke::AttributeAccessor attributes = mesh.attributes();
133 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
134
135 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
136 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
137
138 Array<int> node_vert_offset_data;
139 OffsetIndices node_vert_offsets = create_node_vert_offsets(
140 nodes, node_mask, node_vert_offset_data);
141 Array<float> new_masks(node_vert_offsets.total_size());
142
143 bke::MutableAttributeAccessor write_attributes = mesh.attributes_for_write();
144
145 bke::SpanAttributeWriter<float> mask = write_attributes.lookup_for_write_span<float>(
146 ".sculpt_mask");
147 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
148
150 for (const float strength : iteration_strengths(brush_strength)) {
151 /* Calculate new masks into a separate array to avoid non-threadsafe access of values from
152 * neighboring nodes. */
153 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
154 LocalData &tls = all_tls.local();
156 corner_verts,
157 vert_to_face_map,
158 hide_poly,
159 nodes[i].verts(),
160 mask.span.as_span(),
161 tls,
162 new_masks.as_mutable_span().slice(node_vert_offsets[pos]));
163 });
164
165 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
166 LocalData &tls = all_tls.local();
168 brush,
169 positions_eval,
170 vert_normals,
171 hide_vert,
172 nodes[i],
173 strength,
174 object,
175 tls,
176 new_masks.as_span().slice(node_vert_offsets[pos]),
177 mask.span);
178 });
179 }
180 bke::pbvh::update_mask_mesh(mesh, node_mask, pbvh);
181 pbvh.tag_masks_changed(node_mask);
182 mask.finish();
183}
184
185static void calc_grids(const Depsgraph &depsgraph,
186 Object &object,
187 const Brush &brush,
188 const float strength,
189 const bke::pbvh::GridsNode &node,
190 LocalData &tls)
191{
192 SculptSession &ss = *object.sculpt;
193 const StrokeCache &cache = *ss.cache;
194 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
195
196 const Span<int> grids = node.grids();
197 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
198
199 tls.factors.resize(positions.size());
200 const MutableSpan<float> factors = tls.factors;
201 fill_factor_from_hide(subdiv_ccg, grids, factors);
202 filter_region_clip_factors(ss, positions, factors);
203 if (brush.flag & BRUSH_FRONTFACE) {
204 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
205 }
206
207 tls.distances.resize(positions.size());
208 const MutableSpan<float> distances = tls.distances;
209 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
210 filter_distances_with_radius(cache.radius, distances, factors);
211 apply_hardness_to_distances(cache, distances);
212 calc_brush_strength_factors(cache, brush, distances, factors);
213
214 if (ss.cache->automasking) {
216 depsgraph, object, cache.automasking.get(), node, grids, factors);
217 }
218
219 scale_factors(factors, strength);
220
221 calc_brush_texture_factors(ss, brush, positions, factors);
222
223 tls.masks.resize(positions.size());
224 const MutableSpan<float> masks = tls.masks;
225 mask::gather_mask_grids(subdiv_ccg, grids, masks);
226
227 tls.new_masks.resize(positions.size());
228 const MutableSpan<float> new_masks = tls.new_masks;
229 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_masks);
230
231 mask::mix_new_masks(new_masks, factors, masks);
232 mask::clamp_mask(masks);
233
234 mask::scatter_mask_grids(masks, subdiv_ccg, grids);
235}
236
237static void calc_bmesh(const Depsgraph &depsgraph,
238 Object &object,
239 const int mask_offset,
240 const Brush &brush,
241 const float strength,
243 LocalData &tls)
244{
245 SculptSession &ss = *object.sculpt;
246 const StrokeCache &cache = *ss.cache;
247
249
250 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
251
252 tls.factors.resize(verts.size());
253 const MutableSpan<float> factors = tls.factors;
255 filter_region_clip_factors(ss, positions, factors);
256 if (brush.flag & BRUSH_FRONTFACE) {
257 calc_front_face(cache.view_normal_symm, verts, factors);
258 }
259
260 tls.distances.resize(verts.size());
261 const MutableSpan<float> distances = tls.distances;
262 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
263 filter_distances_with_radius(cache.radius, distances, factors);
264 apply_hardness_to_distances(cache, distances);
265 calc_brush_strength_factors(cache, brush, distances, factors);
266
267 if (ss.cache->automasking) {
268 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
269 }
270
271 scale_factors(factors, strength);
272
273 calc_brush_texture_factors(ss, brush, positions, factors);
274
275 tls.masks.resize(verts.size());
276 const MutableSpan<float> masks = tls.masks;
277 mask::gather_mask_bmesh(*ss.bm, verts, masks);
278
279 tls.new_masks.resize(verts.size());
280 const MutableSpan<float> new_masks = tls.new_masks;
281 mask::average_neighbor_mask_bmesh(mask_offset, verts, new_masks);
282
283 mask::mix_new_masks(new_masks, factors, masks);
284 mask::clamp_mask(masks);
285
286 mask::scatter_mask_bmesh(masks, *ss.bm, verts);
287}
288
289} // namespace smooth_mask_cc
290
291void do_smooth_mask_brush(const Depsgraph &depsgraph,
292 const Sculpt &sd,
293 Object &object,
294 const IndexMask &node_mask,
295 float brush_strength)
296{
297 SculptSession &ss = *object.sculpt;
298 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
299 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
301 switch (pbvh.type()) {
303 do_smooth_brush_mesh(depsgraph, brush, object, node_mask, brush_strength);
304 break;
305 }
308 for (const float strength : iteration_strengths(brush_strength)) {
310 node_mask.foreach_index(GrainSize(1), [&](const int i) {
311 LocalData &tls = all_tls.local();
312 calc_grids(depsgraph, object, brush, strength, nodes[i], tls);
313 });
314 }
315 bke::pbvh::update_mask_grids(*ss.subdiv_ccg, node_mask, pbvh);
316 pbvh.tag_masks_changed(node_mask);
317 break;
318 }
323 const int mask_offset = CustomData_get_offset_named(
324 &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
325 for (const float strength : iteration_strengths(brush_strength)) {
327 node_mask.foreach_index(GrainSize(1), [&](const int i) {
328 LocalData &tls = all_tls.local();
329 calc_bmesh(depsgraph, object, mask_offset, brush, strength, nodes[i], tls);
330 });
331 }
332 bke::pbvh::update_mask_bmesh(*ss.bm, node_mask, pbvh);
333 pbvh.tag_masks_changed(node_mask);
334 break;
335 }
336 }
337}
338
339} // namespace blender::ed::sculpt_paint
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
@ BRUSH_FRONTFACE
eBrushFalloffShape
@ CD_PROP_FLOAT
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_VERT
Span< T > as_span() const
Definition BLI_array.hh:232
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
void resize(const int64_t new_size)
void append_n_times(const T &value, const int64_t n)
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
Span< NodeT > nodes() const
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:586
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
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 verts[][3]
int count
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
void update_mask_bmesh(const BMesh &bm, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1294
void update_mask_mesh(const Mesh &mesh, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1230
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2502
void update_mask_grids(const SubdivCCG &subdiv_ccg, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1261
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
static void calc_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Brush &brush, const float3 &direction, const float strength, bke::pbvh::BMeshNode &node, LocalData &tls)
void ensure_boundary_info(Object &object)
Definition sculpt.cc:5770
static void calc_grids(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const Brush &brush, const float4 &test_plane, const float strength, bke::pbvh::GridsNode &node, LocalData &tls)
Definition clay.cc:95
void scatter_mask_grids(const Span< float > mask, SubdivCCG &subdiv_ccg, const Span< int > grids)
void mix_new_masks(const Span< float > new_masks, const Span< float > factors, const MutableSpan< float > masks)
Definition paint_mask.cc:98
void scatter_mask_bmesh(const Span< float > mask, const BMesh &bm, const Set< BMVert *, 0 > &verts)
void gather_mask_bmesh(const BMesh &bm, const Set< BMVert *, 0 > &verts, const MutableSpan< float > r_mask)
void gather_mask_grids(const SubdivCCG &subdiv_ccg, const Span< int > grids, const MutableSpan< float > r_mask)
void clamp_mask(const MutableSpan< float > masks)
void average_neighbor_mask_bmesh(const int mask_offset, const Set< BMVert *, 0 > &verts, const MutableSpan< float > new_masks)
static std::array< float, 4 > iteration_strengths(const float strength, const int stroke_iteration)
Definition relax.cc:92
static BLI_NOINLINE void do_smooth_brush_mesh(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, Object &object, const IndexMask &node_mask, const float brush_strength)
Definition smooth.cc:95
static void calc_grids(const Depsgraph &depsgraph, Object &object, const Brush &brush, const float strength, const bke::pbvh::GridsNode &node, LocalData &tls)
static void calc_smooth_masks_faces(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const Span< bool > hide_poly, const Span< int > verts, const Span< float > masks, LocalData &tls, const MutableSpan< float > new_masks)
static void calc_bmesh(const Depsgraph &depsgraph, Object &object, const int mask_offset, const Brush &brush, const float strength, bke::pbvh::BMeshNode &node, LocalData &tls)
static Vector< float > iteration_strengths(const float strength)
static void apply_masks_faces(const Depsgraph &depsgraph, const Brush &brush, const Span< float3 > positions_eval, const Span< float3 > vert_normals, const Span< bool > hide_vert, const bke::pbvh::MeshNode &node, const float strength, Object &object, LocalData &tls, const Span< float > mask_averages, MutableSpan< float > mask)
static void do_smooth_brush_mesh(const Depsgraph &depsgraph, const Brush &brush, Object &object, const IndexMask &node_mask, const float brush_strength)
void neighbor_data_average_mesh(const Span< T > src, const Span< Vector< int > > vert_neighbors, const MutableSpan< T > dst)
void average_data_grids(const SubdivCCG &subdiv_ccg, const Span< T > src, const Span< int > grids, const MutableSpan< T > dst)
MutableSpan< float3 > gather_grids_positions(const SubdivCCG &subdiv_ccg, const Span< int > grids, Vector< float3 > &positions)
void gather_bmesh_positions(const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions)
Definition sculpt.cc:6054
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6889
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:6862
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:6772
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6639
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert_indices, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:6722
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7227
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6122
void do_smooth_mask_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, float brush_strength)
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6082
void calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, MutableSpan< Vector< int > > result)
Definition sculpt.cc:7330
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6581
OffsetIndices< int > create_node_vert_offsets(const Span< bke::pbvh::MeshNode > nodes, const IndexMask &nodes_mask, Array< int > &node_data)
Definition sculpt.cc:7296
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert_indices, MutableSpan< float > factors)
Definition sculpt.cc:6898
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6442
static float brush_strength(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const float feather, const UnifiedPaintSettings &ups, const PaintModeSettings &)
Definition sculpt.cc:2067
CustomData vdata
char falloff_shape
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:427
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
blender::Array< float > masks
std::unique_ptr< auto_mask::Cache > automasking