Blender V5.0
MOD_correctivesmooth.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "BLI_math_base.hh"
12#include "BLI_math_matrix.h"
13#include "BLI_math_vector.h"
14#include "BLI_utildefines.h"
15
16#include "BLT_translation.hh"
17
18#include "DNA_defaults.h"
19#include "DNA_mesh_types.h"
20#include "DNA_meshdata_types.h"
21#include "DNA_object_types.h"
22#include "DNA_screen_types.h"
23
24#include "MEM_guardedalloc.h"
25
26#include "BKE_deform.hh"
27#include "BKE_editmesh.hh"
28
30#include "UI_resources.hh"
31
32#include "RNA_access.hh"
33#include "RNA_prototypes.hh"
34
35#include "MOD_modifiertypes.hh"
36#include "MOD_ui_common.hh"
37#include "MOD_util.hh"
38
39#include "BLO_read_write.hh"
40
42
43// #define DEBUG_TIME
44
45#ifdef DEBUG_TIME
46# include "BLI_time.h"
47# include "BLI_time_utildefines.h"
48#endif
49
50#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
51
62
63static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
64{
67
69
72 &tcsmd->bind_coords,
74
75 tcsmd->delta_cache.deltas = nullptr;
76 tcsmd->delta_cache.deltas_num = 0;
77}
78
86
92
93static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
94{
96
97 /* ask for vertex groups if we need them */
98 if (csmd->defgrp_name[0] != '\0') {
99 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
100 }
101}
102
103/* check individual weights for changes and cache values */
104static void mesh_get_weights(const MDeformVert *dvert,
105 const int defgrp_index,
106 const uint verts_num,
107 const bool use_invert_vgroup,
108 float *smooth_weights)
109{
110 uint i;
111
112 for (i = 0; i < verts_num; i++, dvert++) {
113 const float w = BKE_defvert_find_weight(dvert, defgrp_index);
114
115 if (use_invert_vgroup == false) {
116 smooth_weights[i] = w;
117 }
118 else {
119 smooth_weights[i] = 1.0f - w;
120 }
121 }
122}
123
124static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
125{
126 const blender::Span<blender::int2> edges = mesh->edges();
127 const blender::OffsetIndices faces = mesh->faces();
128 const blender::Span<int> corner_edges = mesh->corner_edges();
129
130 /* Flag boundary edges so only boundaries are set to 1. */
131 uint8_t *boundaries = MEM_calloc_arrayN<uint8_t>(size_t(edges.size()), __func__);
132
133 for (const int64_t i : faces.index_range()) {
134 for (const int edge : corner_edges.slice(faces[i])) {
135 uint8_t *e_value = &boundaries[edge];
136 *e_value |= uint8_t((*e_value) + 1);
137 }
138 }
139
140 for (const int64_t i : edges.index_range()) {
141 if (boundaries[i] == 1) {
142 smooth_weights[edges[i][0]] = 0.0f;
143 smooth_weights[edges[i][1]] = 0.0f;
144 }
145 }
146
147 MEM_freeN(boundaries);
148}
149
150/* -------------------------------------------------------------------- */
151/* Simple Weighted Smoothing
152 *
153 * (average of surrounding verts)
154 */
156 Mesh *mesh,
158 const float *smooth_weights,
159 uint iterations)
160{
161 const float lambda = csmd->lambda;
162 int i;
163
164 const int edges_num = mesh->edges_num;
165 const blender::Span<blender::int2> edges = mesh->edges();
166
167 struct SmoothingData_Simple {
168 float delta[3];
169 };
170 SmoothingData_Simple *smooth_data = MEM_calloc_arrayN<SmoothingData_Simple>(
171 size_t(vertexCos.size()), __func__);
172
173 float *vertex_edge_count_div = MEM_calloc_arrayN<float>(size_t(vertexCos.size()), __func__);
174
175 /* calculate as floats to avoid int->float conversion in #smooth_iter */
176 for (i = 0; i < edges_num; i++) {
177 vertex_edge_count_div[edges[i][0]] += 1.0f;
178 vertex_edge_count_div[edges[i][1]] += 1.0f;
179 }
180
181 /* a little confusing, but we can include 'lambda' and smoothing weight
182 * here to avoid multiplying for every iteration */
183 if (smooth_weights == nullptr) {
184 for (i = 0; i < vertexCos.size(); i++) {
185 vertex_edge_count_div[i] = lambda * (vertex_edge_count_div[i] ?
186 (1.0f / vertex_edge_count_div[i]) :
187 1.0f);
188 }
189 }
190 else {
191 for (i = 0; i < vertexCos.size(); i++) {
192 vertex_edge_count_div[i] = smooth_weights[i] * lambda *
193 (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) :
194 1.0f);
195 }
196 }
197
198 /* -------------------------------------------------------------------- */
199 /* Main Smoothing Loop */
200
201 while (iterations--) {
202 for (i = 0; i < edges_num; i++) {
203 SmoothingData_Simple *sd_v1;
204 SmoothingData_Simple *sd_v2;
205 float edge_dir[3];
206
207 sub_v3_v3v3(edge_dir, vertexCos[edges[i][1]], vertexCos[edges[i][0]]);
208
209 sd_v1 = &smooth_data[edges[i][0]];
210 sd_v2 = &smooth_data[edges[i][1]];
211
212 add_v3_v3(sd_v1->delta, edge_dir);
213 sub_v3_v3(sd_v2->delta, edge_dir);
214 }
215
216 for (i = 0; i < vertexCos.size(); i++) {
217 SmoothingData_Simple *sd = &smooth_data[i];
218 madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]);
219 /* zero for the next iteration (saves memset on entire array) */
220 memset(sd, 0, sizeof(*sd));
221 }
222 }
223
224 MEM_freeN(vertex_edge_count_div);
225 MEM_freeN(smooth_data);
226}
227
228/* -------------------------------------------------------------------- */
229/* Edge-Length Weighted Smoothing
230 */
232 Mesh *mesh,
234 const float *smooth_weights,
235 uint iterations)
236{
237 const float eps = FLT_EPSILON * 10.0f;
238 const uint edges_num = uint(mesh->edges_num);
239 /* NOTE: the way this smoothing method works, its approx half as strong as the simple-smooth,
240 * and 2.0 rarely spikes, double the value for consistent behavior. */
241 const float lambda = csmd->lambda * 2.0f;
242 const blender::Span<blender::int2> edges = mesh->edges();
243 uint i;
244
245 struct SmoothingData_Weighted {
246 float delta[3];
247 float edge_length_sum;
248 };
249 SmoothingData_Weighted *smooth_data = MEM_calloc_arrayN<SmoothingData_Weighted>(
250 size_t(vertexCos.size()), __func__);
251
252 /* calculate as floats to avoid int->float conversion in #smooth_iter */
253 float *vertex_edge_count = MEM_calloc_arrayN<float>(size_t(vertexCos.size()), __func__);
254 for (i = 0; i < edges_num; i++) {
255 vertex_edge_count[edges[i][0]] += 1.0f;
256 vertex_edge_count[edges[i][1]] += 1.0f;
257 }
258
259 /* -------------------------------------------------------------------- */
260 /* Main Smoothing Loop */
261
262 while (iterations--) {
263 for (i = 0; i < edges_num; i++) {
264 SmoothingData_Weighted *sd_v1;
265 SmoothingData_Weighted *sd_v2;
266 float edge_dir[3];
267 float edge_dist;
268
269 sub_v3_v3v3(edge_dir, vertexCos[edges[i][1]], vertexCos[edges[i][0]]);
270 edge_dist = len_v3(edge_dir);
271
272 /* weight by distance */
273 mul_v3_fl(edge_dir, edge_dist);
274
275 sd_v1 = &smooth_data[edges[i][0]];
276 sd_v2 = &smooth_data[edges[i][1]];
277
278 add_v3_v3(sd_v1->delta, edge_dir);
279 sub_v3_v3(sd_v2->delta, edge_dir);
280
281 sd_v1->edge_length_sum += edge_dist;
282 sd_v2->edge_length_sum += edge_dist;
283 }
284
285 if (smooth_weights == nullptr) {
286 /* fast-path */
287 for (i = 0; i < vertexCos.size(); i++) {
288 SmoothingData_Weighted *sd = &smooth_data[i];
289 /* Divide by sum of all neighbor distances (weighted) and amount of neighbors,
290 * (mean average). */
291 const float div = sd->edge_length_sum * vertex_edge_count[i];
292 if (div > eps) {
293#if 0
294 /* first calculate the new location */
295 mul_v3_fl(sd->delta, 1.0f / div);
296 /* then interpolate */
297 madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
298#else
299 /* do this in one step */
300 madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
301#endif
302 }
303 /* zero for the next iteration (saves memset on entire array) */
304 memset(sd, 0, sizeof(*sd));
305 }
306 }
307 else {
308 for (i = 0; i < vertexCos.size(); i++) {
309 SmoothingData_Weighted *sd = &smooth_data[i];
310 const float div = sd->edge_length_sum * vertex_edge_count[i];
311 if (div > eps) {
312 const float lambda_w = lambda * smooth_weights[i];
313 madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
314 }
315
316 memset(sd, 0, sizeof(*sd));
317 }
318 }
319 }
320
321 MEM_freeN(vertex_edge_count);
322 MEM_freeN(smooth_data);
323}
324
326 Mesh *mesh,
328 const float *smooth_weights,
329 uint iterations)
330{
331 switch (csmd->smooth_type) {
333 smooth_iter__length_weight(csmd, mesh, vertexCos, smooth_weights, iterations);
334 break;
335
336 /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
337 default:
338 smooth_iter__simple(csmd, mesh, vertexCos, smooth_weights, iterations);
339 break;
340 }
341}
342
344 Mesh *mesh,
345 const MDeformVert *dvert,
346 const int defgrp_index,
348{
349 float *smooth_weights = nullptr;
350
351 if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
352
353 smooth_weights = MEM_malloc_arrayN<float>(size_t(vertexCos.size()), __func__);
354
355 if (dvert) {
356 mesh_get_weights(dvert,
357 defgrp_index,
358 uint(vertexCos.size()),
360 smooth_weights);
361 }
362 else {
363 copy_vn_fl(smooth_weights, int(vertexCos.size()), 1.0f);
364 }
365
367 mesh_get_boundaries(mesh, smooth_weights);
368 }
369 }
370
371 smooth_iter(csmd, mesh, vertexCos, smooth_weights, uint(csmd->repeat));
372
373 if (smooth_weights) {
374 MEM_freeN(smooth_weights);
375 }
376}
377
382static bool calc_tangent_loop(const float v_dir_prev[3],
383 const float v_dir_next[3],
384 float r_tspace[3][3])
385{
386 if (UNLIKELY(compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f))) {
387 /* As there are no weights, the value doesn't matter just initialize it. */
388 unit_m3(r_tspace);
389 return false;
390 }
391
392 copy_v3_v3(r_tspace[0], v_dir_prev);
393 copy_v3_v3(r_tspace[1], v_dir_next);
394
395 cross_v3_v3v3(r_tspace[2], v_dir_prev, v_dir_next);
396 normalize_v3(r_tspace[2]);
397
398 /* Make orthogonal using `r_tspace[2]` as a basis.
399 *
400 * NOTE: while it seems more logical to use `v_dir_prev` & `v_dir_next` as separate X/Y axis
401 * (instead of combining them as is done here). It's not necessary as the directions of the
402 * axis aren't important as long as the difference between tangent matrices is equivalent.
403 * Some computations can be skipped by combining the two directions,
404 * using the cross product for the 3rd axes. */
405 add_v3_v3(r_tspace[0], r_tspace[1]);
406 normalize_v3(r_tspace[0]);
407 cross_v3_v3v3(r_tspace[1], r_tspace[2], r_tspace[0]);
408
409 return true;
410}
411
418static void calc_tangent_spaces(const Mesh *mesh,
420 float (*r_tangent_spaces)[3][3],
421 float *r_tangent_weights,
422 float *r_tangent_weights_per_vertex)
423{
424 const uint mvert_num = uint(mesh->verts_num);
425 const blender::OffsetIndices faces = mesh->faces();
426 blender::Span<int> corner_verts = mesh->corner_verts();
427
428 if (r_tangent_weights_per_vertex != nullptr) {
429 copy_vn_fl(r_tangent_weights_per_vertex, int(mvert_num), 0.0f);
430 }
431
432 for (const int64_t i : faces.index_range()) {
433 const blender::IndexRange face = faces[i];
434 int next_corner = int(face.start());
435 int term_corner = next_corner + int(face.size());
436 int prev_corner = term_corner - 2;
437 int curr_corner = term_corner - 1;
438
439 /* loop directions */
440 float v_dir_prev[3], v_dir_next[3];
441
442 /* needed entering the loop */
444 v_dir_prev, vertexCos[corner_verts[prev_corner]], vertexCos[corner_verts[curr_corner]]);
445 normalize_v3(v_dir_prev);
446
447 for (; next_corner != term_corner;
448 prev_corner = curr_corner, curr_corner = next_corner, next_corner++)
449 {
450 float (*ts)[3] = r_tangent_spaces[curr_corner];
451
452 /* re-use the previous value */
453#if 0
455 v_dir_prev, vertexCos[corner_verts[prev_corner]], vertexCos[corner_verts[curr_corner]]);
456 normalize_v3(v_dir_prev);
457#endif
459 v_dir_next, vertexCos[corner_verts[curr_corner]], vertexCos[corner_verts[next_corner]]);
460 normalize_v3(v_dir_next);
461
462 if (calc_tangent_loop(v_dir_prev, v_dir_next, ts)) {
463 if (r_tangent_weights != nullptr) {
464 const float weight = fabsf(
465 blender::math::safe_acos_approx(dot_v3v3(v_dir_next, v_dir_prev)));
466 r_tangent_weights[curr_corner] = weight;
467 r_tangent_weights_per_vertex[corner_verts[curr_corner]] += weight;
468 }
469 }
470 else {
471 if (r_tangent_weights != nullptr) {
472 r_tangent_weights[curr_corner] = 0;
473 }
474 }
475
476 copy_v3_v3(v_dir_prev, v_dir_next);
477 }
478 }
479}
480
482{
483 csmd->delta_cache.lambda = csmd->lambda;
484 csmd->delta_cache.repeat = csmd->repeat;
485 csmd->delta_cache.flag = csmd->flag;
486 csmd->delta_cache.smooth_type = csmd->smooth_type;
487 csmd->delta_cache.rest_source = csmd->rest_source;
488}
489
491{
492 return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat &&
493 csmd->delta_cache.flag == csmd->flag &&
494 csmd->delta_cache.smooth_type == csmd->smooth_type &&
495 csmd->delta_cache.rest_source == csmd->rest_source);
496}
497
503 Mesh *mesh,
504 const MDeformVert *dvert,
505 const int defgrp_index,
506 const blender::Span<blender::float3> rest_coords)
507{
508 const blender::Span<int> corner_verts = mesh->corner_verts();
509
510 blender::Array<blender::float3> smooth_vertex_coords(rest_coords);
511
512 uint l_index;
513
514 float (*tangent_spaces)[3][3] = MEM_malloc_arrayN<float[3][3]>(size_t(corner_verts.size()),
515 __func__);
516
517 if (csmd->delta_cache.deltas_num != uint(corner_verts.size())) {
519 }
520
521 /* allocate deltas if they have not yet been allocated, otherwise we will just write over them */
522 if (!csmd->delta_cache.deltas) {
523 csmd->delta_cache.deltas_num = uint(corner_verts.size());
524 csmd->delta_cache.deltas = MEM_malloc_arrayN<float[3]>(size_t(corner_verts.size()), __func__);
525 }
526
527 smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords);
528
529 calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces, nullptr, nullptr);
530
531 copy_vn_fl(&csmd->delta_cache.deltas[0][0], int(corner_verts.size()) * 3, 0.0f);
532
533 for (l_index = 0; l_index < corner_verts.size(); l_index++) {
534 const int v_index = corner_verts[l_index];
535 float delta[3];
536 sub_v3_v3v3(delta, rest_coords[v_index], smooth_vertex_coords[v_index]);
537
538 float imat[3][3];
539 if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[l_index]))) {
540 transpose_m3_m3(imat, tangent_spaces[l_index]);
541 }
542 mul_v3_m3v3(csmd->delta_cache.deltas[l_index], imat, delta);
543 }
544
545 MEM_SAFE_FREE(tangent_spaces);
546}
547
549 Depsgraph *depsgraph,
550 Object *ob,
551 Mesh *mesh,
553 BMEditMesh *em)
554{
555 using namespace blender;
557
558 const bool force_delta_cache_update =
559 /* XXX, take care! if mesh data itself changes we need to forcefully recalculate deltas */
560 !cache_settings_equal(csmd) ||
562 (((ID *)ob->data)->recalc & ID_RECALC_ALL));
563
564 blender::Span<int> corner_verts = mesh->corner_verts();
565
566 bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
567 const MDeformVert *dvert = nullptr;
568 int defgrp_index;
569
570 MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index);
571
572 /* if rest bind_coords not are defined, set them (only run during bind) */
574 /* signal to recalculate, whoever sets MUST also free bind coords */
575 (csmd->bind_coords_num == uint(-1)))
576 {
578 BLI_assert(csmd->bind_coords == nullptr);
579 csmd->bind_coords = MEM_malloc_arrayN<float[3]>(size_t(vertexCos.size()), __func__);
581 memcpy(csmd->bind_coords, vertexCos.data(), size_t(vertexCos.size_in_bytes()));
582 csmd->bind_coords_num = uint(vertexCos.size());
583 BLI_assert(csmd->bind_coords != nullptr);
584
585 /* Copy bound data to the original modifier. */
590 &csmd_orig->bind_coords,
591 &csmd_orig->bind_coords_sharing_info);
592
593 csmd_orig->bind_coords_num = csmd->bind_coords_num;
594 }
595 else {
596 BKE_modifier_set_error(ob, md, "Attempt to bind from inactive dependency graph");
597 }
598 }
599
600 if (UNLIKELY(use_only_smooth)) {
601 smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos);
602 return;
603 }
604
606 (csmd->bind_coords == nullptr))
607 {
608 BKE_modifier_set_error(ob, md, "Bind data required");
609 goto error;
610 }
611
612 /* If the number of verts has changed, the bind is invalid, so we do nothing */
614 if (csmd->bind_coords_num != vertexCos.size()) {
616 md,
617 "Bind vertex count mismatch: %u to %u",
618 csmd->bind_coords_num,
619 uint(vertexCos.size()));
620 goto error;
621 }
622 }
623 else {
624 /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
625 if (ob->type != OB_MESH) {
626 BKE_modifier_set_error(ob, md, "Object is not a mesh");
627 goto error;
628 }
629 else {
630 const int me_numVerts = (em) ? em->bm->totvert : ((Mesh *)ob->data)->verts_num;
631
632 if (me_numVerts != vertexCos.size()) {
634 md,
635 "Original vertex count mismatch: %u to %u",
636 uint(me_numVerts),
637 uint(vertexCos.size()));
638 goto error;
639 }
640 }
641 }
642
643 /* check to see if our deltas are still valid */
644 if (!csmd->delta_cache.deltas || (csmd->delta_cache.deltas_num != corner_verts.size()) ||
645 force_delta_cache_update)
646 {
647 blender::Array<blender::float3> rest_coords_alloc;
649
651
653 /* caller needs to do sanity check here */
654 csmd->bind_coords_num = uint(vertexCos.size());
655 rest_coords = {reinterpret_cast<const blender::float3 *>(csmd->bind_coords),
656 csmd->bind_coords_num};
657 }
658 else {
659 if (em) {
660 rest_coords_alloc = BKE_editmesh_vert_coords_alloc_orco(em);
661 rest_coords = rest_coords_alloc;
662 }
663 else {
664 const Mesh *object_mesh = static_cast<const Mesh *>(ob->data);
665 rest_coords = object_mesh->vert_positions();
666 }
667 }
668
669#ifdef DEBUG_TIME
670 TIMEIT_START(corrective_smooth_deltas);
671#endif
672
673 calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords);
674
675#ifdef DEBUG_TIME
676 TIMEIT_END(corrective_smooth_deltas);
677#endif
678 }
679
681 /* this could be a check, but at this point it _must_ be valid */
682 BLI_assert(csmd->bind_coords_num == vertexCos.size() && csmd->delta_cache.deltas);
683 }
684
685#ifdef DEBUG_TIME
686 TIMEIT_START(corrective_smooth);
687#endif
688
689 /* do the actual delta mush */
690 smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos);
691
692 {
693
694 const float scale = csmd->scale;
695
696 float (*tangent_spaces)[3][3] = MEM_malloc_arrayN<float[3][3]>(size_t(corner_verts.size()),
697 __func__);
698 float *tangent_weights = MEM_malloc_arrayN<float>(size_t(corner_verts.size()), __func__);
699 float *tangent_weights_per_vertex = MEM_malloc_arrayN<float>(size_t(vertexCos.size()),
700 __func__);
701
703 mesh, vertexCos, tangent_spaces, tangent_weights, tangent_weights_per_vertex);
704
705 for (const int64_t l_index : corner_verts.index_range()) {
706 const int v_index = corner_verts[l_index];
707 const float weight = tangent_weights[l_index] / tangent_weights_per_vertex[v_index];
708 if (UNLIKELY(!(weight > 0.0f))) {
709 /* Catches zero & divide by zero. */
710 continue;
711 }
712
713 float delta[3];
714 mul_v3_m3v3(delta, tangent_spaces[l_index], csmd->delta_cache.deltas[l_index]);
715 mul_v3_fl(delta, weight);
716 madd_v3_v3fl(vertexCos[v_index], delta, scale);
717 }
718
719 MEM_freeN(tangent_spaces);
720 MEM_freeN(tangent_weights);
721 MEM_freeN(tangent_weights_per_vertex);
722 }
723
724#ifdef DEBUG_TIME
725 TIMEIT_END(corrective_smooth);
726#endif
727
728 return;
729
730 /* when the modifier fails to execute */
731error:
733 csmd->delta_cache.deltas_num = 0;
734}
735
737 const ModifierEvalContext *ctx,
738 Mesh *mesh,
740{
741 correctivesmooth_modifier_do(md, ctx->depsgraph, ctx->object, mesh, positions, nullptr);
742}
743
744static void panel_draw(const bContext * /*C*/, Panel *panel)
745{
746 uiLayout *layout = panel->layout;
747
748 PointerRNA ob_ptr;
750
751 layout->use_property_split_set(true);
752
753 layout->prop(ptr, "factor", UI_ITEM_NONE, IFACE_("Factor"), ICON_NONE);
754 layout->prop(ptr, "iterations", UI_ITEM_NONE, std::nullopt, ICON_NONE);
755 layout->prop(ptr, "scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
756 layout->prop(ptr, "smooth_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
757
758 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
759
760 layout->prop(ptr, "use_only_smooth", UI_ITEM_NONE, std::nullopt, ICON_NONE);
761 layout->prop(ptr, "use_pin_boundary", UI_ITEM_NONE, std::nullopt, ICON_NONE);
762
763 layout->prop(ptr, "rest_source", UI_ITEM_NONE, std::nullopt, ICON_NONE);
765 layout->op("OBJECT_OT_correctivesmooth_bind",
766 (RNA_boolean_get(ptr, "is_bind") ? IFACE_("Unbind") : IFACE_("Bind")),
767 ICON_NONE);
768 }
769
771}
772
777
778static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
779{
781 const bool is_undo = BLO_write_is_undo(writer);
782
783 if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
784 BLI_assert(!ID_IS_LINKED(id_owner));
785 const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
786 if (!is_local) {
787 /* Modifier coming from linked data cannot be bound from an override, so we can remove all
788 * binding data, can save a significant amount of memory. */
789 csmd.bind_coords_num = 0;
790 csmd.bind_coords = nullptr;
791 csmd.bind_coords_sharing_info = nullptr;
792 }
793 }
794
795 if (csmd.bind_coords != nullptr) {
796 BLO_write_shared(writer,
797 csmd.bind_coords,
798 sizeof(float[3]) * csmd.bind_coords_num,
800 [&]() {
801 BLO_write_float3_array(
802 writer, csmd.bind_coords_num, (const float *)csmd.bind_coords);
803 });
804 }
805
807}
808
809static void blend_read(BlendDataReader *reader, ModifierData *md)
810{
812
813 if (csmd->bind_coords) {
814 csmd->bind_coords_sharing_info = BLO_read_shared(reader, &csmd->bind_coords, [&]() {
815 BLO_read_float3_array(reader, int(csmd->bind_coords_num), (float **)&csmd->bind_coords);
816 return blender::implicit_sharing::info_for_mem_free(csmd->bind_coords);
817 });
818 }
819
820 /* runtime only */
821 csmd->delta_cache.deltas = nullptr;
822 csmd->delta_cache.deltas_num = 0;
823}
824
826 /*idname*/ "CorrectiveSmooth",
827 /*name*/ N_("CorrectiveSmooth"),
828 /*struct_name*/ "CorrectiveSmoothModifierData",
829 /*struct_size*/ sizeof(CorrectiveSmoothModifierData),
830 /*srna*/ &RNA_CorrectiveSmoothModifier,
833 /*icon*/ ICON_MOD_SMOOTH,
834
835 /*copy_data*/ copy_data,
836
837 /*deform_verts*/ deform_verts,
838 /*deform_matrices*/ nullptr,
839 /*deform_verts_EM*/ nullptr,
840 /*deform_matrices_EM*/ nullptr,
841 /*modify_mesh*/ nullptr,
842 /*modify_geometry_set*/ nullptr,
843
844 /*init_data*/ init_data,
845 /*required_data_mask*/ required_data_mask,
846 /*free_data*/ free_data,
847 /*is_disabled*/ nullptr,
848 /*update_depsgraph*/ nullptr,
849 /*depends_on_time*/ nullptr,
850 /*depends_on_normals*/ nullptr,
851 /*foreach_ID_link*/ nullptr,
852 /*foreach_tex_link*/ nullptr,
853 /*free_runtime_data*/ nullptr,
854 /*panel_register*/ panel_register,
855 /*blend_write*/ blend_write,
856 /*blend_read*/ blend_read,
857 /*foreach_cache*/ nullptr,
858 /*foreach_working_space_color*/ nullptr,
859};
support for deformation groups and hooks.
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
blender::Array< blender::float3 > BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em)
Definition editmesh.cc:215
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
ModifierData * BKE_modifier_get_original(const Object *object, ModifierData *md)
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:46
void unit_m3(float m[3][3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void transpose_m3_m3(float R[3][3], const float M[3][3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void copy_vn_fl(float *array_tar, int size, float val)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Platform independent time functions.
Utility defines for timing/benchmarks.
#define TIMEIT_START(var)
#define TIMEIT_END(var)
#define UNLIKELY(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
bool BLO_write_is_undo(BlendWriter *writer)
void BLO_write_shared(BlendWriter *writer, const void *data, size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef< void()> write_fn)
const blender::ImplicitSharingInfo * BLO_read_shared(BlendDataReader *reader, T **data_ptr, blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
#define BLO_write_struct_at_address(writer, struct_name, address, data_ptr)
#define IFACE_(msgid)
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:323
@ ID_RECALC_ALL
Definition DNA_ID.h:1188
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
@ eModifierFlag_OverrideLibrary_Local
@ MOD_CORRECTIVESMOOTH_ONLY_SMOOTH
@ MOD_CORRECTIVESMOOTH_PIN_BOUNDARY
@ MOD_CORRECTIVESMOOTH_INVERT_VGROUP
@ eModifierType_CorrectiveSmooth
@ MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT
@ MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO
@ MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND
Object is a sort of wrapper for general info.
@ OB_MESH
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void init_data(ModifierData *md)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void panel_register(ARegionType *region_type)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void blend_read(BlendDataReader *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void free_data(ModifierData *md)
Definition MOD_bevel.cc:272
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
Definition MOD_bevel.cc:433
static void init_data(ModifierData *md)
static void freeBind(CorrectiveSmoothModifierData *csmd)
static void deform_verts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, blender::MutableSpan< blender::float3 > positions)
static void store_cache_settings(CorrectiveSmoothModifierData *csmd)
static void panel_register(ARegionType *region_type)
static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd, Mesh *mesh, blender::MutableSpan< blender::float3 > vertexCos, const float *smooth_weights, uint iterations)
ModifierTypeInfo modifierType_CorrectiveSmooth
static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd, Mesh *mesh, blender::MutableSpan< blender::float3 > vertexCos, const float *smooth_weights, uint iterations)
static void calc_deltas(CorrectiveSmoothModifierData *csmd, Mesh *mesh, const MDeformVert *dvert, const int defgrp_index, const blender::Span< blender::float3 > rest_coords)
static void free_data(ModifierData *md)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static void calc_tangent_spaces(const Mesh *mesh, blender::Span< blender::float3 > vertexCos, float(*r_tangent_spaces)[3][3], float *r_tangent_weights, float *r_tangent_weights_per_vertex)
static void correctivesmooth_modifier_do(ModifierData *md, Depsgraph *depsgraph, Object *ob, Mesh *mesh, blender::MutableSpan< blender::float3 > vertexCos, BMEditMesh *em)
static void panel_draw(const bContext *, Panel *panel)
static bool calc_tangent_loop(const float v_dir_prev[3], const float v_dir_next[3], float r_tspace[3][3])
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void blend_write(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
static void smooth_verts(CorrectiveSmoothModifierData *csmd, Mesh *mesh, const MDeformVert *dvert, const int defgrp_index, blender::MutableSpan< blender::float3 > vertexCos)
static void mesh_get_weights(const MDeformVert *dvert, const int defgrp_index, const uint verts_num, const bool use_invert_vgroup, float *smooth_weights)
static void smooth_iter(CorrectiveSmoothModifierData *csmd, Mesh *mesh, blender::MutableSpan< blender::float3 > vertexCos, const float *smooth_weights, uint iterations)
static bool cache_settings_equal(CorrectiveSmoothModifierData *csmd)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const StringRefNull vgroup_prop, const std::optional< StringRefNull > invert_vgroup_prop, const std::optional< StringRefNull > text)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:156
#define UI_ITEM_NONE
BPy_StructRNA * depsgraph
long long int int64_t
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr T * data() const
Definition BLI_span.hh:539
constexpr int64_t size_in_bytes() const
Definition BLI_span.hh:501
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
nullptr float
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
static void error(const char *str)
void copy_shared_pointer(T *src_ptr, const ImplicitSharingInfo *src_sharing_info, T **r_dst_ptr, const ImplicitSharingInfo **r_dst_sharing_info)
const ImplicitSharingInfo * info_for_mem_free(void *data)
void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
float safe_acos_approx(float x)
VecBase< float, 3 > float3
const btScalar eps
Definition poly34.cpp:11
#define fabsf
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
int totvert
CorrectiveSmoothDeltaCache delta_cache
const ImplicitSharingInfoHandle * bind_coords_sharing_info
Definition DNA_ID.h:414
int edges_num
int verts_num
struct uiLayout * layout
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145