Blender V5.0
surface_smooth.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#include "DNA_mesh_types.h"
9#include "DNA_object_types.h"
10#include "DNA_scene_types.h"
11
12#include "BKE_mesh.hh"
13#include "BKE_paint.hh"
14#include "BKE_paint_bvh.hh"
15#include "BKE_subdiv_ccg.hh"
16
17#include "BLI_array.hh"
19#include "BLI_task.hh"
20
25
26#include "bmesh.hh"
27
29
30inline namespace surface_smooth_cc {
31
42
44{
45 for (float &factor : factors) {
46 factor = std::clamp(factor, 0.0f, 1.0f);
47 }
48}
49
51 const Sculpt &sd,
52 const Brush &brush,
53 const IndexMask &node_mask,
54 Object &object,
55 const MutableSpan<float3> all_laplacian_disp)
56{
57 const SculptSession &ss = *object.sculpt;
59 const StrokeCache &cache = *ss.cache;
60 const float alpha = brush.surface_smooth_shape_preservation;
61 const float beta = brush.surface_smooth_current_vertex;
63
64 Mesh &mesh = *static_cast<Mesh *>(object.data);
65 const OffsetIndices faces = mesh.faces();
66 const Span<int> corner_verts = mesh.corner_verts();
67 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
68 const MeshAttributeData attribute_data(mesh);
69
70 const PositionDeformData position_data(depsgraph, object);
71 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(depsgraph, object);
72
73 Array<int> node_offset_data;
74 const OffsetIndices node_offsets = create_node_vert_offsets(nodes, node_mask, node_offset_data);
75 Array<float> all_factors(node_offsets.total_size());
76
78 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
79 LocalData &tls = all_tls.local();
80 const Span<int> verts = nodes[i].verts();
81
82 const MutableSpan<float> factors = all_factors.as_mutable_span().slice(node_offsets[pos]);
83 fill_factor_from_hide_and_mask(attribute_data.hide_vert, attribute_data.mask, verts, factors);
84 filter_region_clip_factors(ss, position_data.eval, verts, factors);
85 if (brush.flag & BRUSH_FRONTFACE) {
86 calc_front_face(cache.view_normal_symm, vert_normals, verts, factors);
87 }
88
89 tls.distances.resize(verts.size());
90 const MutableSpan<float> distances = tls.distances;
92 ss, position_data.eval, verts, eBrushFalloffShape(brush.falloff_shape), distances);
93 filter_distances_with_radius(cache.radius, distances, factors);
94 apply_hardness_to_distances(cache, distances);
95 calc_brush_strength_factors(cache, brush, distances, factors);
96
98 depsgraph, object, cache.automasking.get(), nodes[i], verts, factors);
99
100 calc_brush_texture_factors(ss, brush, position_data.eval, verts, factors);
101
102 scale_factors(factors, cache.bstrength);
103 clamp_factors(factors);
104 });
105
106 for ([[maybe_unused]] const int iteration : IndexRange(brush.surface_smooth_iterations)) {
107 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
108 LocalData &tls = all_tls.local();
109 const Span<int> verts = nodes[i].verts();
110 const MutableSpan positions = gather_data_mesh(position_data.eval, verts, tls.positions);
111 const OrigPositionData orig_data = orig_position_data_get_mesh(object, nodes[i]);
112 const Span<float> factors = all_factors.as_span().slice(node_offsets[pos]);
113
115 corner_verts,
116 vert_to_face_map,
117 attribute_data.hide_poly,
118 verts,
119 tls.neighbor_offsets,
120 tls.neighbor_data);
121
122 tls.average_positions.resize(verts.size());
123 const MutableSpan<float3> average_positions = tls.average_positions;
124 smooth::neighbor_data_average_mesh(position_data.eval, neighbors, average_positions);
125
126 tls.laplacian_disp.resize(verts.size());
127 const MutableSpan<float3> laplacian_disp = tls.laplacian_disp;
128 tls.translations.resize(verts.size());
129 const MutableSpan<float3> translations = tls.translations;
131 positions, orig_data.positions, average_positions, alpha, laplacian_disp, translations);
132 scale_translations(translations, factors);
133
134 scatter_data_mesh(laplacian_disp.as_span(), verts, all_laplacian_disp);
135
136 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
137 position_data.deform(translations, verts);
138 });
139
140 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
141 LocalData &tls = all_tls.local();
142 const Span<int> verts = nodes[i].verts();
143 const Span<float> factors = all_factors.as_span().slice(node_offsets[pos]);
144
145 const MutableSpan<float3> laplacian_disp = gather_data_mesh(
146 all_laplacian_disp.as_span(), verts, tls.laplacian_disp);
147
149 corner_verts,
150 vert_to_face_map,
151 attribute_data.hide_poly,
152 verts,
153 tls.neighbor_offsets,
154 tls.neighbor_data);
155
156 tls.average_positions.resize(verts.size());
157 const MutableSpan<float3> average_laplacian_disps = tls.average_positions;
159 all_laplacian_disp.as_span(), neighbors, average_laplacian_disps);
160
161 tls.translations.resize(verts.size());
162 const MutableSpan<float3> translations = tls.translations;
164 laplacian_disp, average_laplacian_disps, beta, translations);
165 scale_translations(translations, factors);
166
167 clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
168 position_data.deform(translations, verts);
169 });
170 }
171}
172
174 const Depsgraph &depsgraph,
175 const Sculpt &sd,
176 const Brush &brush,
177 const IndexMask &node_mask,
178 Object &object,
179 const MutableSpan<float3> all_laplacian_disp)
180{
181 const SculptSession &ss = *object.sculpt;
182 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
183 const StrokeCache &cache = *ss.cache;
184 const float alpha = brush.surface_smooth_shape_preservation;
185 const float beta = brush.surface_smooth_current_vertex;
187
188 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
189
190 Array<int> node_offset_data;
191 const OffsetIndices node_offsets = create_node_vert_offsets(
192 BKE_subdiv_ccg_key_top_level(subdiv_ccg), nodes, node_mask, node_offset_data);
193 Array<float> all_factors(node_offsets.total_size());
194
196 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
197 LocalData &tls = all_tls.local();
198 const Span<int> grids = nodes[i].grids();
199 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
200
201 const MutableSpan<float> factors = all_factors.as_mutable_span().slice(node_offsets[pos]);
202 fill_factor_from_hide_and_mask(subdiv_ccg, grids, factors);
203 filter_region_clip_factors(ss, positions, factors);
204 if (brush.flag & BRUSH_FRONTFACE) {
205 calc_front_face(cache.view_normal_symm, subdiv_ccg, grids, factors);
206 }
207
208 tls.distances.resize(positions.size());
209 const MutableSpan<float> distances = tls.distances;
210 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
211 filter_distances_with_radius(cache.radius, distances, factors);
212 apply_hardness_to_distances(cache, distances);
213 calc_brush_strength_factors(cache, brush, distances, factors);
214
216 depsgraph, object, cache.automasking.get(), nodes[i], grids, factors);
217
218 calc_brush_texture_factors(ss, brush, positions, factors);
219
220 scale_factors(factors, cache.bstrength);
221 clamp_factors(factors);
222 });
223
224 for ([[maybe_unused]] const int iteration : IndexRange(brush.surface_smooth_iterations)) {
225 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
226 LocalData &tls = all_tls.local();
227 const Span<int> grids = nodes[i].grids();
228 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
229 const OrigPositionData orig_data = orig_position_data_get_grids(object, nodes[i]);
230 const Span<float> factors = all_factors.as_span().slice(node_offsets[pos]);
231
232 tls.average_positions.resize(positions.size());
233 const MutableSpan<float3> average_positions = tls.average_positions;
235 subdiv_ccg, subdiv_ccg.positions.as_span(), grids, average_positions);
236
237 tls.laplacian_disp.resize(positions.size());
238 const MutableSpan<float3> laplacian_disp = tls.laplacian_disp;
239 tls.translations.resize(positions.size());
240 const MutableSpan<float3> translations = tls.translations;
242 positions, orig_data.positions, average_positions, alpha, laplacian_disp, translations);
243 scale_translations(translations, factors);
244
245 scatter_data_grids(subdiv_ccg, laplacian_disp.as_span(), grids, all_laplacian_disp);
246
247 clip_and_lock_translations(sd, ss, positions, translations);
248 apply_translations(translations, grids, subdiv_ccg);
249 });
250
251 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
252 LocalData &tls = all_tls.local();
253 const Span<int> grids = nodes[i].grids();
254 const MutableSpan positions = gather_grids_positions(subdiv_ccg, grids, tls.positions);
255 const Span<float> factors = all_factors.as_span().slice(node_offsets[pos]);
256
257 const MutableSpan<float3> laplacian_disp = gather_data_grids(
258 subdiv_ccg, all_laplacian_disp.as_span(), grids, tls.laplacian_disp);
259
260 tls.average_positions.resize(positions.size());
261 const MutableSpan<float3> average_laplacian_disps = tls.average_positions;
263 subdiv_ccg, all_laplacian_disp.as_span(), grids, average_laplacian_disps);
264
265 tls.translations.resize(positions.size());
266 const MutableSpan<float3> translations = tls.translations;
268 laplacian_disp, average_laplacian_disps, beta, translations);
269 scale_translations(translations, factors);
270
271 clip_and_lock_translations(sd, ss, positions, translations);
272 apply_translations(translations, grids, subdiv_ccg);
273 });
274 }
275}
276
278 const Depsgraph &depsgraph,
279 const Sculpt &sd,
280 const Brush &brush,
281 const IndexMask &node_mask,
282 Object &object,
283 const MutableSpan<float3> all_laplacian_disp)
284{
285 const SculptSession &ss = *object.sculpt;
286 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
287 const StrokeCache &cache = *ss.cache;
288 const float alpha = brush.surface_smooth_shape_preservation;
289 const float beta = brush.surface_smooth_current_vertex;
291
292 Array<int> node_offset_data;
294 nodes, node_mask, node_offset_data);
295 Array<float> all_factors(node_offsets.total_size());
296
298 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
299 LocalData &tls = all_tls.local();
301 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
302
303 const MutableSpan<float> factors = all_factors.as_mutable_span().slice(node_offsets[pos]);
305 filter_region_clip_factors(ss, positions, factors);
306 if (brush.flag & BRUSH_FRONTFACE) {
307 calc_front_face(cache.view_normal_symm, verts, factors);
308 }
309
310 tls.distances.resize(positions.size());
311 const MutableSpan<float> distances = tls.distances;
312 calc_brush_distances(ss, positions, eBrushFalloffShape(brush.falloff_shape), distances);
313 filter_distances_with_radius(cache.radius, distances, factors);
314 apply_hardness_to_distances(cache, distances);
315 calc_brush_strength_factors(cache, brush, distances, factors);
316
318 depsgraph, object, cache.automasking.get(), nodes[i], verts, factors);
319
320 calc_brush_texture_factors(ss, brush, positions, factors);
321
322 scale_factors(factors, cache.bstrength);
323 clamp_factors(factors);
324 });
325
326 for ([[maybe_unused]] const int iteration : IndexRange(brush.surface_smooth_iterations)) {
327 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
328 LocalData &tls = all_tls.local();
330 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
331 Array<float3> orig_positions(verts.size());
332 Array<float3> orig_normals(verts.size());
333 orig_position_data_gather_bmesh(*ss.bm_log, verts, orig_positions, orig_normals);
334 const Span<float> factors = all_factors.as_span().slice(node_offsets[pos]);
335
336 tls.average_positions.resize(positions.size());
337 const MutableSpan<float3> average_positions = tls.average_positions;
339
340 tls.laplacian_disp.resize(positions.size());
341 const MutableSpan<float3> laplacian_disp = tls.laplacian_disp;
342 tls.translations.resize(positions.size());
343 const MutableSpan<float3> translations = tls.translations;
345 positions, orig_positions, average_positions, alpha, laplacian_disp, translations);
346 scale_translations(translations, factors);
347
348 scatter_data_bmesh(laplacian_disp.as_span(), verts, all_laplacian_disp);
349
350 clip_and_lock_translations(sd, ss, positions, translations);
351 apply_translations(translations, verts);
352 });
353
354 node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
355 LocalData &tls = all_tls.local();
357 const MutableSpan positions = gather_bmesh_positions(verts, tls.positions);
358 const Span<float> factors = all_factors.as_span().slice(node_offsets[pos]);
359
360 const MutableSpan<float3> laplacian_disp = gather_data_bmesh(
361 all_laplacian_disp.as_span(), verts, tls.laplacian_disp);
362
363 tls.average_positions.resize(positions.size());
364 const MutableSpan<float3> average_laplacian_disps = tls.average_positions;
365 smooth::average_data_bmesh(all_laplacian_disp.as_span(), verts, average_laplacian_disps);
366
367 tls.translations.resize(positions.size());
368 const MutableSpan<float3> translations = tls.translations;
370 laplacian_disp, average_laplacian_disps, beta, translations);
371 scale_translations(translations, factors);
372
373 clip_and_lock_translations(sd, ss, positions, translations);
374 apply_translations(translations, verts);
375 });
376 }
377}
378
379} // namespace surface_smooth_cc
380
381void do_surface_smooth_brush(const Depsgraph &depsgraph,
382 const Sculpt &sd,
383 Object &object,
384 const IndexMask &node_mask)
385{
386 SculptSession &ss = *object.sculpt;
387 bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
388 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
389
390 if (ss.cache->surface_smooth_laplacian_disp.is_empty()) {
392 "Should only be allocated on the first step");
394 float3(0));
395 }
396
397 switch (pbvh.type()) {
400 depsgraph, sd, brush, node_mask, object, ss.cache->surface_smooth_laplacian_disp);
401 break;
404 depsgraph, sd, brush, node_mask, object, ss.cache->surface_smooth_laplacian_disp);
405 break;
406 }
410 depsgraph, sd, brush, node_mask, object, ss.cache->surface_smooth_laplacian_disp);
411 break;
412 }
413 }
414 pbvh.tag_positions_changed(node_mask);
415 pbvh.update_bounds(depsgraph, object);
416}
417
418} // namespace blender::ed::sculpt_paint::brushes
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
A BVH for high poly meshes.
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_NOINLINE
@ BRUSH_FRONTFACE
eBrushFalloffShape
Object is a sort of wrapper for general info.
BPy_StructRNA * depsgraph
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
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:635
Span< NodeT > nodes() const
void update_bounds(const Depsgraph &depsgraph, const Object &object)
Definition pbvh.cc:1386
void foreach_index(Fn &&fn) const
static float verts[][3]
uint pos
ccl_device_inline float beta(const float x, const float y)
Definition math_base.h:661
static char faces[256]
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:3052
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:1059
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)
static BLI_NOINLINE void fill_factor_from_hide_and_mask(const Mesh &mesh, const Span< int > face_indices, const MutableSpan< float > r_factors)
static BLI_NOINLINE void do_surface_smooth_brush_mesh(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const IndexMask &node_mask, Object &object, const MutableSpan< float3 > all_laplacian_disp)
static BLI_NOINLINE void do_surface_smooth_brush_grids(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const IndexMask &node_mask, Object &object, const MutableSpan< float3 > all_laplacian_disp)
static BLI_NOINLINE void clamp_factors(const MutableSpan< float > factors)
static BLI_NOINLINE void do_surface_smooth_brush_bmesh(const Depsgraph &depsgraph, const Sculpt &sd, const Brush &brush, const IndexMask &node_mask, Object &object, const MutableSpan< float3 > all_laplacian_disp)
void do_surface_smooth_brush(const Depsgraph &depsgraph, const Sculpt &sd, Object &object, const IndexMask &node_mask)
void average_data_bmesh(const Span< T > src, const Set< BMVert *, 0 > &verts, const MutableSpan< T > dst)
void neighbor_data_average_mesh(const Span< T > src, const GroupedSpan< int > vert_neighbors, const MutableSpan< T > dst)
void surface_smooth_laplacian_step(const Span< float3 > positions, const Span< float3 > orig_positions, const Span< float3 > average_positions, const float alpha, MutableSpan< float3 > laplacian_disp, MutableSpan< float3 > translations)
void surface_smooth_displace_step(const Span< float3 > laplacian_disp, const Span< float3 > average_laplacian_disp, const float beta, const MutableSpan< float3 > translations)
void average_data_grids(const SubdivCCG &subdiv_ccg, const Span< T > src, const Span< int > grids, const MutableSpan< T > dst)
void neighbor_position_average_bmesh(const Set< BMVert *, 0 > &verts, const MutableSpan< float3 > new_positions)
MutableSpan< float3 > gather_grids_positions(const SubdivCCG &subdiv_ccg, const Span< int > grids, Vector< float3 > &positions)
void scatter_data_bmesh(Span< T > node_data, const Set< BMVert *, 0 > &verts, MutableSpan< T > dst)
Definition sculpt.cc:6461
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 gather_data_grids(const SubdivCCG &subdiv_ccg, Span< T > src, Span< int > grids, MutableSpan< T > node_data)
Definition sculpt.cc:6405
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 gather_data_bmesh(Span< T > src, const Set< BMVert *, 0 > &verts, MutableSpan< T > node_data)
Definition sculpt.cc:6421
void orig_position_data_gather_bmesh(const BMLog &bm_log, const Set< BMVert *, 0 > &verts, MutableSpan< float3 > positions, MutableSpan< float3 > normals)
void scale_translations(MutableSpan< float3 > translations, Span< float > factors)
Definition sculpt.cc:7495
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7512
void clip_and_lock_translations(const Sculpt &sd, const SculptSession &ss, Span< float3 > positions, Span< int > verts, MutableSpan< float3 > translations)
Definition sculpt.cc:7335
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 apply_translations(Span< float3 > translations, Span< int > verts, MutableSpan< float3 > positions)
Definition sculpt.cc:7268
OrigPositionData orig_position_data_get_mesh(const Object &object, const bke::pbvh::MeshNode &node)
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
OrigPositionData orig_position_data_get_grids(const Object &object, const bke::pbvh::GridsNode &node)
void calc_front_face(const float3 &view_normal, Span< float3 > normals, MutableSpan< float > factors)
Definition sculpt.cc:6914
void scatter_data_grids(const SubdivCCG &subdiv_ccg, Span< T > node_data, Span< int > grids, MutableSpan< T > dst)
Definition sculpt.cc:6445
OffsetIndices< int > create_node_vert_offsets_bmesh(Span< bke::pbvh::BMeshNode > nodes, const IndexMask &node_mask, Array< int > &node_data)
Definition sculpt.cc:7585
VecBase< float, 3 > float3
int SCULPT_vertex_count_get(const Object &object)
Definition sculpt.cc:151
bool SCULPT_stroke_is_first_brush_step(const blender::ed::sculpt_paint::StrokeCache &cache)
Definition sculpt.cc:536
char falloff_shape
int surface_smooth_iterations
float surface_smooth_current_vertex
float surface_smooth_shape_preservation
blender::ed::sculpt_paint::StrokeCache * cache
Definition BKE_paint.hh:417
BMLog * bm_log
Definition BKE_paint.hh:392
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:395
std::unique_ptr< auto_mask::Cache > automasking
i
Definition text_draw.cc:230