Blender  V3.3
MOD_correctivesmooth.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2005 Blender Foundation. All rights reserved. */
3 
10 #include "BLI_utildefines.h"
11 
12 #include "BLI_math.h"
13 
14 #include "BLT_translation.h"
15 
16 #include "DNA_defaults.h"
17 #include "DNA_mesh_types.h"
18 #include "DNA_meshdata_types.h"
19 #include "DNA_object_types.h"
20 #include "DNA_scene_types.h"
21 #include "DNA_screen_types.h"
22 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BKE_context.h"
26 #include "BKE_deform.h"
27 #include "BKE_editmesh.h"
28 #include "BKE_lib_id.h"
29 #include "BKE_mesh.h"
30 #include "BKE_mesh_wrapper.h"
31 #include "BKE_screen.h"
32 
33 #include "UI_interface.h"
34 #include "UI_resources.h"
35 
36 #include "RNA_access.h"
37 #include "RNA_prototypes.h"
38 
39 #include "MOD_modifiertypes.h"
40 #include "MOD_ui_common.h"
41 #include "MOD_util.h"
42 
43 #include "BLO_read_write.h"
44 
45 #include "DEG_depsgraph_query.h"
46 
47 // #define DEBUG_TIME
48 
49 #include "PIL_time.h"
50 #ifdef DEBUG_TIME
51 # include "PIL_time_utildefines.h"
52 #endif
53 
54 /* minor optimization, calculate this inline */
55 #define USE_TANGENT_CALC_INLINE
56 
57 static void initData(ModifierData *md)
58 {
60 
61  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(csmd, modifier));
62 
64 
65  csmd->delta_cache.deltas = NULL;
66 }
67 
68 #include "BLI_strict_flags.h"
69 
70 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
71 {
74 
75  BKE_modifier_copydata_generic(md, target, flag);
76 
77  if (csmd->bind_coords) {
78  tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
79  }
80 
81  tcsmd->delta_cache.deltas = NULL;
82  tcsmd->delta_cache.totverts = 0;
83 }
84 
86 {
89 
90  csmd->bind_coords_num = 0;
91 }
92 
93 static void freeData(ModifierData *md)
94 {
96  freeBind(csmd);
97 }
98 
99 static void requiredDataMask(Object *UNUSED(ob),
100  ModifierData *md,
101  CustomData_MeshMasks *r_cddata_masks)
102 {
104 
105  /* ask for vertex groups if we need them */
106  if (csmd->defgrp_name[0] != '\0') {
107  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
108  }
109 }
110 
111 /* check individual weights for changes and cache values */
112 static void mesh_get_weights(MDeformVert *dvert,
113  const int defgrp_index,
114  const uint verts_num,
115  const bool use_invert_vgroup,
116  float *smooth_weights)
117 {
118  uint i;
119 
120  for (i = 0; i < verts_num; i++, dvert++) {
121  const float w = BKE_defvert_find_weight(dvert, defgrp_index);
122 
123  if (use_invert_vgroup == false) {
124  smooth_weights[i] = w;
125  }
126  else {
127  smooth_weights[i] = 1.0f - w;
128  }
129  }
130 }
131 
132 static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
133 {
134  const MPoly *mpoly = mesh->mpoly;
135  const MLoop *mloop = mesh->mloop;
136  const MEdge *medge = mesh->medge;
137  uint mpoly_num, medge_num, i;
138  ushort *boundaries;
139 
140  mpoly_num = (uint)mesh->totpoly;
141  medge_num = (uint)mesh->totedge;
142 
143  boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);
144 
145  /* count the number of adjacent faces */
146  for (i = 0; i < mpoly_num; i++) {
147  const MPoly *p = &mpoly[i];
148  const int totloop = p->totloop;
149  int j;
150  for (j = 0; j < totloop; j++) {
151  boundaries[mloop[p->loopstart + j].e]++;
152  }
153  }
154 
155  for (i = 0; i < medge_num; i++) {
156  if (boundaries[i] == 1) {
157  smooth_weights[medge[i].v1] = 0.0f;
158  smooth_weights[medge[i].v2] = 0.0f;
159  }
160  }
161 
162  MEM_freeN(boundaries);
163 }
164 
165 /* -------------------------------------------------------------------- */
166 /* Simple Weighted Smoothing
167  *
168  * (average of surrounding verts)
169  */
171  Mesh *mesh,
172  float (*vertexCos)[3],
173  uint verts_num,
174  const float *smooth_weights,
175  uint iterations)
176 {
177  const float lambda = csmd->lambda;
178  uint i;
179 
180  const uint edges_num = (uint)mesh->totedge;
181  const MEdge *edges = mesh->medge;
182  float *vertex_edge_count_div;
183 
184  struct SmoothingData_Simple {
185  float delta[3];
186  } *smooth_data = MEM_calloc_arrayN(verts_num, sizeof(*smooth_data), __func__);
187 
188  vertex_edge_count_div = MEM_calloc_arrayN(verts_num, sizeof(float), __func__);
189 
190  /* calculate as floats to avoid int->float conversion in #smooth_iter */
191  for (i = 0; i < edges_num; i++) {
192  vertex_edge_count_div[edges[i].v1] += 1.0f;
193  vertex_edge_count_div[edges[i].v2] += 1.0f;
194  }
195 
196  /* a little confusing, but we can include 'lambda' and smoothing weight
197  * here to avoid multiplying for every iteration */
198  if (smooth_weights == NULL) {
199  for (i = 0; i < verts_num; i++) {
200  vertex_edge_count_div[i] = lambda * (vertex_edge_count_div[i] ?
201  (1.0f / vertex_edge_count_div[i]) :
202  1.0f);
203  }
204  }
205  else {
206  for (i = 0; i < verts_num; i++) {
207  vertex_edge_count_div[i] = smooth_weights[i] * lambda *
208  (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) :
209  1.0f);
210  }
211  }
212 
213  /* -------------------------------------------------------------------- */
214  /* Main Smoothing Loop */
215 
216  while (iterations--) {
217  for (i = 0; i < edges_num; i++) {
218  struct SmoothingData_Simple *sd_v1;
219  struct SmoothingData_Simple *sd_v2;
220  float edge_dir[3];
221 
222  sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
223 
224  sd_v1 = &smooth_data[edges[i].v1];
225  sd_v2 = &smooth_data[edges[i].v2];
226 
227  add_v3_v3(sd_v1->delta, edge_dir);
228  sub_v3_v3(sd_v2->delta, edge_dir);
229  }
230 
231  for (i = 0; i < verts_num; i++) {
232  struct SmoothingData_Simple *sd = &smooth_data[i];
233  madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]);
234  /* zero for the next iteration (saves memset on entire array) */
235  memset(sd, 0, sizeof(*sd));
236  }
237  }
238 
239  MEM_freeN(vertex_edge_count_div);
240  MEM_freeN(smooth_data);
241 }
242 
243 /* -------------------------------------------------------------------- */
244 /* Edge-Length Weighted Smoothing
245  */
247  Mesh *mesh,
248  float (*vertexCos)[3],
249  uint verts_num,
250  const float *smooth_weights,
251  uint iterations)
252 {
253  const float eps = FLT_EPSILON * 10.0f;
254  const uint edges_num = (uint)mesh->totedge;
255  /* NOTE: the way this smoothing method works, its approx half as strong as the simple-smooth,
256  * and 2.0 rarely spikes, double the value for consistent behavior. */
257  const float lambda = csmd->lambda * 2.0f;
258  const MEdge *edges = mesh->medge;
259  float *vertex_edge_count;
260  uint i;
261 
262  struct SmoothingData_Weighted {
263  float delta[3];
264  float edge_length_sum;
265  } *smooth_data = MEM_calloc_arrayN(verts_num, sizeof(*smooth_data), __func__);
266 
267  /* calculate as floats to avoid int->float conversion in #smooth_iter */
268  vertex_edge_count = MEM_calloc_arrayN(verts_num, sizeof(float), __func__);
269  for (i = 0; i < edges_num; i++) {
270  vertex_edge_count[edges[i].v1] += 1.0f;
271  vertex_edge_count[edges[i].v2] += 1.0f;
272  }
273 
274  /* -------------------------------------------------------------------- */
275  /* Main Smoothing Loop */
276 
277  while (iterations--) {
278  for (i = 0; i < edges_num; i++) {
279  struct SmoothingData_Weighted *sd_v1;
280  struct SmoothingData_Weighted *sd_v2;
281  float edge_dir[3];
282  float edge_dist;
283 
284  sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
285  edge_dist = len_v3(edge_dir);
286 
287  /* weight by distance */
288  mul_v3_fl(edge_dir, edge_dist);
289 
290  sd_v1 = &smooth_data[edges[i].v1];
291  sd_v2 = &smooth_data[edges[i].v2];
292 
293  add_v3_v3(sd_v1->delta, edge_dir);
294  sub_v3_v3(sd_v2->delta, edge_dir);
295 
296  sd_v1->edge_length_sum += edge_dist;
297  sd_v2->edge_length_sum += edge_dist;
298  }
299 
300  if (smooth_weights == NULL) {
301  /* fast-path */
302  for (i = 0; i < verts_num; i++) {
303  struct SmoothingData_Weighted *sd = &smooth_data[i];
304  /* Divide by sum of all neighbor distances (weighted) and amount of neighbors,
305  * (mean average). */
306  const float div = sd->edge_length_sum * vertex_edge_count[i];
307  if (div > eps) {
308 #if 0
309  /* first calculate the new location */
310  mul_v3_fl(sd->delta, 1.0f / div);
311  /* then interpolate */
312  madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
313 #else
314  /* do this in one step */
315  madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
316 #endif
317  }
318  /* zero for the next iteration (saves memset on entire array) */
319  memset(sd, 0, sizeof(*sd));
320  }
321  }
322  else {
323  for (i = 0; i < verts_num; i++) {
324  struct SmoothingData_Weighted *sd = &smooth_data[i];
325  const float div = sd->edge_length_sum * vertex_edge_count[i];
326  if (div > eps) {
327  const float lambda_w = lambda * smooth_weights[i];
328  madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
329  }
330 
331  memset(sd, 0, sizeof(*sd));
332  }
333  }
334  }
335 
336  MEM_freeN(vertex_edge_count);
337  MEM_freeN(smooth_data);
338 }
339 
341  Mesh *mesh,
342  float (*vertexCos)[3],
343  uint verts_num,
344  const float *smooth_weights,
345  uint iterations)
346 {
347  switch (csmd->smooth_type) {
349  smooth_iter__length_weight(csmd, mesh, vertexCos, verts_num, smooth_weights, iterations);
350  break;
351 
352  /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
353  default:
354  smooth_iter__simple(csmd, mesh, vertexCos, verts_num, smooth_weights, iterations);
355  break;
356  }
357 }
358 
360  Mesh *mesh,
361  MDeformVert *dvert,
362  const int defgrp_index,
363  float (*vertexCos)[3],
364  uint verts_num)
365 {
366  float *smooth_weights = NULL;
367 
368  if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
369 
370  smooth_weights = MEM_malloc_arrayN(verts_num, sizeof(float), __func__);
371 
372  if (dvert) {
373  mesh_get_weights(dvert,
374  defgrp_index,
375  verts_num,
377  smooth_weights);
378  }
379  else {
380  copy_vn_fl(smooth_weights, (int)verts_num, 1.0f);
381  }
382 
384  mesh_get_boundaries(mesh, smooth_weights);
385  }
386  }
387 
388  smooth_iter(csmd, mesh, vertexCos, verts_num, smooth_weights, (uint)csmd->repeat);
389 
390  if (smooth_weights) {
391  MEM_freeN(smooth_weights);
392  }
393 }
394 
398 static void calc_tangent_ortho(float ts[3][3])
399 {
400  float v_tan_a[3], v_tan_b[3];
401  float t_vec_a[3], t_vec_b[3];
402 
403  normalize_v3(ts[2]);
404 
405  copy_v3_v3(v_tan_a, ts[0]);
406  copy_v3_v3(v_tan_b, ts[1]);
407 
408  cross_v3_v3v3(ts[1], ts[2], v_tan_a);
409  mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f);
410 
411  /* Orthogonalize tangent. */
412  mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a));
413  sub_v3_v3v3(ts[0], v_tan_a, t_vec_a);
414 
415  /* Orthogonalize bi-tangent. */
416  mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1]));
417  mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a));
418  sub_v3_v3(ts[1], t_vec_a);
419  sub_v3_v3(ts[1], t_vec_b);
420 
421  normalize_v3(ts[0]);
422  normalize_v3(ts[1]);
423 }
424 
428 static void calc_tangent_loop_accum(const float v_dir_prev[3],
429  const float v_dir_next[3],
430  float r_tspace[3][3])
431 {
432  add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next);
433 
434  if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) {
435  const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev)));
436  float nor[3];
437 
438  cross_v3_v3v3(nor, v_dir_prev, v_dir_next);
439  normalize_v3(nor);
440 
441  cross_v3_v3v3(r_tspace[0], r_tspace[1], nor);
442 
443  mul_v3_fl(nor, weight);
444  /* accumulate weighted normals */
445  add_v3_v3(r_tspace[2], nor);
446  }
447 }
448 
449 static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3])
450 {
451  const uint mpoly_num = (uint)mesh->totpoly;
453  const uint mvert_num = (uint)dm->getNumVerts(dm);
454 #endif
455  const MPoly *mpoly = mesh->mpoly;
456  const MLoop *mloop = mesh->mloop;
457  uint i;
458 
459  for (i = 0; i < mpoly_num; i++) {
460  const MPoly *mp = &mpoly[i];
461  const MLoop *l_next = &mloop[mp->loopstart];
462  const MLoop *l_term = l_next + mp->totloop;
463  const MLoop *l_prev = l_term - 2;
464  const MLoop *l_curr = l_term - 1;
465 
466  /* loop directions */
467  float v_dir_prev[3], v_dir_next[3];
468 
469  /* needed entering the loop */
470  sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
471  normalize_v3(v_dir_prev);
472 
473  for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) {
474  float(*ts)[3] = r_tangent_spaces[l_curr->v];
475 
476  /* re-use the previous value */
477 #if 0
478  sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
479  normalize_v3(v_dir_prev);
480 #endif
481  sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]);
482  normalize_v3(v_dir_next);
483 
484  calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts);
485 
486  copy_v3_v3(v_dir_prev, v_dir_next);
487  }
488  }
489 
490  /* do inline */
491 #ifndef USE_TANGENT_CALC_INLINE
492  for (i = 0; i < mvert_num; i++) {
493  float(*ts)[3] = r_tangent_spaces[i];
494  calc_tangent_ortho(ts);
495  }
496 #endif
497 }
498 
500 {
501  csmd->delta_cache.lambda = csmd->lambda;
502  csmd->delta_cache.repeat = csmd->repeat;
503  csmd->delta_cache.flag = csmd->flag;
504  csmd->delta_cache.smooth_type = csmd->smooth_type;
505  csmd->delta_cache.rest_source = csmd->rest_source;
506 }
507 
509 {
510  return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat &&
511  csmd->delta_cache.flag == csmd->flag &&
512  csmd->delta_cache.smooth_type == csmd->smooth_type &&
513  csmd->delta_cache.rest_source == csmd->rest_source);
514 }
515 
521  Mesh *mesh,
522  MDeformVert *dvert,
523  const int defgrp_index,
524  const float (*rest_coords)[3],
525  uint verts_num)
526 {
527  float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
528  float(*tangent_spaces)[3][3];
529  uint i;
530 
531  tangent_spaces = MEM_calloc_arrayN(verts_num, sizeof(float[3][3]), __func__);
532 
533  if (csmd->delta_cache.totverts != verts_num) {
535  }
536 
537  /* allocate deltas if they have not yet been allocated, otherwise we will just write over them */
538  if (!csmd->delta_cache.deltas) {
539  csmd->delta_cache.totverts = verts_num;
540  csmd->delta_cache.deltas = MEM_malloc_arrayN(verts_num, sizeof(float[3]), __func__);
541  }
542 
543  smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, verts_num);
544 
545  calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces);
546 
547  for (i = 0; i < verts_num; i++) {
548  float imat[3][3], delta[3];
549 
550 #ifdef USE_TANGENT_CALC_INLINE
551  calc_tangent_ortho(tangent_spaces[i]);
552 #endif
553 
554  sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
555  if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
556  transpose_m3_m3(imat, tangent_spaces[i]);
557  }
558  mul_v3_m3v3(csmd->delta_cache.deltas[i], imat, delta);
559  }
560 
561  MEM_freeN(tangent_spaces);
562  MEM_freeN(smooth_vertex_coords);
563 }
564 
567  Object *ob,
568  Mesh *mesh,
569  float (*vertexCos)[3],
570  uint verts_num,
571  struct BMEditMesh *em)
572 {
574 
575  const bool force_delta_cache_update =
576  /* XXX, take care! if mesh data itself changes we need to forcefully recalculate deltas */
577  !cache_settings_equal(csmd) ||
579  (((ID *)ob->data)->recalc & ID_RECALC_ALL));
580 
581  bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
582  MDeformVert *dvert = NULL;
583  int defgrp_index;
584 
585  MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index);
586 
587  /* if rest bind_coords not are defined, set them (only run during bind) */
589  /* signal to recalculate, whoever sets MUST also free bind coords */
590  (csmd->bind_coords_num == (uint)-1)) {
591  if (DEG_is_active(depsgraph)) {
592  BLI_assert(csmd->bind_coords == NULL);
593  csmd->bind_coords = MEM_dupallocN(vertexCos);
594  csmd->bind_coords_num = verts_num;
595  BLI_assert(csmd->bind_coords != NULL);
596  /* Copy bound data to the original modifier. */
599  csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords);
600  csmd_orig->bind_coords_num = csmd->bind_coords_num;
601  }
602  else {
603  BKE_modifier_set_error(ob, md, "Attempt to bind from inactive dependency graph");
604  }
605  }
606 
607  if (UNLIKELY(use_only_smooth)) {
608  smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, verts_num);
609  return;
610  }
611 
612  if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
613  BKE_modifier_set_error(ob, md, "Bind data required");
614  goto error;
615  }
616 
617  /* If the number of verts has changed, the bind is invalid, so we do nothing */
619  if (csmd->bind_coords_num != verts_num) {
621  ob, md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, verts_num);
622  goto error;
623  }
624  }
625  else {
626  /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
627  if (ob->type != OB_MESH) {
628  BKE_modifier_set_error(ob, md, "Object is not a mesh");
629  goto error;
630  }
631  else {
632  uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
633 
634  if (me_numVerts != verts_num) {
636  ob, md, "Original vertex count mismatch: %u to %u", me_numVerts, verts_num);
637  goto error;
638  }
639  }
640  }
641 
642  /* check to see if our deltas are still valid */
643  if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != verts_num) ||
644  force_delta_cache_update) {
645  const float(*rest_coords)[3];
646  bool is_rest_coords_alloc = false;
647 
648  store_cache_settings(csmd);
649 
651  /* caller needs to do sanity check here */
652  csmd->bind_coords_num = verts_num;
653  rest_coords = csmd->bind_coords;
654  }
655  else {
656  int me_numVerts;
657  rest_coords = em ? BKE_editmesh_vert_coords_alloc_orco(em, &me_numVerts) :
658  BKE_mesh_vert_coords_alloc(ob->data, &me_numVerts);
659 
660  BLI_assert((uint)me_numVerts == verts_num);
661  is_rest_coords_alloc = true;
662  }
663 
664 #ifdef DEBUG_TIME
665  TIMEIT_START(corrective_smooth_deltas);
666 #endif
667 
668  calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords, verts_num);
669 
670 #ifdef DEBUG_TIME
671  TIMEIT_END(corrective_smooth_deltas);
672 #endif
673  if (is_rest_coords_alloc) {
674  MEM_freeN((void *)rest_coords);
675  }
676  }
677 
679  /* this could be a check, but at this point it _must_ be valid */
680  BLI_assert(csmd->bind_coords_num == verts_num && csmd->delta_cache.deltas);
681  }
682 
683 #ifdef DEBUG_TIME
684  TIMEIT_START(corrective_smooth);
685 #endif
686 
687  /* do the actual delta mush */
688  smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, verts_num);
689 
690  {
691  uint i;
692 
693  float(*tangent_spaces)[3][3];
694  const float scale = csmd->scale;
695  /* calloc, since values are accumulated */
696  tangent_spaces = MEM_calloc_arrayN(verts_num, sizeof(float[3][3]), __func__);
697 
698  calc_tangent_spaces(mesh, vertexCos, tangent_spaces);
699 
700  for (i = 0; i < verts_num; i++) {
701  float delta[3];
702 
703 #ifdef USE_TANGENT_CALC_INLINE
704  calc_tangent_ortho(tangent_spaces[i]);
705 #endif
706 
707  mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache.deltas[i]);
708  madd_v3_v3fl(vertexCos[i], delta, scale);
709  }
710 
711  MEM_freeN(tangent_spaces);
712  }
713 
714 #ifdef DEBUG_TIME
715  TIMEIT_END(corrective_smooth);
716 #endif
717 
718  return;
719 
720  /* when the modifier fails to execute */
721 error:
723  csmd->delta_cache.totverts = 0;
724 }
725 
726 static void deformVerts(ModifierData *md,
727  const ModifierEvalContext *ctx,
728  Mesh *mesh,
729  float (*vertexCos)[3],
730  int verts_num)
731 {
732  Mesh *mesh_src = MOD_deform_mesh_eval_get(
733  ctx->object, NULL, mesh, NULL, verts_num, false, false);
734 
736  md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)verts_num, NULL);
737 
738  if (!ELEM(mesh_src, NULL, mesh)) {
739  BKE_id_free(NULL, mesh_src);
740  }
741 }
742 
743 static void deformVertsEM(ModifierData *md,
744  const ModifierEvalContext *ctx,
745  struct BMEditMesh *editData,
746  Mesh *mesh,
747  float (*vertexCos)[3],
748  int verts_num)
749 {
750  Mesh *mesh_src = MOD_deform_mesh_eval_get(
751  ctx->object, editData, mesh, NULL, verts_num, false, false);
752 
753  /* TODO(Campbell): use edit-mode data only (remove this line). */
754  if (mesh_src != NULL) {
756  }
757 
759  md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)verts_num, editData);
760 
761  if (!ELEM(mesh_src, NULL, mesh)) {
762  BKE_id_free(NULL, mesh_src);
763  }
764 }
765 
766 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
767 {
768  uiLayout *layout = panel->layout;
769 
770  PointerRNA ob_ptr;
772 
773  uiLayoutSetPropSep(layout, true);
774 
775  uiItemR(layout, ptr, "factor", 0, IFACE_("Factor"), ICON_NONE);
776  uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
777  uiItemR(layout, ptr, "scale", 0, NULL, ICON_NONE);
778  uiItemR(layout, ptr, "smooth_type", 0, NULL, ICON_NONE);
779 
780  modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
781 
782  uiItemR(layout, ptr, "use_only_smooth", 0, NULL, ICON_NONE);
783  uiItemR(layout, ptr, "use_pin_boundary", 0, NULL, ICON_NONE);
784 
785  uiItemR(layout, ptr, "rest_source", 0, NULL, ICON_NONE);
786  if (RNA_enum_get(ptr, "rest_source") == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
787  uiItemO(layout,
788  (RNA_boolean_get(ptr, "is_bind") ? IFACE_("Unbind") : IFACE_("Bind")),
789  ICON_NONE,
790  "OBJECT_OT_correctivesmooth_bind");
791  }
792 
793  modifier_panel_end(layout, ptr);
794 }
795 
796 static void panelRegister(ARegionType *region_type)
797 {
799 }
800 
801 static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
802 {
804  const bool is_undo = BLO_write_is_undo(writer);
805 
806  if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
807  BLI_assert(!ID_IS_LINKED(id_owner));
808  const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
809  if (!is_local) {
810  /* Modifier coming from linked data cannot be bound from an override, so we can remove all
811  * binding data, can save a significant amount of memory. */
812  csmd.bind_coords_num = 0;
813  csmd.bind_coords = NULL;
814  }
815  }
816 
818 
819  if (csmd.bind_coords != NULL) {
820  BLO_write_float3_array(writer, csmd.bind_coords_num, (float *)csmd.bind_coords);
821  }
822 }
823 
824 static void blendRead(BlendDataReader *reader, ModifierData *md)
825 {
827 
828  if (csmd->bind_coords) {
829  BLO_read_float3_array(reader, (int)csmd->bind_coords_num, (float **)&csmd->bind_coords);
830  }
831 
832  /* runtime only */
833  csmd->delta_cache.deltas = NULL;
834  csmd->delta_cache.totverts = 0;
835 }
836 
838  /* name */ N_("CorrectiveSmooth"),
839  /* structName */ "CorrectiveSmoothModifierData",
840  /* structSize */ sizeof(CorrectiveSmoothModifierData),
841  /* srna */ &RNA_CorrectiveSmoothModifier,
842  /* type */ eModifierTypeType_OnlyDeform,
844  /* icon */ ICON_MOD_SMOOTH,
845 
846  /* copyData */ copyData,
847 
848  /* deformVerts */ deformVerts,
849  /* deformMatrices */ NULL,
850  /* deformVertsEM */ deformVertsEM,
851  /* deformMatricesEM */ NULL,
852  /* modifyMesh */ NULL,
853  /* modifyGeometrySet */ NULL,
854 
855  /* initData */ initData,
856  /* requiredDataMask */ requiredDataMask,
857  /* freeData */ freeData,
858  /* isDisabled */ NULL,
859  /* updateDepsgraph */ NULL,
860  /* dependsOnTime */ NULL,
861  /* dependsOnNormals */ NULL,
862  /* foreachIDLink */ NULL,
863  /* foreachTexLink */ NULL,
864  /* freeRuntimeData */ NULL,
865  /* panelRegister */ panelRegister,
866  /* blendWrite */ blendWrite,
867  /* blendRead */ blendRead,
868 };
typedef float(TangentPoint)[2]
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup)
Definition: deform.c:704
float(* BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
Definition: editmesh.c:271
void BKE_id_free(struct Main *bmain, void *idv)
float(* BKE_mesh_vert_coords_alloc(const struct Mesh *mesh, int *r_vert_len))[3]
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.cc:94
struct ModifierData * BKE_modifier_get_original(const struct Object *object, struct ModifierData *md)
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:69
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:66
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, int flag)
@ eModifierTypeType_OnlyDeform
Definition: BKE_modifier.h:44
void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition: BLI_assert.h:46
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:897
void transpose_m3_m3(float R[3][3], const float M[3][3])
Definition: math_matrix.c:1347
MINLINE bool compare_v3v3(const float a[3], const float b[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
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)
Definition: math_vector.c:1259
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:67
unsigned short ushort
Definition: BLI_sys_types.h:68
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
Definition: readfile.c:5201
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr)
Definition: writefile.c:1596
bool BLO_write_is_undo(BlendWriter *writer)
Definition: writefile.c:1608
#define BLO_write_struct_at_address(writer, struct_name, address, data_ptr)
#define IFACE_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
bool DEG_is_active(const struct Depsgraph *depsgraph)
Definition: depsgraph.cc:312
@ ID_RECALC_ALL
Definition: DNA_ID.h:891
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ eModifierFlag_OverrideLibrary_Local
@ MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO
@ MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND
@ MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT
@ MOD_CORRECTIVESMOOTH_ONLY_SMOOTH
@ MOD_CORRECTIVESMOOTH_PIN_BOUNDARY
@ MOD_CORRECTIVESMOOTH_INVERT_VGROUP
@ eModifierType_CorrectiveSmooth
struct CorrectiveSmoothModifierData CorrectiveSmoothModifierData
Object is a sort of wrapper for general info.
@ OB_MESH
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void freeBind(CorrectiveSmoothModifierData *csmd)
static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float(*vertexCos)[3], uint verts_num, const float *smooth_weights, uint iterations)
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
static void store_cache_settings(CorrectiveSmoothModifierData *csmd)
static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, float(*vertexCos)[3], int verts_num)
static void smooth_iter(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float(*vertexCos)[3], uint verts_num, const float *smooth_weights, uint iterations)
static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, Mesh *mesh, float(*vertexCos)[3], int verts_num)
static void correctivesmooth_modifier_do(ModifierData *md, Depsgraph *depsgraph, Object *ob, Mesh *mesh, float(*vertexCos)[3], uint verts_num, struct BMEditMesh *em)
#define USE_TANGENT_CALC_INLINE
ModifierTypeInfo modifierType_CorrectiveSmooth
static void blendRead(BlendDataReader *reader, ModifierData *md)
static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float(*vertexCos)[3], uint verts_num, const float *smooth_weights, uint iterations)
static void calc_tangent_loop_accum(const float v_dir_prev[3], const float v_dir_next[3], float r_tspace[3][3])
static void mesh_get_weights(MDeformVert *dvert, const int defgrp_index, const uint verts_num, const bool use_invert_vgroup, float *smooth_weights)
static void smooth_verts(CorrectiveSmoothModifierData *csmd, Mesh *mesh, MDeformVert *dvert, const int defgrp_index, float(*vertexCos)[3], uint verts_num)
static void calc_deltas(CorrectiveSmoothModifierData *csmd, Mesh *mesh, MDeformVert *dvert, const int defgrp_index, const float(*rest_coords)[3], uint verts_num)
static void calc_tangent_ortho(float ts[3][3])
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void initData(ModifierData *md)
static void panelRegister(ARegionType *region_type)
static bool cache_settings_equal(CorrectiveSmoothModifierData *csmd)
static void calc_tangent_spaces(Mesh *mesh, float(*vertexCos)[3], float(*r_tangent_spaces)[3][3])
static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
static void freeData(ModifierData *md)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
Definition: MOD_ui_common.c:91
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
Mesh * MOD_deform_mesh_eval_get(Object *ob, struct BMEditMesh *em, Mesh *mesh, const float(*vertexCos)[3], const int verts_num, const bool use_normals, const bool use_orco)
Definition: MOD_util.c:167
void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
Definition: MOD_util.c:235
Platform independent time functions.
Utility defines for timing/benchmarks.
#define TIMEIT_START(var)
#define TIMEIT_END(var)
#define C
Definition: RandGen.cpp:25
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
const Depsgraph * depsgraph
uint nor
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
static void error(const char *str)
Definition: meshlaplacian.c:51
#define acosf(x)
Definition: metal/compat.h:222
#define fabsf(x)
Definition: metal/compat.h:219
const btScalar eps
Definition: poly34.cpp:11
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
struct BMesh * bm
Definition: BKE_editmesh.h:40
int totvert
Definition: bmesh_class.h:297
CorrectiveSmoothDeltaCache delta_cache
Definition: DNA_ID.h:368
unsigned int v1
unsigned int e
unsigned int v
struct MEdge * medge
int totedge
struct MLoop * mloop
int totpoly
struct MPoly * mpoly
struct Depsgraph * depsgraph
Definition: BKE_modifier.h:140
struct Object * object
Definition: BKE_modifier.h:141
void * data
struct uiLayout * layout
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480