Blender V5.0
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
22
23#include "bmesh.hh"
24
26
27inline namespace smooth_mask_cc {
28
38
39/* TODO: Extract this and the similarly named smooth.cc function
40 * to a common location. */
41static Vector<float> iteration_strengths(const float strength)
42{
43 constexpr int max_iterations = 4;
44
45 BLI_assert_msg(strength >= 0.0f,
46 "The smooth brush expects a non-negative strength to behave properly");
47 const float clamped_strength = std::min(strength, 1.0f);
48
49 const int count = int(clamped_strength * max_iterations);
50 const float last = max_iterations * (clamped_strength - float(count) / max_iterations);
52 result.append_n_times(1.0f, count);
53 result.append(last);
54 return result;
55}
56
57static void apply_masks_faces(const Depsgraph &depsgraph,
58 const Brush &brush,
59 const Span<float3> positions_eval,
60 const Span<float3> vert_normals,
61 const Span<bool> hide_vert,
62 const bke::pbvh::MeshNode &node,
63 const float strength,
64 Object &object,
65 LocalData &tls,
66 const Span<float> mask_averages,
68{
69 SculptSession &ss = *object.sculpt;
70 const StrokeCache &cache = *ss.cache;
71
72 const Span<int> verts = node.verts();
73
74 tls.factors.resize(verts.size());
75 const MutableSpan<float> factors = tls.factors;
76 fill_factor_from_hide(hide_vert, verts, factors);
77 filter_region_clip_factors(ss, positions_eval, verts, factors);
78 if (brush.flag & BRUSH_FRONTFACE) {
79 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
80 }
81
82 tls.distances.resize(verts.size());
83 const MutableSpan<float> distances = tls.distances;
85 ss, positions_eval, verts, eBrushFalloffShape(brush.falloff_shape), distances);
86 filter_distances_with_radius(cache.radius, distances, factors);
87 apply_hardness_to_distances(cache, distances);
88 calc_brush_strength_factors(cache, brush, distances, factors);
89
91 depsgraph, object, ss.cache->automasking.get(), node, verts, factors);
92
93 scale_factors(factors, strength);
94
95 calc_brush_texture_factors(ss, brush, positions_eval, verts, factors);
96
97 tls.new_masks.resize(verts.size());
98 const MutableSpan<float> new_masks = tls.new_masks;
99 gather_data_mesh(mask.as_span(), verts, new_masks);
100
101 mask::mix_new_masks(mask_averages, factors, new_masks);
102 mask::clamp_mask(new_masks);
103
104 scatter_data_mesh(new_masks.as_span(), verts, mask);
105}
106
107static void do_smooth_brush_mesh(const Depsgraph &depsgraph,
108 const Brush &brush,
109 Object &object,
110 const IndexMask &node_mask,
111 const float brush_strength)
112{
113 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
115 Mesh &mesh = *static_cast<Mesh *>(object.data);
116 const OffsetIndices faces = mesh.faces();
117 const Span<int> corner_verts = mesh.corner_verts();
118 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
119 const bke::AttributeAccessor attributes = mesh.attributes();
120 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
121
122 const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
123 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
124
125 Array<int> node_vert_offset_data;
126 OffsetIndices node_vert_offsets = create_node_vert_offsets(
127 nodes, node_mask, node_vert_offset_data);
128 Array<float> new_masks(node_vert_offsets.total_size());
129
130 bke::MutableAttributeAccessor write_attributes = mesh.attributes_for_write();
131
133 ".sculpt_mask");
134 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
135
137 for (const float strength : iteration_strengths(brush_strength)) {
138 /* Calculate new masks into a separate array to avoid non-threadsafe access of values from
139 * neighboring nodes. */
140 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
141 LocalData &tls = all_tls.local();
143 corner_verts,
144 vert_to_face_map,
145 hide_poly,
146 nodes[i].verts(),
147 tls.neighbor_offsets,
148 tls.neighbor_data);
150 mask.span.as_span(),
151 neighbors,
152 new_masks.as_mutable_span().slice(node_vert_offsets[pos]));
153 });
154
155 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
156 LocalData &tls = all_tls.local();
158 brush,
159 positions_eval,
160 vert_normals,
161 hide_vert,
162 nodes[i],
163 strength,
164 object,
165 tls,
166 new_masks.as_span().slice(node_vert_offsets[pos]),
167 mask.span);
168 });
169 }
170 bke::pbvh::update_mask_mesh(mesh, node_mask, pbvh);
171 pbvh.tag_masks_changed(node_mask);
172 mask.finish();
173}
174
175static void calc_grids(const Depsgraph &depsgraph,
176 Object &object,
177 const Brush &brush,
178 const float strength,
179 const bke::pbvh::GridsNode &node,
180 LocalData &tls)
181{
182 SculptSession &ss = *object.sculpt;
183 const StrokeCache &cache = *ss.cache;
184 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
185
186 const Span<int> grids = node.grids();
187 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
188
189 tls.factors.resize(positions.size());
190 const MutableSpan<float> factors = tls.factors;
191 fill_factor_from_hide(subdiv_ccg, grids, factors);
192 filter_region_clip_factors(ss, positions, factors);
193 if (brush.flag & BRUSH_FRONTFACE) {
194 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
195 }
196
197 tls.distances.resize(positions.size());
198 const MutableSpan<float> distances = tls.distances;
199 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
200 filter_distances_with_radius(cache.radius, distances, factors);
201 apply_hardness_to_distances(cache, distances);
202 calc_brush_strength_factors(cache, brush, distances, factors);
203
204 if (ss.cache->automasking) {
206 depsgraph, object, cache.automasking.get(), node, grids, factors);
207 }
208
209 scale_factors(factors, strength);
210
211 calc_brush_texture_factors(ss, brush, positions, factors);
212
213 tls.masks.resize(positions.size());
214 const MutableSpan<float> masks = tls.masks;
215 mask::gather_mask_grids(subdiv_ccg, grids, masks);
216
217 tls.new_masks.resize(positions.size());
218 const MutableSpan<float> new_masks = tls.new_masks;
219 smooth::average_data_grids(subdiv_ccg, subdiv_ccg.masks.as_span(), grids, new_masks);
220
221 mask::mix_new_masks(new_masks, factors, masks);
222 mask::clamp_mask(masks);
223
224 mask::scatter_mask_grids(masks, subdiv_ccg, grids);
225}
226
227static void calc_bmesh(const Depsgraph &depsgraph,
228 Object &object,
229 const int mask_offset,
230 const Brush &brush,
231 const float strength,
233 LocalData &tls)
234{
235 SculptSession &ss = *object.sculpt;
236 const StrokeCache &cache = *ss.cache;
237
239
240 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
241
242 tls.factors.resize(verts.size());
243 const MutableSpan<float> factors = tls.factors;
245 filter_region_clip_factors(ss, positions, factors);
246 if (brush.flag & BRUSH_FRONTFACE) {
247 calc_front_face(cache.view_normal_symm, verts, factors);
248 }
249
250 tls.distances.resize(verts.size());
251 const MutableSpan<float> distances = tls.distances;
252 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
253 filter_distances_with_radius(cache.radius, distances, factors);
254 apply_hardness_to_distances(cache, distances);
255 calc_brush_strength_factors(cache, brush, distances, factors);
256
257 if (ss.cache->automasking) {
258 auto_mask::calc_vert_factors(depsgraph, object, cache.automasking.get(), node, verts, factors);
259 }
260
261 scale_factors(factors, strength);
262
263 calc_brush_texture_factors(ss, brush, positions, factors);
264
265 tls.masks.resize(verts.size());
266 const MutableSpan<float> masks = tls.masks;
267 mask::gather_mask_bmesh(*ss.bm, verts, masks);
268
269 tls.new_masks.resize(verts.size());
270 const MutableSpan<float> new_masks = tls.new_masks;
271 mask::average_neighbor_mask_bmesh(mask_offset, verts, new_masks);
272
273 mask::mix_new_masks(new_masks, factors, masks);
274 mask::clamp_mask(masks);
275
276 mask::scatter_mask_bmesh(masks, *ss.bm, verts);
277}
278
279} // namespace smooth_mask_cc
280
281void do_smooth_mask_brush(const Depsgraph &depsgraph,
282 const Sculpt &sd,
283 Object &object,
284 const IndexMask &node_mask,
285 float brush_strength)
286{
287 SculptSession &ss = *object.sculpt;
288 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
289 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
291 switch (pbvh.type()) {
293 do_smooth_brush_mesh(depsgraph, brush, object, node_mask, brush_strength);
294 break;
295 }
298 for (const float strength : iteration_strengths(brush_strength)) {
300 node_mask.foreach_index(GrainSize(1), [&](const int i) {
301 LocalData &tls = all_tls.local();
302 calc_grids(depsgraph, object, brush, strength, nodes[i], tls);
303 });
304 }
305 bke::pbvh::update_mask_grids(*ss.subdiv_ccg, node_mask, pbvh);
306 pbvh.tag_masks_changed(node_mask);
307 break;
308 }
312 const int mask_offset = CustomData_get_offset_named(
313 &ss.bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
314 for (const float strength : iteration_strengths(brush_strength)) {
316 node_mask.foreach_index(GrainSize(1), [&](const int i) {
317 LocalData &tls = all_tls.local();
318 calc_bmesh(depsgraph, object, mask_offset, brush, strength, nodes[i], tls);
319 });
320 }
321 bke::pbvh::update_mask_bmesh(*ss.bm, node_mask, pbvh);
322 pbvh.tag_masks_changed(node_mask);
323 break;
324 }
325 }
326}
327
328} // namespace blender::ed::sculpt_paint::brushes
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:650
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:53
@ BRUSH_FRONTFACE
eBrushFalloffShape
@ CD_PROP_FLOAT
BPy_StructRNA * depsgraph
Span< T > as_span() const
Definition BLI_array.hh:243
void resize(const int64_t new_size)
Span< T > as_span() const
Definition BLI_array.hh:243
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
Span< NodeT > nodes() const
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:669
void foreach_index(Fn &&fn) const
nullptr float
static float verts[][3]
uint pos
int count
static char faces[256]
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
void update_mask_bmesh(const BMesh &bm, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1496
void update_mask_mesh(const Mesh &mesh, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1432
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
void update_mask_grids(const SubdivCCG &subdiv_ccg, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1463
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1040
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &automasking, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
void ensure_boundary_info(Object &object)
Definition sculpt.cc:6073
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)
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:93
static std::array< float, 4 > iteration_strengths(const float strength, const int stroke_iteration)
Definition relax.cc:90
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:80
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 void do_smooth_brush_mesh(const Depsgraph &depsgraph, const Brush &brush, Object &object, const IndexMask &node_mask, const float brush_strength)
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 calc_grids(const Depsgraph &depsgraph, Object &object, const Brush &brush, const float strength, const bke::pbvh::GridsNode &node, LocalData &tls)
void do_smooth_mask_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask, float brush_strength)
void scatter_mask_grids(const Span< float > mask, SubdivCCG &subdiv_ccg, const Span< int > grids)
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 mix_new_masks(const Span< float > new_masks, const float factor, const MutableSpan< float > masks)
Definition paint_mask.cc:95
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)
void neighbor_data_average_mesh(const Span< T > src, const GroupedSpan< 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:6367
void calc_brush_strength_factors(const StrokeCache &cache, const Brush &brush, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7183
void vert_random_access_ensure(Object &object)
Definition sculpt.cc:141
void apply_hardness_to_distances(float radius, float hardness, MutableSpan< float > distances)
Definition sculpt.cc:7156
GroupedSpan< int > calc_vert_neighbors(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face, Span< bool > hide_poly, Span< int > verts, Vector< int > &r_offset_data, Vector< int > &r_data)
Definition sculpt.cc:7597
void filter_distances_with_radius(float radius, Span< float > distances, MutableSpan< float > factors)
Definition sculpt.cc:7105
void filter_region_clip_factors(const SculptSession &ss, Span< float3 > vert_positions, Span< int > verts, MutableSpan< float > factors)
Definition sculpt.cc:6972
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6435
void calc_brush_distances(const SculptSession &ss, Span< float3 > vert_positions, Span< int > vert, eBrushFalloffShape falloff_shape, MutableSpan< float > r_distances)
Definition sculpt.cc:7055
OffsetIndices< int > create_node_vert_offsets(Span< bke::pbvh::MeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7563
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6395
void calc_brush_texture_factors(const SculptSession &ss, const Brush &brush, Span< float3 > vert_positions, Span< int > vert, MutableSpan< float > factors)
Definition sculpt.cc:7195
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6914
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6775
static float brush_strength(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const float feather, const PaintModeSettings &)
Definition sculpt.cc:2175
CustomData vdata
char falloff_shape
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
blender::Array< float > masks
std::unique_ptr< auto_mask::Cache > automasking
i
Definition text_draw.cc:230