Blender  V2.93
MOD_weighted_normal.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 
21 #include "MEM_guardedalloc.h"
22 
23 #include "BLI_bitmap.h"
24 #include "BLI_linklist.h"
25 #include "BLI_math.h"
26 
27 #include "BLT_translation.h"
28 
29 #include "DNA_defaults.h"
30 #include "DNA_mesh_types.h"
31 #include "DNA_meshdata_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_screen_types.h"
35 
36 #include "BKE_context.h"
37 #include "BKE_deform.h"
38 #include "BKE_lib_id.h"
39 #include "BKE_mesh.h"
40 #include "BKE_screen.h"
41 
42 #include "UI_interface.h"
43 #include "UI_resources.h"
44 
45 #include "RNA_access.h"
46 
47 #include "MOD_modifiertypes.h"
48 #include "MOD_ui_common.h"
49 #include "MOD_util.h"
50 
51 #include "bmesh.h"
52 
53 #define CLNORS_VALID_VEC_LEN (1e-6f)
54 
55 typedef struct ModePair {
56  float val; /* Contains mode based value (face area / corner angle). */
57  int index; /* Index value per poly or per loop. */
59 
60 /* Sorting function used in modifier, sorts in decreasing order. */
61 static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
62 {
63  ModePair *r1 = (ModePair *)p1;
64  ModePair *r2 = (ModePair *)p2;
65 
66  return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
67 }
68 
69 /* There will be one of those per vertex
70  * (simple case, computing one normal per vertex), or per smooth fan. */
72  float normal[3];
73 
74  int num_loops; /* Count number of loops using this item so far. */
75  float curr_val; /* Current max val for this item. */
76  int curr_strength; /* Current max strength encountered for this item. */
78 
79 #define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
80 
81 typedef struct WeightedNormalData {
82  const int numVerts;
83  const int numEdges;
84  const int numLoops;
85  const int numPolys;
86 
89 
91  short (*clnors)[2];
92  const bool has_clnors; /* True if clnors already existed, false if we had to create them. */
93  const float split_angle;
94 
96  float (*polynors)[3];
98 
100  const int defgrp_index;
101  const bool use_invert_vgroup;
102 
103  const float weight;
104  const short mode;
105 
106  /* Lower-level, internal processing data. */
108 
110 
112 
115 
122  const int mp_index)
123 {
124  BLI_assert(wn_data->poly_strength != NULL);
125 
126  const int mp_strength = wn_data->poly_strength[mp_index];
127 
128  if (mp_strength > item_data->curr_strength) {
129  item_data->curr_strength = mp_strength;
130  item_data->curr_val = 0.0f;
131  item_data->num_loops = 0;
132  zero_v3(item_data->normal);
133  }
134 
135  return mp_strength == item_data->curr_strength;
136 }
137 
139  WeightedNormalData *wn_data,
141  const int mv_index,
142  const int mp_index,
143  const float curr_val,
144  const bool use_face_influence)
145 {
146  float(*polynors)[3] = wn_data->polynors;
147 
148  MDeformVert *dvert = wn_data->dvert;
149  const int defgrp_index = wn_data->defgrp_index;
150  const bool use_invert_vgroup = wn_data->use_invert_vgroup;
151 
152  const float weight = wn_data->weight;
153 
154  float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
155 
156  const bool has_vgroup = dvert != NULL;
157  const bool vert_of_group = has_vgroup &&
158  BKE_defvert_find_index(&dvert[mv_index], defgrp_index) != NULL;
159 
160  if (has_vgroup &&
161  ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) {
162  return;
163  }
164 
165  if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) {
166  return;
167  }
168 
169  /* If item's curr_val is 0 init it to present value. */
170  if (item_data->curr_val == 0.0f) {
171  item_data->curr_val = curr_val;
172  }
173  if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
174  /* item's curr_val and present value differ more than threshold, update. */
175  item_data->num_loops++;
176  item_data->curr_val = curr_val;
177  }
178 
179  /* Exponentially divided weight for each normal
180  * (since a few values will be used by most cases, we cache those). */
181  const int num_loops = item_data->num_loops;
182  if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT &&
183  cached_inverse_powers_of_weight[num_loops] == 0.0f) {
184  cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops);
185  }
186  const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
187  cached_inverse_powers_of_weight[num_loops] :
188  1.0f / powf(weight, num_loops);
189 
190  madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight);
191 }
192 
194  WeightedNormalData *wn_data)
195 {
196  const int numVerts = wn_data->numVerts;
197  const int numEdges = wn_data->numEdges;
198  const int numLoops = wn_data->numLoops;
199  const int numPolys = wn_data->numPolys;
200 
201  MVert *mvert = wn_data->mvert;
202  MEdge *medge = wn_data->medge;
203 
204  MLoop *mloop = wn_data->mloop;
205  short(*clnors)[2] = wn_data->clnors;
206  int *loop_to_poly = wn_data->loop_to_poly;
207 
208  MPoly *mpoly = wn_data->mpoly;
209  float(*polynors)[3] = wn_data->polynors;
210  int *poly_strength = wn_data->poly_strength;
211 
212  MDeformVert *dvert = wn_data->dvert;
213 
214  const short mode = wn_data->mode;
215  ModePair *mode_pair = wn_data->mode_pair;
216 
217  const bool has_clnors = wn_data->has_clnors;
218  const float split_angle = wn_data->split_angle;
219  MLoopNorSpaceArray lnors_spacearr = {NULL};
220 
221  const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
222  const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 &&
223  poly_strength != NULL;
224  const bool has_vgroup = dvert != NULL;
225 
226  float(*loop_normals)[3] = NULL;
227 
229  int num_items = 0;
230  if (keep_sharp) {
231  BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__);
232 
233  /* This will give us loop normal spaces,
234  * we do not actually care about computed loop_normals for now... */
235  loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
237  numVerts,
238  medge,
239  numEdges,
240  mloop,
241  loop_normals,
242  numLoops,
243  mpoly,
244  polynors,
245  numPolys,
246  true,
247  split_angle,
248  &lnors_spacearr,
249  has_clnors ? clnors : NULL,
250  loop_to_poly);
251 
252  num_items = lnors_spacearr.num_spaces;
253  items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
254 
255  /* In this first loop, we assign each WeightedNormalDataAggregateItem
256  * to its smooth fan of loops (aka lnor space). */
257  MPoly *mp;
258  int mp_index;
259  int item_index;
260  for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) {
261  int ml_index = mp->loopstart;
262  const int ml_end_index = ml_index + mp->totloop;
263 
264  for (; ml_index < ml_end_index; ml_index++) {
265  if (BLI_BITMAP_TEST(done_loops, ml_index)) {
266  /* Smooth fan of this loop has already been processed, skip it. */
267  continue;
268  }
269  BLI_assert(item_index < num_items);
270 
271  WeightedNormalDataAggregateItem *itdt = &items_data[item_index];
273 
274  MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index];
275  lnor_space->user_data = itdt;
276 
277  if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) {
278  for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) {
279  const int ml_fan_index = POINTER_AS_INT(lnode->link);
280  BLI_BITMAP_ENABLE(done_loops, ml_fan_index);
281  }
282  }
283  else {
284  BLI_BITMAP_ENABLE(done_loops, ml_index);
285  }
286 
287  item_index++;
288  }
289  }
290 
291  MEM_freeN(done_loops);
292  }
293  else {
294  num_items = numVerts;
295  items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
296  if (use_face_influence) {
297  for (int item_index = 0; item_index < num_items; item_index++) {
298  items_data[item_index].curr_strength = FACE_STRENGTH_WEAK;
299  }
300  }
301  }
302  wn_data->items_data = items_data;
303 
304  switch (mode) {
306  for (int i = 0; i < numPolys; i++) {
307  const int mp_index = mode_pair[i].index;
308  const float mp_val = mode_pair[i].val;
309 
310  int ml_index = mpoly[mp_index].loopstart;
311  const int ml_index_end = ml_index + mpoly[mp_index].totloop;
312  for (; ml_index < ml_index_end; ml_index++) {
313  const int mv_index = mloop[ml_index].v;
315  keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index];
316 
318  wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence);
319  }
320  }
321  break;
324  BLI_assert(loop_to_poly != NULL);
325 
326  for (int i = 0; i < numLoops; i++) {
327  const int ml_index = mode_pair[i].index;
328  const float ml_val = mode_pair[i].val;
329 
330  const int mp_index = loop_to_poly[ml_index];
331  const int mv_index = mloop[ml_index].v;
333  keep_sharp ? lnors_spacearr.lspacearr[ml_index]->user_data : &items_data[mv_index];
334 
336  wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence);
337  }
338  break;
339  default:
340  BLI_assert(0);
341  }
342 
343  /* Validate computed weighted normals. */
344  for (int item_index = 0; item_index < num_items; item_index++) {
345  if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
346  zero_v3(items_data[item_index].normal);
347  }
348  }
349 
350  if (keep_sharp) {
351  /* Set loop normals for normal computed for each lnor space (smooth fan).
352  * Note that loop_normals is already populated with clnors
353  * (before this modifier is applied, at start of this function),
354  * so no need to recompute them here. */
355  for (int ml_index = 0; ml_index < numLoops; ml_index++) {
356  WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data;
357  if (!is_zero_v3(item_data->normal)) {
358  copy_v3_v3(loop_normals[ml_index], item_data->normal);
359  }
360  }
361 
363  numVerts,
364  medge,
365  numEdges,
366  mloop,
367  loop_normals,
368  numLoops,
369  mpoly,
370  polynors,
371  numPolys,
372  clnors);
373  }
374  else {
375  /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set()
376  * to keep current clnors instead of resetting them to default auto-computed ones,
377  * when given new custom normal is zero-vec.
378  * But this is not exactly trivial change, better to keep this optimization for later...
379  */
380  if (!has_vgroup) {
381  /* Note: in theory, we could avoid this extra allocation & copying...
382  * But think we can live with it for now,
383  * and it makes code simpler & cleaner. */
384  float(*vert_normals)[3] = MEM_calloc_arrayN(
385  (size_t)numVerts, sizeof(*loop_normals), __func__);
386 
387  for (int ml_index = 0; ml_index < numLoops; ml_index++) {
388  const int mv_index = mloop[ml_index].v;
389  copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
390  }
391 
393  vert_normals,
394  numVerts,
395  medge,
396  numEdges,
397  mloop,
398  numLoops,
399  mpoly,
400  polynors,
401  numPolys,
402  clnors);
403 
404  MEM_freeN(vert_normals);
405  }
406  else {
407  loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
408 
410  numVerts,
411  medge,
412  numEdges,
413  mloop,
414  loop_normals,
415  numLoops,
416  mpoly,
417  polynors,
418  numPolys,
419  true,
420  split_angle,
421  NULL,
422  has_clnors ? clnors : NULL,
423  loop_to_poly);
424 
425  for (int ml_index = 0; ml_index < numLoops; ml_index++) {
426  const int item_index = mloop[ml_index].v;
427  if (!is_zero_v3(items_data[item_index].normal)) {
428  copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal);
429  }
430  }
431 
433  numVerts,
434  medge,
435  numEdges,
436  mloop,
437  loop_normals,
438  numLoops,
439  mpoly,
440  polynors,
441  numPolys,
442  clnors);
443  }
444  }
445 
446  if (keep_sharp) {
447  BKE_lnor_spacearr_free(&lnors_spacearr);
448  }
449  MEM_SAFE_FREE(loop_normals);
450 }
451 
453 {
454  const int numPolys = wn_data->numPolys;
455 
456  MVert *mvert = wn_data->mvert;
457  MLoop *mloop = wn_data->mloop;
458  MPoly *mpoly = wn_data->mpoly;
459 
460  MPoly *mp;
461  int mp_index;
462 
463  ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__);
464 
465  ModePair *f_area = face_area;
466  for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) {
467  f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert);
468  f_area->index = mp_index;
469  }
470 
471  qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse);
472 
473  wn_data->mode_pair = face_area;
474  apply_weights_vertex_normal(wnmd, wn_data);
475 }
476 
478 {
479  const int numLoops = wn_data->numLoops;
480  const int numPolys = wn_data->numPolys;
481 
482  MVert *mvert = wn_data->mvert;
483  MLoop *mloop = wn_data->mloop;
484  MPoly *mpoly = wn_data->mpoly;
485 
486  MPoly *mp;
487  int mp_index;
488 
489  int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
490 
491  ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__);
492 
493  for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
494  MLoop *ml_start = &mloop[mp->loopstart];
495 
496  float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
497  BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
498 
499  ModePair *c_angl = &corner_angle[mp->loopstart];
500  float *angl = index_angle;
501  for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop;
502  ml_index++, c_angl++, angl++) {
503  c_angl->val = (float)M_PI - *angl;
504  c_angl->index = ml_index;
505 
506  loop_to_poly[ml_index] = mp_index;
507  }
508  MEM_freeN(index_angle);
509  }
510 
511  qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse);
512 
513  wn_data->loop_to_poly = loop_to_poly;
514  wn_data->mode_pair = corner_angle;
515  apply_weights_vertex_normal(wnmd, wn_data);
516 }
517 
519 {
520  const int numLoops = wn_data->numLoops;
521  const int numPolys = wn_data->numPolys;
522 
523  MVert *mvert = wn_data->mvert;
524  MLoop *mloop = wn_data->mloop;
525  MPoly *mpoly = wn_data->mpoly;
526 
527  MPoly *mp;
528  int mp_index;
529 
530  int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
531 
532  ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__);
533 
534  for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
535  MLoop *ml_start = &mloop[mp->loopstart];
536 
537  float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert);
538  float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
539  BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
540 
541  ModePair *cmbnd = &combined[mp->loopstart];
542  float *angl = index_angle;
543  for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop;
544  ml_index++, cmbnd++, angl++) {
545  /* In this case val is product of corner angle and face area. */
546  cmbnd->val = ((float)M_PI - *angl) * face_area;
547  cmbnd->index = ml_index;
548 
549  loop_to_poly[ml_index] = mp_index;
550  }
551  MEM_freeN(index_angle);
552  }
553 
554  qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse);
555 
556  wn_data->loop_to_poly = loop_to_poly;
557  wn_data->mode_pair = combined;
558  apply_weights_vertex_normal(wnmd, wn_data);
559 }
560 
562 {
564  Object *ob = ctx->object;
565 
566  /* XXX TODO(Rohan Rathi):
567  * Once we fully switch to Mesh evaluation of modifiers,
568  * we can expect to get that flag from the COW copy.
569  * But for now, it is lost in the DM intermediate step,
570  * so we need to directly check orig object's data. */
571 #if 0
572  if (!(mesh->flag & ME_AUTOSMOOTH))
573 #else
574  if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
575 #endif
576  {
578  ctx->object, (ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
579  return mesh;
580  }
581 
582  Mesh *result;
584 
585  const int numVerts = result->totvert;
586  const int numEdges = result->totedge;
587  const int numLoops = result->totloop;
588  const int numPolys = result->totpoly;
589 
590  MEdge *medge = result->medge;
591  MPoly *mpoly = result->mpoly;
592  MVert *mvert = result->mvert;
593  MLoop *mloop = result->mloop;
594 
595  /* Right now:
596  * If weight = 50 then all faces are given equal weight.
597  * If weight > 50 then more weight given to faces with larger vals (face area / corner angle).
598  * If weight < 50 then more weight given to faces with lesser vals. However current calculation
599  * does not converge to min/max.
600  */
601  float weight = ((float)wnmd->weight) / 50.0f;
602  if (wnmd->weight == 100) {
603  weight = (float)SHRT_MAX;
604  }
605  else if (wnmd->weight == 1) {
606  weight = 1 / (float)SHRT_MAX;
607  }
608  else if ((weight - 1) * 25 > 1) {
609  weight = (weight - 1) * 25;
610  }
611 
612  CustomData *pdata = &result->pdata;
613  float(*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
614  if (!polynors) {
615  polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
617  }
619  mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false);
620 
621  const float split_angle = mesh->smoothresh;
622  short(*clnors)[2];
623  CustomData *ldata = &result->ldata;
624  clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
625 
626  /* Keep info whether we had clnors,
627  * it helps when generating clnor spaces and default normals. */
628  const bool has_clnors = clnors != NULL;
629  if (!clnors) {
630  clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numLoops);
631  }
632 
633  MDeformVert *dvert;
634  int defgrp_index;
635  MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index);
636 
637  WeightedNormalData wn_data = {
638  .numVerts = numVerts,
639  .numEdges = numEdges,
640  .numLoops = numLoops,
641  .numPolys = numPolys,
642 
643  .mvert = mvert,
644  .medge = medge,
645 
646  .mloop = mloop,
647  .clnors = clnors,
648  .has_clnors = has_clnors,
649  .split_angle = split_angle,
650 
651  .mpoly = mpoly,
652  .polynors = polynors,
653  .poly_strength = CustomData_get_layer_named(
655 
656  .dvert = dvert,
657  .defgrp_index = defgrp_index,
658  .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0,
659 
660  .weight = weight,
661  .mode = wnmd->mode,
662  };
663 
664  switch (wnmd->mode) {
666  wn_face_area(wnmd, &wn_data);
667  break;
669  wn_corner_angle(wnmd, &wn_data);
670  break;
672  wn_face_with_angle(wnmd, &wn_data);
673  break;
674  }
675 
676  MEM_SAFE_FREE(wn_data.loop_to_poly);
677  MEM_SAFE_FREE(wn_data.mode_pair);
678  MEM_SAFE_FREE(wn_data.items_data);
679 
680  /* Currently Modifier stack assumes there is no poly normal data passed around... */
681  CustomData_free_layers(pdata, CD_NORMAL, numPolys);
682 
683  result->runtime.is_original = false;
684 
685  return result;
686 }
687 
688 static void initData(ModifierData *md)
689 {
691 
692  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wnmd, modifier));
693 
695 }
696 
697 static void requiredDataMask(Object *UNUSED(ob),
698  ModifierData *md,
699  CustomData_MeshMasks *r_cddata_masks)
700 {
702 
703  r_cddata_masks->lmask = CD_MASK_CUSTOMLOOPNORMAL;
704 
705  if (wnmd->defgrp_name[0] != '\0') {
706  r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
707  }
708 
710  r_cddata_masks->pmask |= CD_MASK_PROP_INT32;
711  }
712 }
713 
715 {
716  return true;
717 }
718 
719 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
720 {
721  uiLayout *col;
722  uiLayout *layout = panel->layout;
723 
724  PointerRNA ob_ptr;
726 
727  uiLayoutSetPropSep(layout, true);
728 
729  uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
730 
731  uiItemR(layout, ptr, "weight", 0, IFACE_("Weight"), ICON_NONE);
732  uiItemR(layout, ptr, "thresh", 0, IFACE_("Threshold"), ICON_NONE);
733 
734  col = uiLayoutColumn(layout, false);
735  uiItemR(col, ptr, "keep_sharp", 0, NULL, ICON_NONE);
736  uiItemR(col, ptr, "use_face_influence", 0, NULL, ICON_NONE);
737 
738  modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
739 
740  modifier_panel_end(layout, ptr);
741 }
742 
743 static void panelRegister(ARegionType *region_type)
744 {
746 }
747 
749  /* name */ "WeightedNormal",
750  /* structName */ "WeightedNormalModifierData",
751  /* structSize */ sizeof(WeightedNormalModifierData),
752  /* srna */ &RNA_WeightedNormalModifier,
756  /* icon */ ICON_MOD_NORMALEDIT,
757 
758  /* copyData */ BKE_modifier_copydata_generic,
759 
760  /* deformVerts */ NULL,
761  /* deformMatrices */ NULL,
762  /* deformVertsEM */ NULL,
763  /* deformMatricesEM */ NULL,
764  /* modifyMesh */ modifyMesh,
765  /* modifyHair */ NULL,
766  /* modifyGeometrySet */ NULL,
767  /* modifyVolume */ NULL,
768 
769  /* initData */ initData,
770  /* requiredDataMask */ requiredDataMask,
771  /* freeData */ NULL,
772  /* isDisabled */ NULL,
773  /* updateDepsgraph */ NULL,
774  /* dependsOnTime */ NULL,
775  /* dependsOnNormals */ dependsOnNormals,
776  /* foreachIDLink */ NULL,
777  /* foreachTexLink */ NULL,
778  /* freeRuntimeData */ NULL,
779  /* panelRegister */ panelRegister,
780  /* blendWrite */ NULL,
781  /* blendRead */ NULL,
782 };
typedef float(TangentPoint)[2]
@ CD_CALLOC
void CustomData_free_layers(struct CustomData *data, int type, int totelem)
Definition: customdata.c:2716
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
Definition: customdata.c:3217
void * CustomData_get_layer(const struct CustomData *data, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.c:2620
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
Definition: customdata.c:2475
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup)
@ LIB_ID_COPY_LOCALIZE
Definition: BKE_lib_id.h:145
struct ID * BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag)
void BKE_mesh_normals_loop_custom_set(const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges, struct MLoop *mloops, float(*r_custom_loopnors)[3], const int numLoops, struct MPoly *mpolys, const float(*polynors)[3], const int numPolys, short(*r_clnors_data)[2])
void BKE_mesh_calc_poly_angles(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray, float angles[])
@ MLNOR_SPACE_IS_SINGLE
Definition: BKE_mesh.h:365
void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts, float(*r_custom_vertnors)[3], const int numVerts, struct MEdge *medges, const int numEdges, struct MLoop *mloops, const int numLoops, struct MPoly *mpolys, const float(*polynors)[3], const int numPolys, short(*r_clnors_data)[2])
void BKE_mesh_normals_loop_split(const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges, struct MLoop *mloops, float(*r_loopnors)[3], const int numLoops, struct MPoly *mpolys, const float(*polynors)[3], const int numPolys, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2], int *r_loop_to_poly)
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray)
void BKE_mesh_calc_normals_poly(struct MVert *mverts, float(*r_vertnors)[3], int numVerts, const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float(*r_polyNors)[3], const bool only_face_normals)
@ eModifierTypeFlag_SupportsMapping
Definition: BKE_modifier.h:82
@ eModifierTypeFlag_EnableInEditmode
Definition: BKE_modifier.h:92
@ 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_Constructive
Definition: BKE_modifier.h:61
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
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:63
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_NEW(_tot, _alloc_string)
Definition: BLI_bitmap.h:50
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
MINLINE int compare_ff(float a, float b, const float max_diff)
#define M_PI
Definition: BLI_math_base.h:38
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define IFACE_(msgid)
#define CD_MASK_MDEFORMVERT
@ CD_CUSTOMLOOPNORMAL
@ CD_PROP_INT32
#define CD_MASK_PROP_INT32
#define CD_MASK_CUSTOMLOOPNORMAL
@ CD_FLAG_TEMPORARY
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
@ ME_AUTOSMOOTH
@ MOD_WEIGHTEDNORMAL_KEEP_SHARP
@ MOD_WEIGHTEDNORMAL_FACE_INFLUENCE
@ MOD_WEIGHTEDNORMAL_INVERT_VGROUP
@ MOD_WEIGHTEDNORMAL_MODE_FACE
@ MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE
@ MOD_WEIGHTEDNORMAL_MODE_ANGLE
struct WeightedNormalModifierData WeightedNormalModifierData
@ eModifierType_WeightedNormal
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
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)
void MOD_get_vgroup(Object *ob, struct Mesh *mesh, const char *name, MDeformVert **dvert, int *defgrp_index)
Definition: MOD_util.c:254
static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static Mesh * modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static bool check_item_poly_strength(WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index)
static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT
struct ModePair ModePair
static bool dependsOnNormals(ModifierData *UNUSED(md))
ModifierTypeInfo modifierType_WeightedNormal
struct WeightedNormalData WeightedNormalData
static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
struct WeightedNormalDataAggregateItem WeightedNormalDataAggregateItem
#define CLNORS_VALID_VEC_LEN
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void initData(ModifierData *md)
static void panelRegister(ARegionType *region_type)
static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
static void aggregate_item_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mv_index, const int mp_index, const float curr_val, const bool use_face_influence)
static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
StructRNA RNA_WeightedNormalModifier
#define C
Definition: RandGen.cpp:39
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
@ FACE_STRENGTH_WEAK
uint col
IconTextureDrawCall normal
#define powf(x, y)
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_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
struct LinkNode * next
Definition: BLI_linklist.h:39
MLoopNorSpace ** lspacearr
Definition: BKE_mesh.h:372
void * user_data
Definition: BKE_mesh.h:359
struct LinkNode * loops
Definition: BKE_mesh.h:355
unsigned int v
float smoothresh
short flag
struct Object * object
Definition: BKE_modifier.h:154
void * data
struct uiLayout * layout
WeightedNormalDataAggregateItem * items_data
float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT]
PointerRNA * ptr
Definition: wm_files.c:3157