Blender  V2.93
MOD_correctivesmooth.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2005 by the Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include "BLI_utildefines.h"
27 
28 #include "BLI_math.h"
29 
30 #include "BLT_translation.h"
31 
32 #include "DNA_defaults.h"
33 #include "DNA_mesh_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_screen_types.h"
38 
39 #include "MEM_guardedalloc.h"
40 
41 #include "BKE_context.h"
42 #include "BKE_deform.h"
43 #include "BKE_editmesh.h"
44 #include "BKE_lib_id.h"
45 #include "BKE_mesh.h"
46 #include "BKE_mesh_wrapper.h"
47 #include "BKE_screen.h"
48 
49 #include "UI_interface.h"
50 #include "UI_resources.h"
51 
52 #include "RNA_access.h"
53 
54 #include "MOD_modifiertypes.h"
55 #include "MOD_ui_common.h"
56 #include "MOD_util.h"
57 
58 #include "BLO_read_write.h"
59 
60 #include "DEG_depsgraph_query.h"
61 
62 // #define DEBUG_TIME
63 
64 #include "PIL_time.h"
65 #ifdef DEBUG_TIME
66 # include "PIL_time_utildefines.h"
67 #endif
68 
69 /* minor optimization, calculate this inline */
70 #define USE_TANGENT_CALC_INLINE
71 
72 static void initData(ModifierData *md)
73 {
75 
76  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(csmd, modifier));
77 
79 
80  csmd->delta_cache.deltas = NULL;
81 }
82 
83 #include "BLI_strict_flags.h"
84 
85 static void copyData(const ModifierData *md, ModifierData *target, const int flag)
86 {
89 
90  BKE_modifier_copydata_generic(md, target, flag);
91 
92  if (csmd->bind_coords) {
93  tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
94  }
95 
96  tcsmd->delta_cache.deltas = NULL;
97  tcsmd->delta_cache.totverts = 0;
98 }
99 
101 {
102  MEM_SAFE_FREE(csmd->bind_coords);
104 
105  csmd->bind_coords_num = 0;
106 }
107 
108 static void freeData(ModifierData *md)
109 {
111  freeBind(csmd);
112 }
113 
114 static void requiredDataMask(Object *UNUSED(ob),
115  ModifierData *md,
116  CustomData_MeshMasks *r_cddata_masks)
117 {
119 
120  /* ask for vertex groups if we need them */
121  if (csmd->defgrp_name[0] != '\0') {
122  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
123  }
124 }
125 
126 /* check individual weights for changes and cache values */
127 static void mesh_get_weights(MDeformVert *dvert,
128  const int defgrp_index,
129  const uint numVerts,
130  const bool use_invert_vgroup,
131  float *smooth_weights)
132 {
133  uint i;
134 
135  for (i = 0; i < numVerts; i++, dvert++) {
136  const float w = BKE_defvert_find_weight(dvert, defgrp_index);
137 
138  if (use_invert_vgroup == false) {
139  smooth_weights[i] = w;
140  }
141  else {
142  smooth_weights[i] = 1.0f - w;
143  }
144  }
145 }
146 
147 static void mesh_get_boundaries(Mesh *mesh, float *smooth_weights)
148 {
149  const MPoly *mpoly = mesh->mpoly;
150  const MLoop *mloop = mesh->mloop;
151  const MEdge *medge = mesh->medge;
152  uint mpoly_num, medge_num, i;
153  ushort *boundaries;
154 
155  mpoly_num = (uint)mesh->totpoly;
156  medge_num = (uint)mesh->totedge;
157 
158  boundaries = MEM_calloc_arrayN(medge_num, sizeof(*boundaries), __func__);
159 
160  /* count the number of adjacent faces */
161  for (i = 0; i < mpoly_num; i++) {
162  const MPoly *p = &mpoly[i];
163  const int totloop = p->totloop;
164  int j;
165  for (j = 0; j < totloop; j++) {
166  boundaries[mloop[p->loopstart + j].e]++;
167  }
168  }
169 
170  for (i = 0; i < medge_num; i++) {
171  if (boundaries[i] == 1) {
172  smooth_weights[medge[i].v1] = 0.0f;
173  smooth_weights[medge[i].v2] = 0.0f;
174  }
175  }
176 
177  MEM_freeN(boundaries);
178 }
179 
180 /* -------------------------------------------------------------------- */
181 /* Simple Weighted Smoothing
182  *
183  * (average of surrounding verts)
184  */
186  Mesh *mesh,
187  float (*vertexCos)[3],
188  uint numVerts,
189  const float *smooth_weights,
190  uint iterations)
191 {
192  const float lambda = csmd->lambda;
193  uint i;
194 
195  const uint numEdges = (uint)mesh->totedge;
196  const MEdge *edges = mesh->medge;
197  float *vertex_edge_count_div;
198 
199  struct SmoothingData_Simple {
200  float delta[3];
201  } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);
202 
203  vertex_edge_count_div = MEM_calloc_arrayN(numVerts, sizeof(float), __func__);
204 
205  /* calculate as floats to avoid int->float conversion in #smooth_iter */
206  for (i = 0; i < numEdges; i++) {
207  vertex_edge_count_div[edges[i].v1] += 1.0f;
208  vertex_edge_count_div[edges[i].v2] += 1.0f;
209  }
210 
211  /* a little confusing, but we can include 'lambda' and smoothing weight
212  * here to avoid multiplying for every iteration */
213  if (smooth_weights == NULL) {
214  for (i = 0; i < numVerts; i++) {
215  vertex_edge_count_div[i] = lambda * (vertex_edge_count_div[i] ?
216  (1.0f / vertex_edge_count_div[i]) :
217  1.0f);
218  }
219  }
220  else {
221  for (i = 0; i < numVerts; i++) {
222  vertex_edge_count_div[i] = smooth_weights[i] * lambda *
223  (vertex_edge_count_div[i] ? (1.0f / vertex_edge_count_div[i]) :
224  1.0f);
225  }
226  }
227 
228  /* -------------------------------------------------------------------- */
229  /* Main Smoothing Loop */
230 
231  while (iterations--) {
232  for (i = 0; i < numEdges; i++) {
233  struct SmoothingData_Simple *sd_v1;
234  struct SmoothingData_Simple *sd_v2;
235  float edge_dir[3];
236 
237  sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
238 
239  sd_v1 = &smooth_data[edges[i].v1];
240  sd_v2 = &smooth_data[edges[i].v2];
241 
242  add_v3_v3(sd_v1->delta, edge_dir);
243  sub_v3_v3(sd_v2->delta, edge_dir);
244  }
245 
246  for (i = 0; i < numVerts; i++) {
247  struct SmoothingData_Simple *sd = &smooth_data[i];
248  madd_v3_v3fl(vertexCos[i], sd->delta, vertex_edge_count_div[i]);
249  /* zero for the next iteration (saves memset on entire array) */
250  memset(sd, 0, sizeof(*sd));
251  }
252  }
253 
254  MEM_freeN(vertex_edge_count_div);
255  MEM_freeN(smooth_data);
256 }
257 
258 /* -------------------------------------------------------------------- */
259 /* Edge-Length Weighted Smoothing
260  */
262  Mesh *mesh,
263  float (*vertexCos)[3],
264  uint numVerts,
265  const float *smooth_weights,
266  uint iterations)
267 {
268  const float eps = FLT_EPSILON * 10.0f;
269  const uint numEdges = (uint)mesh->totedge;
270  /* note: the way this smoothing method works, its approx half as strong as the simple-smooth,
271  * and 2.0 rarely spikes, double the value for consistent behavior. */
272  const float lambda = csmd->lambda * 2.0f;
273  const MEdge *edges = mesh->medge;
274  float *vertex_edge_count;
275  uint i;
276 
277  struct SmoothingData_Weighted {
278  float delta[3];
279  float edge_length_sum;
280  } *smooth_data = MEM_calloc_arrayN(numVerts, sizeof(*smooth_data), __func__);
281 
282  /* calculate as floats to avoid int->float conversion in #smooth_iter */
283  vertex_edge_count = MEM_calloc_arrayN(numVerts, sizeof(float), __func__);
284  for (i = 0; i < numEdges; i++) {
285  vertex_edge_count[edges[i].v1] += 1.0f;
286  vertex_edge_count[edges[i].v2] += 1.0f;
287  }
288 
289  /* -------------------------------------------------------------------- */
290  /* Main Smoothing Loop */
291 
292  while (iterations--) {
293  for (i = 0; i < numEdges; i++) {
294  struct SmoothingData_Weighted *sd_v1;
295  struct SmoothingData_Weighted *sd_v2;
296  float edge_dir[3];
297  float edge_dist;
298 
299  sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]);
300  edge_dist = len_v3(edge_dir);
301 
302  /* weight by distance */
303  mul_v3_fl(edge_dir, edge_dist);
304 
305  sd_v1 = &smooth_data[edges[i].v1];
306  sd_v2 = &smooth_data[edges[i].v2];
307 
308  add_v3_v3(sd_v1->delta, edge_dir);
309  sub_v3_v3(sd_v2->delta, edge_dir);
310 
311  sd_v1->edge_length_sum += edge_dist;
312  sd_v2->edge_length_sum += edge_dist;
313  }
314 
315  if (smooth_weights == NULL) {
316  /* fast-path */
317  for (i = 0; i < numVerts; i++) {
318  struct SmoothingData_Weighted *sd = &smooth_data[i];
319  /* Divide by sum of all neighbor distances (weighted) and amount of neighbors,
320  * (mean average). */
321  const float div = sd->edge_length_sum * vertex_edge_count[i];
322  if (div > eps) {
323 #if 0
324  /* first calculate the new location */
325  mul_v3_fl(sd->delta, 1.0f / div);
326  /* then interpolate */
327  madd_v3_v3fl(vertexCos[i], sd->delta, lambda);
328 #else
329  /* do this in one step */
330  madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div);
331 #endif
332  }
333  /* zero for the next iteration (saves memset on entire array) */
334  memset(sd, 0, sizeof(*sd));
335  }
336  }
337  else {
338  for (i = 0; i < numVerts; i++) {
339  struct SmoothingData_Weighted *sd = &smooth_data[i];
340  const float div = sd->edge_length_sum * vertex_edge_count[i];
341  if (div > eps) {
342  const float lambda_w = lambda * smooth_weights[i];
343  madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div);
344  }
345 
346  memset(sd, 0, sizeof(*sd));
347  }
348  }
349  }
350 
351  MEM_freeN(vertex_edge_count);
352  MEM_freeN(smooth_data);
353 }
354 
356  Mesh *mesh,
357  float (*vertexCos)[3],
358  uint numVerts,
359  const float *smooth_weights,
360  uint iterations)
361 {
362  switch (csmd->smooth_type) {
364  smooth_iter__length_weight(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations);
365  break;
366 
367  /* case MOD_CORRECTIVESMOOTH_SMOOTH_SIMPLE: */
368  default:
369  smooth_iter__simple(csmd, mesh, vertexCos, numVerts, smooth_weights, iterations);
370  break;
371  }
372 }
373 
375  Mesh *mesh,
376  MDeformVert *dvert,
377  const int defgrp_index,
378  float (*vertexCos)[3],
379  uint numVerts)
380 {
381  float *smooth_weights = NULL;
382 
383  if (dvert || (csmd->flag & MOD_CORRECTIVESMOOTH_PIN_BOUNDARY)) {
384 
385  smooth_weights = MEM_malloc_arrayN(numVerts, sizeof(float), __func__);
386 
387  if (dvert) {
388  mesh_get_weights(dvert,
389  defgrp_index,
390  numVerts,
392  smooth_weights);
393  }
394  else {
395  copy_vn_fl(smooth_weights, (int)numVerts, 1.0f);
396  }
397 
399  mesh_get_boundaries(mesh, smooth_weights);
400  }
401  }
402 
403  smooth_iter(csmd, mesh, vertexCos, numVerts, smooth_weights, (uint)csmd->repeat);
404 
405  if (smooth_weights) {
406  MEM_freeN(smooth_weights);
407  }
408 }
409 
413 static void calc_tangent_ortho(float ts[3][3])
414 {
415  float v_tan_a[3], v_tan_b[3];
416  float t_vec_a[3], t_vec_b[3];
417 
418  normalize_v3(ts[2]);
419 
420  copy_v3_v3(v_tan_a, ts[0]);
421  copy_v3_v3(v_tan_b, ts[1]);
422 
423  cross_v3_v3v3(ts[1], ts[2], v_tan_a);
424  mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f);
425 
426  /* Orthogonalize tangent. */
427  mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a));
428  sub_v3_v3v3(ts[0], v_tan_a, t_vec_a);
429 
430  /* Orthogonalize bi-tangent. */
431  mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1]));
432  mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a));
433  sub_v3_v3(ts[1], t_vec_a);
434  sub_v3_v3(ts[1], t_vec_b);
435 
436  normalize_v3(ts[0]);
437  normalize_v3(ts[1]);
438 }
439 
443 static void calc_tangent_loop_accum(const float v_dir_prev[3],
444  const float v_dir_next[3],
445  float r_tspace[3][3])
446 {
447  add_v3_v3v3(r_tspace[1], v_dir_prev, v_dir_next);
448 
449  if (compare_v3v3(v_dir_prev, v_dir_next, FLT_EPSILON * 10.0f) == false) {
450  const float weight = fabsf(acosf(dot_v3v3(v_dir_next, v_dir_prev)));
451  float nor[3];
452 
453  cross_v3_v3v3(nor, v_dir_prev, v_dir_next);
454  normalize_v3(nor);
455 
456  cross_v3_v3v3(r_tspace[0], r_tspace[1], nor);
457 
458  mul_v3_fl(nor, weight);
459  /* accumulate weighted normals */
460  add_v3_v3(r_tspace[2], nor);
461  }
462 }
463 
464 static void calc_tangent_spaces(Mesh *mesh, float (*vertexCos)[3], float (*r_tangent_spaces)[3][3])
465 {
466  const uint mpoly_num = (uint)mesh->totpoly;
468  const uint mvert_num = (uint)dm->getNumVerts(dm);
469 #endif
470  const MPoly *mpoly = mesh->mpoly;
471  const MLoop *mloop = mesh->mloop;
472  uint i;
473 
474  for (i = 0; i < mpoly_num; i++) {
475  const MPoly *mp = &mpoly[i];
476  const MLoop *l_next = &mloop[mp->loopstart];
477  const MLoop *l_term = l_next + mp->totloop;
478  const MLoop *l_prev = l_term - 2;
479  const MLoop *l_curr = l_term - 1;
480 
481  /* loop directions */
482  float v_dir_prev[3], v_dir_next[3];
483 
484  /* needed entering the loop */
485  sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
486  normalize_v3(v_dir_prev);
487 
488  for (; l_next != l_term; l_prev = l_curr, l_curr = l_next, l_next++) {
489  float(*ts)[3] = r_tangent_spaces[l_curr->v];
490 
491  /* re-use the previous value */
492 #if 0
493  sub_v3_v3v3(v_dir_prev, vertexCos[l_prev->v], vertexCos[l_curr->v]);
494  normalize_v3(v_dir_prev);
495 #endif
496  sub_v3_v3v3(v_dir_next, vertexCos[l_curr->v], vertexCos[l_next->v]);
497  normalize_v3(v_dir_next);
498 
499  calc_tangent_loop_accum(v_dir_prev, v_dir_next, ts);
500 
501  copy_v3_v3(v_dir_prev, v_dir_next);
502  }
503  }
504 
505  /* do inline */
506 #ifndef USE_TANGENT_CALC_INLINE
507  for (i = 0; i < mvert_num; i++) {
508  float(*ts)[3] = r_tangent_spaces[i];
509  calc_tangent_ortho(ts);
510  }
511 #endif
512 }
513 
515 {
516  csmd->delta_cache.lambda = csmd->lambda;
517  csmd->delta_cache.repeat = csmd->repeat;
518  csmd->delta_cache.flag = csmd->flag;
519  csmd->delta_cache.smooth_type = csmd->smooth_type;
520  csmd->delta_cache.rest_source = csmd->rest_source;
521 }
522 
524 {
525  return (csmd->delta_cache.lambda == csmd->lambda && csmd->delta_cache.repeat == csmd->repeat &&
526  csmd->delta_cache.flag == csmd->flag &&
527  csmd->delta_cache.smooth_type == csmd->smooth_type &&
528  csmd->delta_cache.rest_source == csmd->rest_source);
529 }
530 
536  Mesh *mesh,
537  MDeformVert *dvert,
538  const int defgrp_index,
539  const float (*rest_coords)[3],
540  uint numVerts)
541 {
542  float(*smooth_vertex_coords)[3] = MEM_dupallocN(rest_coords);
543  float(*tangent_spaces)[3][3];
544  uint i;
545 
546  tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
547 
548  if (csmd->delta_cache.totverts != numVerts) {
550  }
551 
552  /* allocate deltas if they have not yet been allocated, otherwise we will just write over them */
553  if (!csmd->delta_cache.deltas) {
554  csmd->delta_cache.totverts = numVerts;
555  csmd->delta_cache.deltas = MEM_malloc_arrayN(numVerts, sizeof(float[3]), __func__);
556  }
557 
558  smooth_verts(csmd, mesh, dvert, defgrp_index, smooth_vertex_coords, numVerts);
559 
560  calc_tangent_spaces(mesh, smooth_vertex_coords, tangent_spaces);
561 
562  for (i = 0; i < numVerts; i++) {
563  float imat[3][3], delta[3];
564 
565 #ifdef USE_TANGENT_CALC_INLINE
566  calc_tangent_ortho(tangent_spaces[i]);
567 #endif
568 
569  sub_v3_v3v3(delta, rest_coords[i], smooth_vertex_coords[i]);
570  if (UNLIKELY(!invert_m3_m3(imat, tangent_spaces[i]))) {
571  transpose_m3_m3(imat, tangent_spaces[i]);
572  }
573  mul_v3_m3v3(csmd->delta_cache.deltas[i], imat, delta);
574  }
575 
576  MEM_freeN(tangent_spaces);
577  MEM_freeN(smooth_vertex_coords);
578 }
579 
582  Object *ob,
583  Mesh *mesh,
584  float (*vertexCos)[3],
585  uint numVerts,
586  struct BMEditMesh *em)
587 {
589 
590  const bool force_delta_cache_update =
591  /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
592  !cache_settings_equal(csmd) ||
594  (((ID *)ob->data)->recalc & ID_RECALC_ALL));
595 
596  bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
597  MDeformVert *dvert = NULL;
598  int defgrp_index;
599 
600  MOD_get_vgroup(ob, mesh, csmd->defgrp_name, &dvert, &defgrp_index);
601 
602  /* if rest bind_coords not are defined, set them (only run during bind) */
604  /* signal to recalculate, whoever sets MUST also free bind coords */
605  (csmd->bind_coords_num == (uint)-1)) {
606  if (DEG_is_active(depsgraph)) {
607  BLI_assert(csmd->bind_coords == NULL);
608  csmd->bind_coords = MEM_dupallocN(vertexCos);
609  csmd->bind_coords_num = numVerts;
610  BLI_assert(csmd->bind_coords != NULL);
611  /* Copy bound data to the original modifier. */
614  csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords);
615  csmd_orig->bind_coords_num = csmd->bind_coords_num;
616  }
617  else {
618  BKE_modifier_set_error(ob, md, "Attempt to bind from inactive dependency graph");
619  }
620  }
621 
622  if (UNLIKELY(use_only_smooth)) {
623  smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
624  return;
625  }
626 
627  if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
628  BKE_modifier_set_error(ob, md, "Bind data required");
629  goto error;
630  }
631 
632  /* If the number of verts has changed, the bind is invalid, so we do nothing */
634  if (csmd->bind_coords_num != numVerts) {
636  ob, md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
637  goto error;
638  }
639  }
640  else {
641  /* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
642  if (ob->type != OB_MESH) {
643  BKE_modifier_set_error(ob, md, "Object is not a mesh");
644  goto error;
645  }
646  else {
647  uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
648 
649  if (me_numVerts != numVerts) {
651  ob, md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
652  goto error;
653  }
654  }
655  }
656 
657  /* check to see if our deltas are still valid */
658  if (!csmd->delta_cache.deltas || (csmd->delta_cache.totverts != numVerts) ||
659  force_delta_cache_update) {
660  const float(*rest_coords)[3];
661  bool is_rest_coords_alloc = false;
662 
663  store_cache_settings(csmd);
664 
666  /* caller needs to do sanity check here */
667  csmd->bind_coords_num = numVerts;
668  rest_coords = csmd->bind_coords;
669  }
670  else {
671  int me_numVerts;
672  rest_coords = em ? BKE_editmesh_vert_coords_alloc_orco(em, &me_numVerts) :
673  BKE_mesh_vert_coords_alloc(ob->data, &me_numVerts);
674 
675  BLI_assert((uint)me_numVerts == numVerts);
676  is_rest_coords_alloc = true;
677  }
678 
679 #ifdef DEBUG_TIME
680  TIMEIT_START(corrective_smooth_deltas);
681 #endif
682 
683  calc_deltas(csmd, mesh, dvert, defgrp_index, rest_coords, numVerts);
684 
685 #ifdef DEBUG_TIME
686  TIMEIT_END(corrective_smooth_deltas);
687 #endif
688  if (is_rest_coords_alloc) {
689  MEM_freeN((void *)rest_coords);
690  }
691  }
692 
694  /* this could be a check, but at this point it _must_ be valid */
695  BLI_assert(csmd->bind_coords_num == numVerts && csmd->delta_cache.deltas);
696  }
697 
698 #ifdef DEBUG_TIME
699  TIMEIT_START(corrective_smooth);
700 #endif
701 
702  /* do the actual delta mush */
703  smooth_verts(csmd, mesh, dvert, defgrp_index, vertexCos, numVerts);
704 
705  {
706  uint i;
707 
708  float(*tangent_spaces)[3][3];
709  const float scale = csmd->scale;
710  /* calloc, since values are accumulated */
711  tangent_spaces = MEM_calloc_arrayN(numVerts, sizeof(float[3][3]), __func__);
712 
713  calc_tangent_spaces(mesh, vertexCos, tangent_spaces);
714 
715  for (i = 0; i < numVerts; i++) {
716  float delta[3];
717 
718 #ifdef USE_TANGENT_CALC_INLINE
719  calc_tangent_ortho(tangent_spaces[i]);
720 #endif
721 
722  mul_v3_m3v3(delta, tangent_spaces[i], csmd->delta_cache.deltas[i]);
723  madd_v3_v3fl(vertexCos[i], delta, scale);
724  }
725 
726  MEM_freeN(tangent_spaces);
727  }
728 
729 #ifdef DEBUG_TIME
730  TIMEIT_END(corrective_smooth);
731 #endif
732 
733  return;
734 
735  /* when the modifier fails to execute */
736 error:
738  csmd->delta_cache.totverts = 0;
739 }
740 
741 static void deformVerts(ModifierData *md,
742  const ModifierEvalContext *ctx,
743  Mesh *mesh,
744  float (*vertexCos)[3],
745  int numVerts)
746 {
747  Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
748 
750  md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, NULL);
751 
752  if (!ELEM(mesh_src, NULL, mesh)) {
753  BKE_id_free(NULL, mesh_src);
754  }
755 }
756 
757 static void deformVertsEM(ModifierData *md,
758  const ModifierEvalContext *ctx,
759  struct BMEditMesh *editData,
760  Mesh *mesh,
761  float (*vertexCos)[3],
762  int numVerts)
763 {
764  Mesh *mesh_src = MOD_deform_mesh_eval_get(
765  ctx->object, editData, mesh, NULL, numVerts, false, false);
766 
767  /* TODO(Campbell): use edit-mode data only (remove this line). */
768  if (mesh_src != NULL) {
770  }
771 
773  md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData);
774 
775  if (!ELEM(mesh_src, NULL, mesh)) {
776  BKE_id_free(NULL, mesh_src);
777  }
778 }
779 
780 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
781 {
782  uiLayout *layout = panel->layout;
783 
784  PointerRNA ob_ptr;
786 
787  uiLayoutSetPropSep(layout, true);
788 
789  uiItemR(layout, ptr, "factor", 0, IFACE_("Factor"), ICON_NONE);
790  uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
791  uiItemR(layout, ptr, "scale", 0, NULL, ICON_NONE);
792  uiItemR(layout, ptr, "smooth_type", 0, NULL, ICON_NONE);
793 
794  modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
795 
796  uiItemR(layout, ptr, "use_only_smooth", 0, NULL, ICON_NONE);
797  uiItemR(layout, ptr, "use_pin_boundary", 0, NULL, ICON_NONE);
798 
799  uiItemR(layout, ptr, "rest_source", 0, NULL, ICON_NONE);
800  if (RNA_enum_get(ptr, "rest_source") == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
801  uiItemO(layout,
802  (RNA_boolean_get(ptr, "is_bind") ? IFACE_("Unbind") : IFACE_("Bind")),
803  ICON_NONE,
804  "OBJECT_OT_correctivesmooth_bind");
805  }
806 
807  modifier_panel_end(layout, ptr);
808 }
809 
810 static void panelRegister(ARegionType *region_type)
811 {
813 }
814 
815 static void blendWrite(BlendWriter *writer, const ModifierData *md)
816 {
818 
819  if (csmd->bind_coords) {
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 */ "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  /* modifyHair */ NULL,
854  /* modifyGeometrySet */ NULL,
855  /* modifyVolume */ NULL,
856 
857  /* initData */ initData,
858  /* requiredDataMask */ requiredDataMask,
859  /* freeData */ freeData,
860  /* isDisabled */ NULL,
861  /* updateDepsgraph */ NULL,
862  /* dependsOnTime */ NULL,
863  /* dependsOnNormals */ NULL,
864  /* foreachIDLink */ NULL,
865  /* foreachTexLink */ NULL,
866  /* freeRuntimeData */ NULL,
867  /* panelRegister */ panelRegister,
868  /* blendWrite */ blendWrite,
869  /* blendRead */ blendRead,
870 };
typedef float(TangentPoint)[2]
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
float(* BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
Definition: editmesh.c:259
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.c:98
@ eModifierTypeFlag_SupportsEditmode
Definition: BKE_modifier.h:83
@ eModifierTypeFlag_AcceptsMesh
Definition: BKE_modifier.h:80
void BKE_modifier_copydata_generic(const struct ModifierData *md, struct ModifierData *md_dst, const int flag)
@ eModifierTypeType_OnlyDeform
Definition: BKE_modifier.h:58
struct ModifierData * BKE_modifier_get_original(struct ModifierData *md)
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:58
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1161
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:901
void transpose_m3_m3(float R[3][3], const float M[3][3])
Definition: math_matrix.c:1327
void copy_vn_fl(float *array_tar, const int size, const float val)
Definition: math_vector.c:1410
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT
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])
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:83
unsigned short ushort
Definition: BLI_sys_types.h:84
#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:5683
void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr)
Definition: writefile.c:1393
#define IFACE_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
bool DEG_is_active(const struct Depsgraph *depsgraph)
Definition: depsgraph.cc:331
@ ID_RECALC_ALL
Definition: DNA_ID.h:697
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
@ MOD_CORRECTIVESMOOTH_ONLY_SMOOTH
@ MOD_CORRECTIVESMOOTH_PIN_BOUNDARY
@ MOD_CORRECTIVESMOOTH_INVERT_VGROUP
@ MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO
@ MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND
@ eModifierType_CorrectiveSmooth
struct CorrectiveSmoothModifierData CorrectiveSmoothModifierData
@ MOD_CORRECTIVESMOOTH_SMOOTH_LENGTH_WEIGHT
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 deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, struct BMEditMesh *editData, Mesh *mesh, float(*vertexCos)[3], int numVerts)
static void freeBind(CorrectiveSmoothModifierData *csmd)
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
static void store_cache_settings(CorrectiveSmoothModifierData *csmd)
static void mesh_get_weights(MDeformVert *dvert, const int defgrp_index, const uint numVerts, const bool use_invert_vgroup, float *smooth_weights)
#define USE_TANGENT_CALC_INLINE
static void smooth_iter__simple(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float(*vertexCos)[3], uint numVerts, const float *smooth_weights, uint iterations)
ModifierTypeInfo modifierType_CorrectiveSmooth
static void smooth_verts(CorrectiveSmoothModifierData *csmd, Mesh *mesh, MDeformVert *dvert, const int defgrp_index, float(*vertexCos)[3], uint numVerts)
static void blendWrite(BlendWriter *writer, const ModifierData *md)
static void deformVerts(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh, float(*vertexCos)[3], int numVerts)
static void blendRead(BlendDataReader *reader, ModifierData *md)
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 correctivesmooth_modifier_do(ModifierData *md, Depsgraph *depsgraph, Object *ob, Mesh *mesh, float(*vertexCos)[3], uint numVerts, struct BMEditMesh *em)
static void smooth_iter(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float(*vertexCos)[3], uint numVerts, const float *smooth_weights, uint iterations)
static void calc_tangent_ortho(float ts[3][3])
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void smooth_iter__length_weight(CorrectiveSmoothModifierData *csmd, Mesh *mesh, float(*vertexCos)[3], uint numVerts, const float *smooth_weights, uint iterations)
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 requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void calc_deltas(CorrectiveSmoothModifierData *csmd, Mesh *mesh, MDeformVert *dvert, const int defgrp_index, const float(*rest_coords)[3], uint numVerts)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
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 num_verts, const bool use_normals, const bool use_orco)
Definition: MOD_util.c:186
void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
Definition: MOD_util.c:254
Platform independent time functions.
Utility defines for timing/benchmarks.
#define TIMEIT_START(var)
#define TIMEIT_END(var)
StructRNA RNA_CorrectiveSmoothModifier
#define C
Definition: RandGen.cpp:39
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
#define acosf(x)
#define fabsf(x)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
static void error(const char *str)
Definition: meshlaplacian.c:65
const btScalar eps
Definition: poly34.cpp:11
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
struct BMesh * bm
Definition: BKE_editmesh.h:52
int totvert
Definition: bmesh_class.h:297
CorrectiveSmoothDeltaCache delta_cache
Definition: DNA_ID.h:273
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:153
struct Object * object
Definition: BKE_modifier.h:154
void * data
struct uiLayout * layout
PointerRNA * ptr
Definition: wm_files.c:3157