Blender V4.3
MOD_skin.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9/* Implementation based in part off the paper "B-Mesh: A Fast Modeling
10 * System for Base Meshes of 3D Articulated Shapes" (Zhongping Ji,
11 * Ligang Liu, Yigang Wang)
12 *
13 * Note that to avoid confusion with Blender's BMesh data structure,
14 * this tool is renamed as the Skin modifier.
15 *
16 * The B-Mesh paper is current available here:
17 * http://www.math.zju.edu.cn/ligangliu/CAGD/Projects/BMesh/
18 *
19 * The main missing features in this code compared to the paper are:
20 *
21 * - No mesh evolution. The paper suggests iteratively subdivision-surfacing the
22 * skin output and adapting the output to better conform with the
23 * spheres of influence surrounding each vertex.
24 *
25 * - No mesh fairing. The paper suggests re-aligning output edges to
26 * follow principal mesh curvatures.
27 *
28 * - No auxiliary balls. These would serve to influence mesh
29 * evolution, which as noted above is not implemented.
30 *
31 * The code also adds some features not present in the paper:
32 *
33 * + Loops in the input edge graph.
34 *
35 * + Concave surfaces around branch nodes. The paper does not discuss
36 * how to handle non-convex regions; this code adds a number of
37 * cleanup operations to handle many (though not all) of these
38 * cases.
39 */
40
41#include "MEM_guardedalloc.h"
42
43#include "BLI_utildefines.h"
44
45#include "BLI_array_utils.hh"
46#include "BLI_bitmap.h"
47#include "BLI_heap_simple.h"
48#include "BLI_math_geom.h"
49#include "BLI_math_matrix.h"
50#include "BLI_stack.h"
51#include "BLI_vector.hh"
52
53#include "BLT_translation.hh"
54
55#include "DNA_defaults.h"
56#include "DNA_mesh_types.h"
57#include "DNA_meshdata_types.h"
58#include "DNA_modifier_types.h"
59#include "DNA_screen_types.h"
60
61#include "BKE_deform.hh"
62#include "BKE_lib_id.hh"
63#include "BKE_mesh.hh"
64#include "BKE_mesh_mapping.hh"
65#include "BKE_modifier.hh"
66
67#include "UI_interface.hh"
68#include "UI_resources.hh"
69
70#include "RNA_access.hh"
71#include "RNA_prototypes.hh"
72
73#include "WM_types.hh" /* For skin mark clear operator UI. */
74
75#include "MOD_ui_common.hh"
76
77#include "bmesh.hh"
78
79/* -------------------------------------------------------------------- */
84{
85 BMIter iter;
86 BMFace *f;
87 BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
88 f->no[0] = FLT_MAX;
89 }
90}
91
93{
94 BMIter iter;
95 BMFace *f;
96 BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
97 if (f->no[0] == FLT_MAX) {
99 }
100 }
101}
102
106static void vert_array_face_normal_update(BMVert **verts, int verts_len)
107{
108 for (int i = 0; i < verts_len; i++) {
110 }
111
112 for (int i = 0; i < verts_len; i++) {
114 }
115}
116
119struct EMat {
120 float mat[3][3];
121 /* Vert that edge is pointing away from, no relation to
122 * edge[0] */
124};
125
133
134struct Frame {
135 /* Index in the vertex array */
137 /* Location of each corner */
138 float co[4][3];
139 /* Indicates which corners have been merged with another
140 * frame's corner (so they share a vertex index) */
141 struct {
142 /* Merge to target frame/corner (no merge if frame is null) */
145 /* checked to avoid chaining.
146 * (merging when we're already been referenced), see #39775 */
148 } merge[4];
149
150 /* For hull frames, whether each vertex is detached or not */
151 bool inside_hull[4];
152 /* Whether any part of the frame (corner or edge) is detached */
154};
155
156#define MAX_SKIN_NODE_FRAMES 2
157struct SkinNode {
160
162
163 /* Used for hulling a loop seam */
165};
166
172
173static void add_poly(SkinOutput *so, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4);
174
175/***************************** Convex Hull ****************************/
176
177static bool is_quad_symmetric(BMVert *quad[4], const SkinModifierData *smd)
178{
179 const float threshold = 0.0001f;
180 const float threshold_squared = threshold * threshold;
181 int axis;
182
183 for (axis = 0; axis < 3; axis++) {
184 if (smd->symmetry_axes & (1 << axis)) {
185 float a[3];
186
187 copy_v3_v3(a, quad[0]->co);
188 a[axis] = -a[axis];
189
190 if (len_squared_v3v3(a, quad[1]->co) < threshold_squared) {
191 copy_v3_v3(a, quad[2]->co);
192 a[axis] = -a[axis];
193 if (len_squared_v3v3(a, quad[3]->co) < threshold_squared) {
194 return true;
195 }
196 }
197 else if (len_squared_v3v3(a, quad[3]->co) < threshold_squared) {
198 copy_v3_v3(a, quad[2]->co);
199 a[axis] = -a[axis];
200 if (len_squared_v3v3(a, quad[1]->co) < threshold_squared) {
201 return true;
202 }
203 }
204 }
205 }
206
207 return false;
208}
209
210/* Returns true if the quad crosses the plane of symmetry, false otherwise */
212{
213 int axis;
214
215 for (axis = 0; axis < 3; axis++) {
216 if (smd->symmetry_axes & (1 << axis)) {
217 bool left = false, right = false;
218 int i;
219
220 for (i = 0; i < 4; i++) {
221 if (quad[i]->co[axis] < 0.0f) {
222 left = true;
223 }
224 else if (quad[i]->co[axis] > 0.0f) {
225 right = true;
226 }
227
228 if (left && right) {
229 return true;
230 }
231 }
232 }
233 }
234
235 return false;
236}
237
238#ifdef WITH_BULLET
239
240/* Returns true if the frame is filled by precisely two faces (and
241 * outputs those faces to fill_faces), otherwise returns false. */
242static bool skin_frame_find_contained_faces(const Frame *frame, BMFace *fill_faces[2])
243{
244 BMEdge *diag;
245
246 /* See if the frame is bisected by a diagonal edge */
247 diag = BM_edge_exists(frame->verts[0], frame->verts[2]);
248 if (!diag) {
249 diag = BM_edge_exists(frame->verts[1], frame->verts[3]);
250 }
251
252 if (diag) {
253 return BM_edge_face_pair(diag, &fill_faces[0], &fill_faces[1]);
254 }
255
256 return false;
257}
258
259#endif
260
261/* Returns true if hull is successfully built, false otherwise */
262static bool build_hull(SkinOutput *so, Frame **frames, int totframe)
263{
264#ifdef WITH_BULLET
265 BMesh *bm = so->bm;
266 BMOperator op;
267 BMIter iter;
268 BMOIter oiter;
269 BMVert *v;
270 BMFace *f;
271 BMEdge *e;
272 int i, j;
273
275
276 for (i = 0; i < totframe; i++) {
277 for (j = 0; j < 4; j++) {
278 BM_elem_flag_enable(frames[i]->verts[j], BM_ELEM_TAG);
279 }
280 }
281
282 /* Deselect all faces so that only new hull output faces are
283 * selected after the operator is run */
285
287 bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "convex_hull input=%hv", BM_ELEM_TAG);
288 BMO_op_exec(bm, &op);
289
291 BMO_op_finish(bm, &op);
292 return false;
293 }
294
295 /* Apply face attributes to hull output */
296 BMO_ITER (f, &oiter, op.slots_out, "geom.out", BM_FACE) {
298 if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING) {
300 }
301 f->mat_nr = so->mat_nr;
302 }
303
304 /* Mark interior frames */
305 BMO_ITER (v, &oiter, op.slots_out, "geom_interior.out", BM_VERT) {
306 for (i = 0; i < totframe; i++) {
307 Frame *frame = frames[i];
308
309 if (!frame->detached) {
310 for (j = 0; j < 4; j++) {
311 if (frame->verts[j] == v) {
312 frame->inside_hull[j] = true;
313 frame->detached = true;
314 break;
315 }
316 }
317 }
318 }
319 }
320
321 /* Also mark frames as interior if an edge is not in the hull */
322 for (i = 0; i < totframe; i++) {
323 Frame *frame = frames[i];
324
325 if (!frame->detached && (!BM_edge_exists(frame->verts[0], frame->verts[1]) ||
326 !BM_edge_exists(frame->verts[1], frame->verts[2]) ||
327 !BM_edge_exists(frame->verts[2], frame->verts[3]) ||
328 !BM_edge_exists(frame->verts[3], frame->verts[0])))
329 {
330 frame->detached = true;
331 }
332 }
333
334 /* Remove triangles that would fill the original frames -- skip if
335 * frame is partially detached */
337 for (i = 0; i < totframe; i++) {
338 Frame *frame = frames[i];
339 if (!frame->detached) {
340 BMFace *fill_faces[2];
341
342 /* Check if the frame is filled by precisely two
343 * triangles. If so, delete the triangles and their shared
344 * edge. Otherwise, give up and mark the frame as
345 * detached. */
346 if (skin_frame_find_contained_faces(frame, fill_faces)) {
347 BM_elem_flag_enable(fill_faces[0], BM_ELEM_TAG);
348 BM_elem_flag_enable(fill_faces[1], BM_ELEM_TAG);
349 }
350 else {
351 frame->detached = true;
352 }
353 }
354 }
355
356 /* Check if removing triangles above will create wire triangles,
357 * mark them too */
358 BMO_ITER (e, &oiter, op.slots_out, "geom.out", BM_EDGE) {
359 bool is_wire = true;
360 BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) {
362 is_wire = false;
363 break;
364 }
365 }
366 if (is_wire) {
368 }
369 }
370
371 BMO_op_finish(bm, &op);
372
374
375 return true;
376#else
377 UNUSED_VARS(so, frames, totframe);
378 return false;
379#endif
380}
381
382/* Returns the average frame side length (frames are rectangular, so
383 * just the average of two adjacent edge lengths) */
384static float frame_len(const Frame *frame)
385{
386 return (len_v3v3(frame->co[0], frame->co[1]) + len_v3v3(frame->co[1], frame->co[2])) * 0.5f;
387}
388
389static void merge_frame_corners(Frame **frames, int totframe)
390{
391 float dist, side_a, side_b, thresh, mid[3];
392 int i, j, k, l;
393
394 for (i = 0; i < totframe; i++) {
395 side_a = frame_len(frames[i]);
396
397 /* For each corner of each frame... */
398 for (j = 0; j < 4; j++) {
399
400 /* Ensure the merge target is not itself a merge target */
401 if (frames[i]->merge[j].frame) {
402 continue;
403 }
404
405 for (k = i + 1; k < totframe; k++) {
406 BLI_assert(frames[i] != frames[k]);
407
408 side_b = frame_len(frames[k]);
409 thresh = min_ff(side_a, side_b) / 2.0f;
410
411 /* Compare with each corner of all other frames... */
412 for (l = 0; l < 4; l++) {
413 if (frames[k]->merge[l].frame || frames[k]->merge[l].is_target) {
414 continue;
415 }
416
417 /* Some additional concerns that could be checked
418 * further:
419 *
420 * + Vertex coords are being used for the
421 * edge-length test, but are also being
422 * modified, might cause symmetry problems.
423 *
424 * + A frame could be merged diagonally across
425 * another, would generate a weird (bad) T
426 * junction
427 */
428
429 /* Check if corners are near each other, where
430 * 'near' is based in the frames' minimum side
431 * length */
432 dist = len_v3v3(frames[i]->co[j], frames[k]->co[l]);
433 if (dist < thresh) {
434 mid_v3_v3v3(mid, frames[i]->co[j], frames[k]->co[l]);
435
436 copy_v3_v3(frames[i]->co[j], mid);
437 copy_v3_v3(frames[k]->co[l], mid);
438
439 frames[k]->merge[l].frame = frames[i];
440 frames[k]->merge[l].corner = j;
441 frames[i]->merge[j].is_target = true;
442
443 /* Can't merge another corner into the same
444 * frame corner, so move on to frame k+1 */
445 break;
446 }
447 }
448 }
449 }
450 }
451}
452
454 SkinNode *frames,
457 int *tothullframe)
458{
459 SkinNode *f;
460 Frame **hull_frames;
461 int hull_frames_num, i;
462
463 (*tothullframe) = emap[v].size();
464 hull_frames = MEM_cnew_array<Frame *>(*tothullframe, __func__);
465 hull_frames_num = 0;
466 for (i = 0; i < emap[v].size(); i++) {
467 const blender::int2 &edge = edges[emap[v][i]];
468 f = &frames[blender::bke::mesh::edge_other_vert(edge, v)];
469 /* Can't have adjacent branch nodes yet */
470 if (f->totframe) {
471 hull_frames[hull_frames_num++] = &f->frames[0];
472 }
473 else {
474 (*tothullframe)--;
475 }
476 }
477
478 return hull_frames;
479}
480
481/**************************** Create Frames ***************************/
482
483static void node_frames_init(SkinNode *nf, int totframe)
484{
485 int i;
486
487 nf->totframe = totframe;
488 memset(nf->frames, 0, sizeof(nf->frames));
489
490 nf->flag = SkinNodeFlag(0);
491 for (i = 0; i < 2; i++) {
492 nf->seam_edges[i] = -1;
493 }
494}
495
496static void create_frame(
497 Frame *frame, const float co[3], const float radius[2], const float mat[3][3], float offset)
498{
499 float rx[3], ry[3], rz[3];
500 int i;
501
502 mul_v3_v3fl(ry, mat[1], radius[0]);
503 mul_v3_v3fl(rz, mat[2], radius[1]);
504
505 add_v3_v3v3(frame->co[3], co, ry);
506 add_v3_v3v3(frame->co[3], frame->co[3], rz);
507
508 sub_v3_v3v3(frame->co[2], co, ry);
509 add_v3_v3v3(frame->co[2], frame->co[2], rz);
510
511 sub_v3_v3v3(frame->co[1], co, ry);
512 sub_v3_v3v3(frame->co[1], frame->co[1], rz);
513
514 add_v3_v3v3(frame->co[0], co, ry);
515 sub_v3_v3v3(frame->co[0], frame->co[0], rz);
516
517 mul_v3_v3fl(rx, mat[0], offset);
518 for (i = 0; i < 4; i++) {
519 add_v3_v3v3(frame->co[i], frame->co[i], rx);
520 }
521}
522
523static float half_v2(const float v[2])
524{
525 return (v[0] + v[1]) * 0.5f;
526}
527
528static void end_node_frames(int v,
529 SkinNode *skin_nodes,
530 const blender::Span<blender::float3> vert_positions,
531 const MVertSkin *nodes,
533 EMat *emat)
534{
535 const float *rad = nodes[v].radius;
536 float mat[3][3];
537
538 if (emap[v].is_empty()) {
539 float avg = half_v2(rad);
540
541 /* For solitary nodes, just build a box (two frames) */
542 node_frames_init(&skin_nodes[v], 2);
543 skin_nodes[v].flag |= (CAP_START | CAP_END);
544
545 /* Hardcoded basis */
546 zero_m3(mat);
547 mat[0][2] = mat[1][0] = mat[2][1] = 1;
548
549 /* Caps */
550 create_frame(&skin_nodes[v].frames[0], vert_positions[v], rad, mat, avg);
551 create_frame(&skin_nodes[v].frames[1], vert_positions[v], rad, mat, -avg);
552 }
553 else {
554 /* For nodes with an incoming edge, create a single (capped) frame */
555 node_frames_init(&skin_nodes[v], 1);
556 skin_nodes[v].flag |= CAP_START;
557
558 /* Use incoming edge for orientation */
559 copy_m3_m3(mat, emat[emap[v][0]].mat);
560 if (emat[emap[v][0]].origin != v) {
561 negate_v3(mat[0]);
562 }
563
564 Frame *frame = &skin_nodes[v].frames[0];
565
566 /* End frame */
567 create_frame(frame, vert_positions[v], rad, mat, 0);
568
569 /* The caps might need to have their normals inverted. So check if they
570 * need to be flipped when creating faces. */
571 float normal[3];
572 normal_quad_v3(normal, frame->co[0], frame->co[1], frame->co[2], frame->co[3]);
573 if (dot_v3v3(mat[0], normal) < 0.0f) {
574 skin_nodes[v].flag |= FLIP_NORMAL;
575 }
576 }
577}
578
579/* Returns 1 for seam, 0 otherwise */
580static int connection_node_mat(float mat[3][3], int v, blender::GroupedSpan<int> emap, EMat *emat)
581{
582 float axis[3], angle, ine[3][3], oute[3][3];
583 EMat *e1, *e2;
584
585 e1 = &emat[emap[v][0]];
586 e2 = &emat[emap[v][1]];
587
588 if (e1->origin != v && e2->origin == v) {
589 copy_m3_m3(ine, e1->mat);
590 copy_m3_m3(oute, e2->mat);
591 }
592 else if (e1->origin == v && e2->origin != v) {
593 copy_m3_m3(ine, e2->mat);
594 copy_m3_m3(oute, e1->mat);
595 }
596 else {
597 return 1;
598 }
599
600 /* Get axis and angle to rotate frame by */
601 angle = angle_normalized_v3v3(ine[0], oute[0]) / 2.0f;
602 cross_v3_v3v3(axis, ine[0], oute[0]);
603 normalize_v3(axis);
604
605 /* Build frame matrix (don't care about X axis here) */
606 copy_v3_v3(mat[0], ine[0]);
607 rotate_normalized_v3_v3v3fl(mat[1], ine[1], axis, angle);
608 rotate_normalized_v3_v3v3fl(mat[2], ine[2], axis, angle);
609
610 return 0;
611}
612
613static void connection_node_frames(int v,
614 SkinNode *skin_nodes,
615 const blender::Span<blender::float3> vert_positions,
616 const MVertSkin *nodes,
618 EMat *emat)
619{
620 const float *rad = nodes[v].radius;
621 float mat[3][3];
622 EMat *e1, *e2;
623
624 if (connection_node_mat(mat, v, emap, emat)) {
625 float avg = half_v2(rad);
626
627 /* Get edges */
628 e1 = &emat[emap[v][0]];
629 e2 = &emat[emap[v][1]];
630
631 /* Handle seam separately to avoid twisting */
632 /* Create two frames, will be hulled to neighbors later */
633 node_frames_init(&skin_nodes[v], 2);
634 skin_nodes[v].flag |= SEAM_FRAME;
635
636 copy_m3_m3(mat, e1->mat);
637 if (e1->origin != v) {
638 negate_v3(mat[0]);
639 }
640 create_frame(&skin_nodes[v].frames[0], vert_positions[v], rad, mat, avg);
641 skin_nodes[v].seam_edges[0] = emap[v][0];
642
643 copy_m3_m3(mat, e2->mat);
644 if (e2->origin != v) {
645 negate_v3(mat[0]);
646 }
647 create_frame(&skin_nodes[v].frames[1], vert_positions[v], rad, mat, avg);
648 skin_nodes[v].seam_edges[1] = emap[v][1];
649
650 return;
651 }
652
653 /* Build regular frame */
654 node_frames_init(&skin_nodes[v], 1);
655 create_frame(&skin_nodes[v].frames[0], vert_positions[v], rad, mat, 0);
656}
657
659 int verts_num,
660 const MVertSkin *nodes,
662 EMat *emat)
663{
664 int v;
665
666 SkinNode *skin_nodes = MEM_cnew_array<SkinNode>(verts_num, __func__);
667
668 for (v = 0; v < verts_num; v++) {
669 if (emap[v].size() <= 1) {
670 end_node_frames(v, skin_nodes, vert_positions, nodes, emap, emat);
671 }
672 else if (emap[v].size() == 2) {
673 connection_node_frames(v, skin_nodes, vert_positions, nodes, emap, emat);
674 }
675 else {
676 /* Branch node generates no frames */
677 }
678 }
679
680 return skin_nodes;
681}
682
683/**************************** Edge Matrices ***************************/
684
685static void calc_edge_mat(float mat[3][3], const float a[3], const float b[3])
686{
687 const float z_up[3] = {0, 0, 1};
688 float dot;
689
690 /* X = edge direction */
691 sub_v3_v3v3(mat[0], b, a);
692 normalize_v3(mat[0]);
693
694 dot = dot_v3v3(mat[0], z_up);
695 if (dot > -1 + FLT_EPSILON && dot < 1 - FLT_EPSILON) {
696 /* Y = Z cross x */
697 cross_v3_v3v3(mat[1], z_up, mat[0]);
698 normalize_v3(mat[1]);
699
700 /* Z = x cross y */
701 cross_v3_v3v3(mat[2], mat[0], mat[1]);
702 normalize_v3(mat[2]);
703 }
704 else {
705 mat[1][0] = 1;
706 mat[1][1] = 0;
707 mat[1][2] = 0;
708 mat[2][0] = 0;
709 mat[2][1] = 1;
710 mat[2][2] = 0;
711 }
712}
713
715 float mat[3][3];
717 int e;
718};
719
720static void build_emats_stack(BLI_Stack *stack,
721 BLI_bitmap *visited_e,
722 EMat *emat,
725 const MVertSkin *vs,
726 const blender::Span<blender::float3> vert_positions)
727{
728 EdgeStackElem stack_elem;
729 float axis[3], angle;
730 int i, e, v, parent_v, parent_is_branch;
731
732 BLI_stack_pop(stack, &stack_elem);
733 parent_v = stack_elem.parent_v;
734 e = stack_elem.e;
735
736 /* Skip if edge already visited */
737 if (BLI_BITMAP_TEST(visited_e, e)) {
738 return;
739 }
740
741 /* Mark edge as visited */
742 BLI_BITMAP_ENABLE(visited_e, e);
743
744 /* Process edge */
745
746 parent_is_branch = ((emap[parent_v].size() > 2) || (vs[parent_v].flag & MVERT_SKIN_ROOT));
747
748 v = blender::bke::mesh::edge_other_vert(edges[e], parent_v);
749 emat[e].origin = parent_v;
750
751 /* If parent is a branch node, start a new edge chain */
752 if (parent_is_branch) {
753 calc_edge_mat(emat[e].mat, vert_positions[parent_v], vert_positions[v]);
754 }
755 else {
756 /* Build edge matrix guided by parent matrix */
757 sub_v3_v3v3(emat[e].mat[0], vert_positions[v], vert_positions[parent_v]);
758 normalize_v3(emat[e].mat[0]);
759 angle = angle_normalized_v3v3(stack_elem.mat[0], emat[e].mat[0]);
760 cross_v3_v3v3(axis, stack_elem.mat[0], emat[e].mat[0]);
761 normalize_v3(axis);
762 rotate_normalized_v3_v3v3fl(emat[e].mat[1], stack_elem.mat[1], axis, angle);
763 rotate_normalized_v3_v3v3fl(emat[e].mat[2], stack_elem.mat[2], axis, angle);
764 }
765
766 /* Add neighbors to stack */
767 for (i = 0; i < emap[v].size(); i++) {
768 /* Add neighbors to stack */
769 copy_m3_m3(stack_elem.mat, emat[e].mat);
770 stack_elem.e = emap[v][i];
771 stack_elem.parent_v = v;
772 BLI_stack_push(stack, &stack_elem);
773 }
774}
775
777 const blender::Span<blender::float3> vert_positions,
778 const int verts_num,
781 bool *has_valid_root)
782{
783 BLI_Stack *stack;
784 EMat *emat;
785 EdgeStackElem stack_elem;
786 BLI_bitmap *visited_e;
787 int i, v;
788
789 stack = BLI_stack_new(sizeof(stack_elem), "build_edge_mats.stack");
790
791 visited_e = BLI_BITMAP_NEW(edges.size(), "build_edge_mats.visited_e");
792 emat = MEM_cnew_array<EMat>(edges.size(), __func__);
793
794 /* Edge matrices are built from the root nodes, add all roots with
795 * children to the stack */
796 for (v = 0; v < verts_num; v++) {
797 if (vs[v].flag & MVERT_SKIN_ROOT) {
798 if (emap[v].size() >= 1) {
799 const blender::int2 &edge = edges[emap[v][0]];
800 calc_edge_mat(stack_elem.mat,
801 vert_positions[v],
802 vert_positions[blender::bke::mesh::edge_other_vert(edge, v)]);
803 stack_elem.parent_v = v;
804
805 /* Add adjacent edges to stack */
806 for (i = 0; i < emap[v].size(); i++) {
807 stack_elem.e = emap[v][i];
808 BLI_stack_push(stack, &stack_elem);
809 }
810
811 *has_valid_root = true;
812 }
813 else if (edges.is_empty()) {
814 /* Vertex-only mesh is valid, mark valid root as well (will display error otherwise). */
815 *has_valid_root = true;
816 break;
817 }
818 }
819 }
820
821 while (!BLI_stack_is_empty(stack)) {
822 build_emats_stack(stack, visited_e, emat, emap, edges, vs, vert_positions);
823 }
824
825 MEM_freeN(visited_e);
826 BLI_stack_free(stack);
827
828 return emat;
829}
830
831/************************** Input Subdivision *************************/
832
833/* Returns number of edge subdivisions, taking into account the radius
834 * of the endpoints and the edge length. If both endpoints are branch
835 * nodes, at least two intermediate frames are required. (This avoids
836 * having any special cases for dealing with sharing a frame between
837 * two hulls.) */
839 const MVertSkin *nodes,
840 const blender::int2 &edge,
841 const blender::Span<int> degree)
842{
843 /* prevent memory errors #38003. */
844#define NUM_SUBDIVISIONS_MAX 128
845
846 const MVertSkin *evs[2] = {&nodes[edge[0]], &nodes[edge[1]]};
847 float avg_radius;
848 const bool v1_branch = degree[edge[0]] > 2;
849 const bool v2_branch = degree[edge[1]] > 2;
850 int subdivisions_num;
851
852 /* If either end is a branch node marked 'loose', don't subdivide
853 * the edge (or subdivide just twice if both are branches) */
854 if ((v1_branch && (evs[0]->flag & MVERT_SKIN_LOOSE)) ||
855 (v2_branch && (evs[1]->flag & MVERT_SKIN_LOOSE)))
856 {
857 if (v1_branch && v2_branch) {
858 return 2;
859 }
860
861 return 0;
862 }
863
864 avg_radius = half_v2(evs[0]->radius) + half_v2(evs[1]->radius);
865
866 if (avg_radius != 0.0f) {
867 /* possible (but unlikely) that we overflow INT_MAX */
868 float subdivisions_num_fl;
869 const float edge_len = len_v3v3(vert_positions[edge[0]], vert_positions[edge[1]]);
870 subdivisions_num_fl = (edge_len / avg_radius);
871 if (subdivisions_num_fl < NUM_SUBDIVISIONS_MAX) {
872 subdivisions_num = int(subdivisions_num_fl);
873 }
874 else {
875 subdivisions_num = NUM_SUBDIVISIONS_MAX;
876 }
877 }
878 else {
879 subdivisions_num = 0;
880 }
881
882 /* If both ends are branch nodes, two intermediate nodes are
883 * required */
884 if (subdivisions_num < 2 && v1_branch && v2_branch) {
885 subdivisions_num = 2;
886 }
887
888 return subdivisions_num;
889
890#undef NUM_SUBDIVISIONS_MAX
891}
892
893/* Take a Mesh and subdivide its edges to keep skin nodes
894 * reasonably close. */
895static Mesh *subdivide_base(const Mesh *orig)
896{
897 int subd_num;
898 int i, j, k, u, v;
899 float radrat;
900
901 const MVertSkin *orignode = static_cast<const MVertSkin *>(
903 const blender::Span<blender::float3> orig_vert_positions = orig->vert_positions();
904 const blender::Span<blender::int2> orig_edges = orig->edges();
905 const MDeformVert *origdvert = orig->deform_verts().data();
906 int orig_vert_num = orig->verts_num;
907 int orig_edge_num = orig->edges_num;
908
909 /* Get degree of all vertices */
910 blender::Array<int> degree(orig_vert_num, 0);
911 blender::array_utils::count_indices(orig_edges.cast<int>(), degree);
912
913 /* Per edge, store how many subdivisions are needed */
914 blender::Array<int> edge_subd(orig_edge_num, 0);
915 for (i = 0, subd_num = 0; i < orig_edge_num; i++) {
916 edge_subd[i] += calc_edge_subdivisions(orig_vert_positions, orignode, orig_edges[i], degree);
917 BLI_assert(edge_subd[i] >= 0);
918 subd_num += edge_subd[i];
919 }
920
921 /* Allocate output mesh */
923 orig, orig_vert_num + subd_num, orig_edge_num + subd_num, 0, 0);
924
925 blender::MutableSpan<blender::float3> out_vert_positions = result->vert_positions_for_write();
926 blender::MutableSpan<blender::int2> result_edges = result->edges_for_write();
927 MVertSkin *outnode = static_cast<MVertSkin *>(
928 CustomData_get_layer_for_write(&result->vert_data, CD_MVERT_SKIN, result->verts_num));
929 MDeformVert *outdvert = nullptr;
930 if (origdvert) {
931 outdvert = result->deform_verts_for_write().data();
932 }
933
934 /* Copy original vertex data */
935 CustomData_copy_data(&orig->vert_data, &result->vert_data, 0, 0, orig_vert_num);
936
937 /* Subdivide edges */
938 int result_edge_i = 0;
939 for (i = 0, v = orig_vert_num; i < orig_edge_num; i++) {
940 struct VGroupData {
941 /* Vertex group number */
942 int def_nr;
943 float w1, w2;
944 };
945 VGroupData *vgroups = nullptr, *vg;
946 int vgroups_num = 0;
947
948 const blender::int2 &edge = orig_edges[i];
949
950 if (origdvert) {
951 const MDeformVert *dv1 = &origdvert[edge[0]];
952 const MDeformVert *dv2 = &origdvert[edge[1]];
953 vgroups = MEM_cnew_array<VGroupData>(dv1->totweight, __func__);
954
955 /* Only want vertex groups used by both vertices */
956 for (j = 0; j < dv1->totweight; j++) {
957 vg = nullptr;
958 for (k = 0; k < dv2->totweight; k++) {
959 if (dv1->dw[j].def_nr == dv2->dw[k].def_nr) {
960 vg = &vgroups[vgroups_num];
961 vgroups_num++;
962 break;
963 }
964 }
965
966 if (vg) {
967 vg->def_nr = dv1->dw[j].def_nr;
968 vg->w1 = dv1->dw[j].weight;
969 vg->w2 = dv2->dw[k].weight;
970 }
971 }
972 }
973
974 u = edge[0];
975 radrat = (half_v2(outnode[edge[1]].radius) / half_v2(outnode[edge[0]].radius));
976 if (isfinite(radrat)) {
977 radrat = (radrat + 1) / 2;
978 }
979 else {
980 /* Happens when skin is scaled to zero. */
981 radrat = 1.0f;
982 }
983
984 /* Add vertices and edge segments */
985 for (j = 0; j < edge_subd[i]; j++, v++) {
986 float r = (j + 1) / float(edge_subd[i] + 1);
987 float t = powf(r, radrat);
988
989 /* Interpolate vertex coord */
991 out_vert_positions[v], out_vert_positions[edge[0]], out_vert_positions[edge[1]], t);
992
993 /* Interpolate skin radii */
994 interp_v3_v3v3(outnode[v].radius, orignode[edge[0]].radius, orignode[edge[1]].radius, t);
995
996 /* Interpolate vertex group weights */
997 for (k = 0; k < vgroups_num; k++) {
998 float weight;
999
1000 vg = &vgroups[k];
1001 weight = interpf(vg->w2, vg->w1, t);
1002
1003 if (weight > 0) {
1004 BKE_defvert_add_index_notest(&outdvert[v], vg->def_nr, weight);
1005 }
1006 }
1007
1008 result_edges[result_edge_i][0] = u;
1009 result_edges[result_edge_i][1] = v;
1010 result_edge_i++;
1011 u = v;
1012 }
1013
1014 if (vgroups) {
1015 MEM_freeN(vgroups);
1016 }
1017
1018 /* Link up to final vertex */
1019 result_edges[result_edge_i][0] = u;
1020 result_edges[result_edge_i][1] = edge[1];
1021 result_edge_i++;
1022 }
1023
1024 return result;
1025}
1026
1027/******************************* Output *******************************/
1028
1029/* Can be either quad or triangle */
1030static void add_poly(SkinOutput *so, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4)
1031{
1032 BMVert *verts[4] = {v1, v2, v3, v4};
1033 BMFace *f;
1034
1035 BLI_assert(!ELEM(v1, v2, v3, v4));
1036 BLI_assert(!ELEM(v2, v3, v4));
1037 BLI_assert(v3 != v4);
1038 BLI_assert(v1 && v2 && v3);
1039
1040 f = BM_face_create_verts(so->bm, verts, v4 ? 4 : 3, nullptr, BM_CREATE_NO_DOUBLE, true);
1042 if (so->smd->flag & MOD_SKIN_SMOOTH_SHADING) {
1044 }
1045 f->mat_nr = so->mat_nr;
1046}
1047
1048static void connect_frames(SkinOutput *so, BMVert *frame1[4], BMVert *frame2[4])
1049{
1050 BMVert *q[4][4] = {
1051 {frame2[0], frame2[1], frame1[1], frame1[0]},
1052 {frame2[1], frame2[2], frame1[2], frame1[1]},
1053 {frame2[2], frame2[3], frame1[3], frame1[2]},
1054 {frame2[3], frame2[0], frame1[0], frame1[3]},
1055 };
1056 int i;
1057 bool swap;
1058
1059 /* Check if frame normals need swap */
1060#if 0
1061 {
1062 /* simple method, works mostly */
1063 float p[3], no[3];
1064 sub_v3_v3v3(p, q[3][0]->co, q[0][0]->co);
1065 normal_quad_v3(no, q[0][0]->co, q[0][1]->co, q[0][2]->co, q[0][3]->co);
1066 swap = dot_v3v3(no, p) > 0;
1067 }
1068#else
1069 {
1070 /* comprehensive method, accumulate flipping of all faces */
1071 float cent_sides[4][3];
1072 float cent[3];
1073 float dot = 0.0f;
1074
1075 for (i = 0; i < 4; i++) {
1076 mid_v3_v3v3v3v3(cent_sides[i], UNPACK4_EX(, q[i], ->co));
1077 }
1078 mid_v3_v3v3v3v3(cent, UNPACK4(cent_sides));
1079
1080 for (i = 0; i < 4; i++) {
1081 float p[3], no[3];
1082 normal_quad_v3(no, UNPACK4_EX(, q[i], ->co));
1083 sub_v3_v3v3(p, cent, cent_sides[i]);
1084 dot += dot_v3v3(no, p);
1085 }
1086
1087 swap = dot > 0;
1088 }
1089#endif
1090
1091 for (i = 0; i < 4; i++) {
1092 if (swap) {
1093 add_poly(so, q[i][3], q[i][2], q[i][1], q[i][0]);
1094 }
1095 else {
1096 add_poly(so, q[i][0], q[i][1], q[i][2], q[i][3]);
1097 }
1098 }
1099}
1100
1101static void output_frames(BMesh *bm, SkinNode *sn, const MDeformVert *input_dvert)
1102{
1103 Frame *f;
1104 int i, j;
1105
1106 /* Output all frame verts */
1107 for (i = 0; i < sn->totframe; i++) {
1108 f = &sn->frames[i];
1109 for (j = 0; j < 4; j++) {
1110 if (!f->merge[j].frame) {
1111 BMVert *v = f->verts[j] = BM_vert_create(bm, f->co[j], nullptr, BM_CREATE_NOP);
1112
1113 if (input_dvert) {
1114 MDeformVert *dv = static_cast<MDeformVert *>(
1116
1117 BLI_assert(dv->totweight == 0);
1118 BKE_defvert_copy(dv, input_dvert);
1119 }
1120 }
1121 }
1122 }
1123}
1124
1125#define PRINT_HOLE_INFO 0
1126
1127static void calc_frame_center(float center[3], const Frame *frame)
1128{
1129 add_v3_v3v3(center, frame->verts[0]->co, frame->verts[1]->co);
1130 add_v3_v3(center, frame->verts[2]->co);
1131 add_v3_v3(center, frame->verts[3]->co);
1132 mul_v3_fl(center, 0.25f);
1133}
1134
1135/* Does crappy fan triangulation of face, may not be so accurate for
1136 * concave faces */
1137static int isect_ray_poly(const float ray_start[3],
1138 const float ray_dir[3],
1139 BMFace *f,
1140 float *r_lambda)
1141{
1142 BMVert *v, *v_first = nullptr, *v_prev = nullptr;
1143 BMIter iter;
1144 float best_dist = FLT_MAX;
1145 bool hit = false;
1146
1147 BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
1148 if (!v_first) {
1149 v_first = v;
1150 }
1151 else if (v_prev != v_first) {
1152 float dist;
1153 bool curhit;
1154
1155 curhit = isect_ray_tri_v3(
1156 ray_start, ray_dir, v_first->co, v_prev->co, v->co, &dist, nullptr);
1157 if (curhit && dist < best_dist) {
1158 hit = true;
1159 best_dist = dist;
1160 }
1161 }
1162
1163 v_prev = v;
1164 }
1165
1166 *r_lambda = best_dist;
1167 return hit;
1168}
1169
1170/* Reduce the face down to 'n' corners by collapsing the edges;
1171 * returns the new face.
1172 *
1173 * The orig_verts should contain the vertices of 'f'
1174 */
1175static BMFace *collapse_face_corners(BMesh *bm, BMFace *f, int n, BMVert **orig_verts)
1176{
1177 int orig_len = f->len;
1178
1179 BLI_assert(n >= 3);
1180 BLI_assert(f->len > n);
1181 if (f->len <= n) {
1182 return f;
1183 }
1184
1185 /* Collapse shortest edge for now */
1186 while (f->len > n) {
1187 BMFace *vf;
1188 BMEdge *shortest_edge;
1189 BMVert *v_safe, *v_merge;
1190 BMOperator op;
1191 BMIter iter;
1192 int i;
1193 BMOpSlot *slot_targetmap;
1194
1195 shortest_edge = BM_face_find_shortest_loop(f)->e;
1196 BMO_op_initf(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "weld_verts");
1197
1198 slot_targetmap = BMO_slot_get(op.slots_in, "targetmap");
1199
1200 /* NOTE: could probably calculate merges in one go to be
1201 * faster */
1202
1203 v_safe = shortest_edge->v1;
1204 v_merge = shortest_edge->v2;
1205 mid_v3_v3v3(v_safe->co, v_safe->co, v_merge->co);
1206 BMO_slot_map_elem_insert(&op, slot_targetmap, v_merge, v_safe);
1207 BMO_op_exec(bm, &op);
1208 BMO_op_finish(bm, &op);
1209
1210 /* Find the new face */
1211 f = nullptr;
1212 BM_ITER_ELEM (vf, &iter, v_safe, BM_FACES_OF_VERT) {
1213 bool wrong_face = false;
1214
1215 for (i = 0; i < orig_len; i++) {
1216 if (orig_verts[i] == v_merge) {
1217 orig_verts[i] = nullptr;
1218 }
1219 else if (orig_verts[i] && !BM_vert_in_face(orig_verts[i], vf)) {
1220 wrong_face = true;
1221 break;
1222 }
1223 }
1224
1225 if (!wrong_face) {
1226 f = vf;
1227 break;
1228 }
1229 }
1230
1231 BLI_assert(f);
1232 }
1233
1234 return f;
1235}
1236
1237/* Choose a good face to merge the frame with, used in case the frame
1238 * is completely inside the hull. */
1240{
1241 BMFace *f, *isect_target_face, *center_target_face;
1242 BMIter iter;
1243 float frame_center[3];
1244 float frame_normal[3];
1245 float best_isect_dist = FLT_MAX;
1246 float best_center_dist = FLT_MAX;
1247
1248 calc_frame_center(frame_center, frame);
1249 normal_quad_v3(frame_normal,
1250 frame->verts[3]->co,
1251 frame->verts[2]->co,
1252 frame->verts[1]->co,
1253 frame->verts[0]->co);
1254
1255 /* Use a line intersection test and nearest center test against
1256 * all faces */
1257 isect_target_face = center_target_face = nullptr;
1258 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1259 float dist, poly_center[3];
1260 int hit;
1261
1262 /* Intersection test */
1263 hit = isect_ray_poly(frame_center, frame_normal, f, &dist);
1264 if (hit && dist < best_isect_dist) {
1265 isect_target_face = f;
1266 best_isect_dist = dist;
1267 }
1268
1269 /* Nearest test */
1270 BM_face_calc_center_median(f, poly_center);
1271 dist = len_v3v3(frame_center, poly_center);
1272 if (dist < best_center_dist) {
1273 center_target_face = f;
1274 best_center_dist = dist;
1275 }
1276 }
1277
1278 f = isect_target_face;
1279 if (!f || best_center_dist < best_isect_dist / 2) {
1280 f = center_target_face;
1281 }
1282
1283 /* This case is unlikely now, but could still happen. Should look
1284 * into splitting edges to make new faces. */
1285#if PRINT_HOLE_INFO
1286 if (!f) {
1287 printf("no good face found\n");
1288 }
1289#endif
1290
1291 return f;
1292}
1293
1294/* Use edge-length heuristic to choose from eight possible face bridges */
1295static void skin_choose_quad_bridge_order(BMVert *a[4], BMVert *b[4], int best_order[4])
1296{
1297 int orders[8][4];
1298 float shortest_len;
1299 int i, j;
1300
1301 /* Enumerate all valid orderings */
1302 for (i = 0; i < 4; i++) {
1303 for (j = 0; j < 4; j++) {
1304 orders[i][j] = (j + i) % 4;
1305 orders[i + 4][j] = 3 - ((j + i) % 4);
1306 }
1307 }
1308
1309 shortest_len = FLT_MAX;
1310 for (i = 0; i < 8; i++) {
1311 float len = 0;
1312
1313 /* Get total edge length for this configuration */
1314 for (j = 0; j < 4; j++) {
1315 len += len_squared_v3v3(a[j]->co, b[orders[i][j]]->co);
1316 }
1317
1318 if (len < shortest_len) {
1319 shortest_len = len;
1320 memcpy(best_order, orders[i], sizeof(int[4]));
1321 }
1322 }
1323}
1324
1325static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_face)
1326{
1327 BMFace *f;
1328 BMVert *verts[4];
1329 BMOIter oiter;
1330 BMOperator op;
1331 int i, best_order[4];
1332 BMOpSlot *slot_targetmap;
1333
1334 BLI_assert(split_face->len >= 3);
1335
1336 /* Extrude the split face */
1338 BM_elem_flag_enable(split_face, BM_ELEM_TAG);
1340 &op,
1342 "extrude_discrete_faces faces=%hf",
1343 BM_ELEM_TAG);
1344 BMO_op_exec(bm, &op);
1345
1346 /* Update split face (should only be one new face created
1347 * during extrusion) */
1348 split_face = nullptr;
1349 BMO_ITER (f, &oiter, op.slots_out, "faces.out", BM_FACE) {
1350 BLI_assert(!split_face);
1351 split_face = f;
1352 }
1353
1354 BMO_op_finish(bm, &op);
1355
1357
1358 if (split_face->len == 3) {
1359 BMEdge *longest_edge;
1360
1361 /* Need at least four ring edges, so subdivide longest edge if
1362 * face is a triangle */
1363 longest_edge = BM_face_find_longest_loop(split_face)->e;
1364
1366 BM_elem_flag_enable(longest_edge, BM_ELEM_TAG);
1367
1370 "subdivide_edges edges=%he cuts=%i quad_corner_type=%i",
1372 1,
1374 }
1375 else if (split_face->len > 4) {
1376 /* Maintain a dynamic vert array containing the split_face's
1377 * vertices, avoids frequent allocations in #collapse_face_corners(). */
1378 vert_buf.reinitialize(split_face->len);
1379
1380 /* Get split face's verts */
1381 BM_iter_as_array(bm, BM_VERTS_OF_FACE, split_face, (void **)vert_buf.data(), split_face->len);
1382
1383 /* Earlier edge split operations may have turned some quads
1384 * into higher-degree faces */
1385 split_face = collapse_face_corners(bm, split_face, 4, vert_buf.data());
1386 }
1387
1388 /* `split_face` should now be a quad. */
1389 BLI_assert(split_face->len == 4);
1390
1391 /* Account for the highly unlikely case that it's not a quad. */
1392 if (split_face->len != 4) {
1393 /* Reuse `vert_buf` for updating normals. */
1394 vert_buf.reinitialize(split_face->len);
1395 BM_iter_as_array(bm, BM_FACES_OF_VERT, split_face, (void **)vert_buf.data(), split_face->len);
1396
1397 vert_array_face_normal_update(vert_buf.data(), split_face->len);
1398 return;
1399 }
1400
1401 /* Get split face's verts */
1402 // BM_iter_as_array(bm, BM_VERTS_OF_FACE, split_face, (void **)verts, 4);
1403 BM_face_as_array_vert_quad(split_face, verts);
1404 skin_choose_quad_bridge_order(verts, frame->verts, best_order);
1405
1406 /* Delete split face and merge */
1407 BM_face_kill(bm, split_face);
1408 BMO_op_init(bm, &op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), "weld_verts");
1409 slot_targetmap = BMO_slot_get(op.slots_in, "targetmap");
1410 for (i = 0; i < 4; i++) {
1411 BMO_slot_map_elem_insert(&op, slot_targetmap, verts[i], frame->verts[best_order[i]]);
1412 }
1413 BMO_op_exec(bm, &op);
1414 BMO_op_finish(bm, &op);
1415
1417}
1418
1419/* If the frame has some vertices that are inside the hull (detached)
1420 * and some attached, duplicate the attached vertices and take the
1421 * whole frame off the hull. */
1423{
1424 int i, attached[4], totattached = 0;
1425
1426 /* Get/count attached frame corners */
1427 for (i = 0; i < 4; i++) {
1428 if (!frame->inside_hull[i]) {
1429 attached[totattached++] = i;
1430 }
1431 }
1432
1433 /* Detach everything */
1434 for (i = 0; i < totattached; i++) {
1435 BMVert **av = &frame->verts[attached[i]];
1436 (*av) = BM_vert_create(bm, (*av)->co, *av, BM_CREATE_NOP);
1437 }
1438}
1439
1440static void quad_from_tris(BMEdge *e, BMFace *adj[2], BMVert *ndx[4])
1441{
1442 BMVert *tri[2][3];
1443 BMVert *opp = nullptr;
1444 int i, j;
1445
1446 BLI_assert(adj[0]->len == 3 && adj[1]->len == 3);
1447
1448#if 0
1449 BM_iter_as_array(bm, BM_VERTS_OF_FACE, adj[0], (void **)tri[0], 3);
1450 BM_iter_as_array(bm, BM_VERTS_OF_FACE, adj[1], (void **)tri[1], 3);
1451#else
1452 BM_face_as_array_vert_tri(adj[0], tri[0]);
1453 BM_face_as_array_vert_tri(adj[1], tri[1]);
1454#endif
1455
1456 /* Find what the second tri has that the first doesn't */
1457 for (i = 0; i < 3; i++) {
1458 if (!ELEM(tri[1][i], tri[0][0], tri[0][1], tri[0][2])) {
1459 opp = tri[1][i];
1460 break;
1461 }
1462 }
1463 BLI_assert(opp);
1464
1465 for (i = 0, j = 0; i < 3; i++, j++) {
1466 ndx[j] = tri[0][i];
1467 /* When the triangle edge cuts across our quad-to-be,
1468 * throw in the second triangle's vertex */
1469 if (ELEM(tri[0][i], e->v1, e->v2) &&
1470 (tri[0][(i + 1) % 3] == e->v1 || tri[0][(i + 1) % 3] == e->v2))
1471 {
1472 j++;
1473 ndx[j] = opp;
1474 }
1475 }
1476}
1477
1478static void add_quad_from_tris(SkinOutput *so, BMEdge *e, BMFace *adj[2])
1479{
1480 BMVert *quad[4];
1481
1482 quad_from_tris(e, adj, quad);
1483
1484 add_poly(so, quad[0], quad[1], quad[2], quad[3]);
1485}
1486
1488{
1489 BMIter iter;
1490 BMEdge *e;
1491 HeapSimple *heap;
1492 float score;
1493
1494 heap = BLI_heapsimple_new();
1495
1497
1498 /* Build heap */
1499 BM_ITER_MESH (e, &iter, so->bm, BM_EDGES_OF_MESH) {
1500 BMFace *adj[2];
1501
1502 /* Only care if the edge is used by exactly two triangles */
1503 if (BM_edge_face_pair(e, &adj[0], &adj[1])) {
1504 if (adj[0]->len == 3 && adj[1]->len == 3) {
1505 BMVert *quad[4];
1506
1509
1510 /* Construct quad using the two triangles adjacent to
1511 * the edge */
1512 quad_from_tris(e, adj, quad);
1513
1514 /* Calculate a score for the quad, higher score for
1515 * triangles being closer to coplanar */
1516 score = ((BM_face_calc_area(adj[0]) + BM_face_calc_area(adj[1])) *
1517 dot_v3v3(adj[0]->no, adj[1]->no));
1518
1519 /* Check if quad crosses the axis of symmetry */
1521 /* Increase score if the triangles form a
1522 * symmetric quad, otherwise don't use it */
1523 if (is_quad_symmetric(quad, smd)) {
1524 score *= 10;
1525 }
1526 else {
1527 continue;
1528 }
1529 }
1530
1531 /* Don't use the quad if it's concave */
1532 if (!is_quad_convex_v3(quad[0]->co, quad[1]->co, quad[2]->co, quad[3]->co)) {
1533 continue;
1534 }
1535
1536 BLI_heapsimple_insert(heap, -score, e);
1537 }
1538 }
1539 }
1540
1541 while (!BLI_heapsimple_is_empty(heap)) {
1542 BMFace *adj[2];
1543
1544 e = static_cast<BMEdge *>(BLI_heapsimple_pop_min(heap));
1545
1546 if (BM_edge_face_pair(e, &adj[0], &adj[1])) {
1547 /* If both triangles still free, and if they don't already
1548 * share a border with another face, output as a quad */
1549 if (!BM_elem_flag_test(adj[0], BM_ELEM_TAG) && !BM_elem_flag_test(adj[1], BM_ELEM_TAG) &&
1550 !BM_face_share_face_check(adj[0], adj[1]))
1551 {
1552 add_quad_from_tris(so, e, adj);
1556 }
1557 }
1558 }
1559
1560 BLI_heapsimple_free(heap, nullptr);
1561
1563}
1564
1566 int verts_num,
1568 const blender::Span<blender::int2> edges)
1569{
1570 Frame **hull_frames;
1571 int v, tothullframe;
1572
1573 for (v = 0; v < verts_num; v++) {
1574 /* Only check branch nodes */
1575 if (!skin_nodes[v].totframe) {
1576 hull_frames = collect_hull_frames(v, skin_nodes, emap, edges, &tothullframe);
1577 merge_frame_corners(hull_frames, tothullframe);
1578 MEM_freeN(hull_frames);
1579 }
1580 }
1581}
1582
1583static void skin_update_merged_vertices(SkinNode *skin_nodes, int verts_num)
1584{
1585 int v;
1586
1587 for (v = 0; v < verts_num; v++) {
1588 SkinNode *sn = &skin_nodes[v];
1589 int i, j;
1590
1591 for (i = 0; i < sn->totframe; i++) {
1592 Frame *f = &sn->frames[i];
1593
1594 for (j = 0; j < 4; j++) {
1595 if (f->merge[j].frame) {
1596 /* Merge chaining not allowed */
1597 BLI_assert(!f->merge[j].frame->merge[f->merge[j].corner].frame);
1598
1599 f->verts[j] = f->merge[j].frame->verts[f->merge[j].corner];
1600 }
1601 }
1602 }
1603 }
1604}
1605
1606static void skin_fix_hull_topology(BMesh *bm, SkinNode *skin_nodes, int verts_num)
1607{
1608 int v;
1609
1610 for (v = 0; v < verts_num; v++) {
1611 SkinNode *sn = &skin_nodes[v];
1612 int j;
1613
1614 for (j = 0; j < sn->totframe; j++) {
1615 Frame *f = &sn->frames[j];
1616
1617 if (f->detached) {
1618 BMFace *target_face;
1619
1621
1622 target_face = skin_hole_target_face(bm, f);
1623 if (target_face) {
1624 skin_fix_hole_no_good_verts(bm, f, target_face);
1625 }
1626 }
1627 }
1628 }
1629}
1630
1631static void skin_output_end_nodes(SkinOutput *so, SkinNode *skin_nodes, int verts_num)
1632{
1633 int v;
1634
1635 for (v = 0; v < verts_num; v++) {
1636 SkinNode *sn = &skin_nodes[v];
1637 /* Assuming here just two frames */
1638 if (sn->flag & SEAM_FRAME) {
1639 BMVert *v_order[4];
1640 int i, order[4];
1641
1642 skin_choose_quad_bridge_order(sn->frames[0].verts, sn->frames[1].verts, order);
1643 for (i = 0; i < 4; i++) {
1644 v_order[i] = sn->frames[1].verts[order[i]];
1645 }
1646 connect_frames(so, sn->frames[0].verts, v_order);
1647 }
1648 else if (sn->totframe == 2) {
1649 connect_frames(so, sn->frames[0].verts, sn->frames[1].verts);
1650 }
1651
1652 if (sn->flag & CAP_START) {
1653 if (sn->flag & FLIP_NORMAL) {
1654 add_poly(so,
1655 sn->frames[0].verts[0],
1656 sn->frames[0].verts[1],
1657 sn->frames[0].verts[2],
1658 sn->frames[0].verts[3]);
1659 }
1660 else {
1661 add_poly(so,
1662 sn->frames[0].verts[3],
1663 sn->frames[0].verts[2],
1664 sn->frames[0].verts[1],
1665 sn->frames[0].verts[0]);
1666 }
1667 }
1668 if (sn->flag & CAP_END) {
1669 add_poly(so,
1670 sn->frames[1].verts[0],
1671 sn->frames[1].verts[1],
1672 sn->frames[1].verts[2],
1673 sn->frames[1].verts[3]);
1674 }
1675 }
1676}
1677
1679 SkinNode *skin_nodes,
1680 const blender::Span<blender::int2> edges)
1681{
1682 for (const int e : edges.index_range()) {
1683 SkinNode *a, *b;
1684 a = &skin_nodes[edges[e][0]];
1685 b = &skin_nodes[edges[e][1]];
1686
1687 if (a->totframe && b->totframe) {
1688 if ((a->flag & SEAM_FRAME) || (b->flag & SEAM_FRAME)) {
1689 Frame *fr[2] = {&a->frames[0], &b->frames[0]};
1690 BMVert *v_order[4];
1691 int i, order[4];
1692
1693 if ((a->flag & SEAM_FRAME) && (e != a->seam_edges[0])) {
1694 fr[0]++;
1695 }
1696 if ((b->flag & SEAM_FRAME) && (e != b->seam_edges[0])) {
1697 fr[1]++;
1698 }
1699
1700 skin_choose_quad_bridge_order(fr[0]->verts, fr[1]->verts, order);
1701 for (i = 0; i < 4; i++) {
1702 v_order[i] = fr[1]->verts[order[i]];
1703 }
1704 connect_frames(so, fr[0]->verts, v_order);
1705 }
1706 else {
1707 connect_frames(so, a->frames[0].verts, b->frames[0].verts);
1708 }
1709 }
1710 }
1711}
1712
1714 SkinNode *skin_nodes,
1715 int verts_num,
1716 const SkinModifierData *smd)
1717{
1718 BMIter iter, eiter;
1719 BMVert *v;
1720 int i, j, k, skey;
1721
1722 if (smd->branch_smoothing == 0) {
1723 return;
1724 }
1725
1726 /* Mark all frame vertices */
1728 for (i = 0; i < verts_num; i++) {
1729 for (j = 0; j < skin_nodes[i].totframe; j++) {
1730 Frame *frame = &skin_nodes[i].frames[j];
1731
1732 for (k = 0; k < 4; k++) {
1734 }
1735 }
1736 }
1737
1738 /* Add temporary shape-key layer to store original coordinates. */
1741 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
1742 copy_v3_v3(
1743 static_cast<float *>(CustomData_bmesh_get_n(&bm->vdata, v->head.data, CD_SHAPEKEY, skey)),
1744 v->co);
1745 }
1746
1747 /* Smooth vertices, weight unmarked vertices more strongly (helps
1748 * to smooth frame vertices, but don't want to alter them too
1749 * much) */
1750 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
1751 BMEdge *e;
1752 float avg[3];
1753 float weight = smd->branch_smoothing;
1754 int totv = 1;
1755
1757 weight *= 0.5f;
1758 }
1759
1760 copy_v3_v3(avg, v->co);
1761 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1762 BMVert *other = BM_edge_other_vert(e, v);
1763
1764 add_v3_v3(avg,
1765 static_cast<float *>(
1766 CustomData_bmesh_get_n(&bm->vdata, other->head.data, CD_SHAPEKEY, skey)));
1767 totv++;
1768 }
1769
1770 if (totv > 1) {
1771 mul_v3_fl(avg, 1.0f / float(totv));
1772 interp_v3_v3v3(v->co, v->co, avg, weight);
1773 }
1774 }
1775
1776 /* Done with original coordinates */
1778
1779 BMFace *f;
1780 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1782 }
1783}
1784
1785/* Returns true if all hulls are successfully built, false otherwise */
1787 SkinNode *skin_nodes,
1788 int verts_num,
1790 const blender::Span<blender::int2> edges)
1791{
1792 bool result = true;
1793 int v;
1794
1795 for (v = 0; v < verts_num; v++) {
1796 SkinNode *sn = &skin_nodes[v];
1797
1798 /* Branch node hulls */
1799 if (!sn->totframe) {
1800 Frame **hull_frames;
1801 int tothullframe;
1802
1803 hull_frames = collect_hull_frames(v, skin_nodes, emap, edges, &tothullframe);
1804 if (!build_hull(so, hull_frames, tothullframe)) {
1805 result = false;
1806 }
1807
1808 MEM_freeN(hull_frames);
1809 }
1810 }
1811
1812 return result;
1813}
1814
1820
1821static BMesh *build_skin(SkinNode *skin_nodes,
1822 int verts_num,
1824 const blender::Span<blender::int2> edges,
1825 const MDeformVert *input_dvert,
1826 SkinModifierData *smd,
1827 eSkinErrorFlag *r_error)
1828{
1829 SkinOutput so;
1830 int v;
1831
1832 so.smd = smd;
1833 BMeshCreateParams create_params{};
1834 create_params.use_toolflags = true;
1835 so.bm = BM_mesh_create(&bm_mesh_allocsize_default, &create_params);
1836 so.mat_nr = 0;
1837
1838 /* BMESH_TODO: bumping up the stack level (see MOD_array.cc) */
1840 BMO_push(so.bm, nullptr);
1841 bmesh_edit_begin(so.bm, BMOpTypeFlag(0));
1842
1843 if (input_dvert) {
1844 BM_data_layer_add(so.bm, &so.bm->vdata, CD_MDEFORMVERT);
1845 }
1846
1847 /* Check for mergeable frame corners around hulls before
1848 * outputting vertices */
1849 skin_merge_close_frame_verts(skin_nodes, verts_num, emap, edges);
1850
1851 /* Write out all frame vertices to the mesh */
1852 for (v = 0; v < verts_num; v++) {
1853 if (skin_nodes[v].totframe) {
1854 output_frames(so.bm, &skin_nodes[v], input_dvert ? &input_dvert[v] : nullptr);
1855 }
1856 }
1857
1858 /* Update vertex pointers for merged frame corners */
1859 skin_update_merged_vertices(skin_nodes, verts_num);
1860
1861 if (!skin_output_branch_hulls(&so, skin_nodes, verts_num, emap, edges)) {
1862 *r_error |= SKIN_ERROR_HULL;
1863 }
1864
1865 /* Merge triangles here in the hope of providing better target
1866 * faces for skin_fix_hull_topology() to connect to */
1867 hull_merge_triangles(&so, smd);
1868
1869 /* Using convex hulls may not generate a nice manifold mesh. Two
1870 * problems can occur: an input frame's edges may be inside the
1871 * hull, and/or an input frame's vertices may be inside the hull.
1872 *
1873 * General fix to produce manifold mesh: for any frame that is
1874 * partially detached, first detach it fully, then find a suitable
1875 * existing face to merge with. (Note that we do this after
1876 * creating all hull faces, but before creating any other
1877 * faces.
1878 */
1879 skin_fix_hull_topology(so.bm, skin_nodes, verts_num);
1880
1881 skin_smooth_hulls(so.bm, skin_nodes, verts_num, smd);
1882
1883 skin_output_end_nodes(&so, skin_nodes, verts_num);
1884 skin_output_connections(&so, skin_nodes, edges);
1885 hull_merge_triangles(&so, smd);
1886
1887 bmesh_edit_end(so.bm, BMOpTypeFlag(0));
1888 BMO_pop(so.bm);
1889
1890 return so.bm;
1891}
1892
1893static void skin_set_orig_indices(Mesh *mesh)
1894{
1895 int *orig = static_cast<int *>(
1896 CustomData_add_layer(&mesh->face_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh->faces_num));
1897 copy_vn_i(orig, mesh->faces_num, ORIGINDEX_NONE);
1898}
1899
1900/*
1901 * 0) Subdivide edges (in caller)
1902 * 1) Generate good edge matrices (uses root nodes)
1903 * 2) Generate node frames
1904 * 3) Output vertices and polygons from frames, connections, and hulls
1905 */
1906static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd, eSkinErrorFlag *r_error)
1907{
1908 Mesh *result;
1909 BMesh *bm;
1910 EMat *emat;
1911 SkinNode *skin_nodes;
1912 bool has_valid_root = false;
1913
1914 const MVertSkin *nodes = static_cast<const MVertSkin *>(
1916
1917 const blender::Span<blender::float3> vert_positions = origmesh->vert_positions();
1918 const blender::Span<blender::int2> edges = origmesh->edges();
1919 const MDeformVert *dvert = origmesh->deform_verts().data();
1920 const int verts_num = origmesh->verts_num;
1921
1922 blender::Array<int> vert_to_edge_offsets;
1923 blender::Array<int> vert_to_edge_indices;
1925 edges, verts_num, vert_to_edge_offsets, vert_to_edge_indices);
1926
1927 emat = build_edge_mats(nodes, vert_positions, verts_num, edges, vert_to_edge, &has_valid_root);
1928 skin_nodes = build_frames(vert_positions, verts_num, nodes, vert_to_edge, emat);
1929 MEM_freeN(emat);
1930 emat = nullptr;
1931
1932 bm = build_skin(skin_nodes, verts_num, vert_to_edge, edges, dvert, smd, r_error);
1933
1934 MEM_freeN(skin_nodes);
1935
1936 if (!has_valid_root) {
1937 *r_error |= SKIN_ERROR_NO_VALID_ROOT;
1938 }
1939
1940 if (!bm) {
1941 return nullptr;
1942 }
1943
1944 result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, origmesh);
1946
1947 skin_set_orig_indices(result);
1948
1949 return result;
1950}
1951
1953{
1954 Mesh *result;
1955
1956 /* Skin node layer is required */
1957 if (!CustomData_get_layer(&mesh->vert_data, CD_MVERT_SKIN)) {
1958 return mesh;
1959 }
1960
1961 mesh = subdivide_base(mesh);
1962 result = base_skin(mesh, smd, r_error);
1963
1964 BKE_id_free(nullptr, mesh);
1965 return result;
1966}
1967
1968/**************************** Skin Modifier ***************************/
1969
1970static void init_data(ModifierData *md)
1971{
1973
1975
1977
1978 /* Enable in editmode by default. */
1980}
1981
1983{
1985 Mesh *result = final_skin((SkinModifierData *)md, mesh, &error);
1986
1988 error &= ~SKIN_ERROR_NO_VALID_ROOT;
1990 ctx->object,
1991 md,
1992 "No valid root vertex found (you need one per mesh island you want to skin)");
1993 }
1994 if (error & SKIN_ERROR_HULL) {
1995 error &= ~SKIN_ERROR_HULL;
1996 BKE_modifier_set_error(ctx->object, md, "Hull error");
1997 }
1998 BLI_assert(error == 0);
1999
2000 if (result == nullptr) {
2001 return mesh;
2002 }
2003 return result;
2004}
2005
2006static void required_data_mask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
2007{
2008 r_cddata_masks->vmask |= CD_MASK_MVERT_SKIN | CD_MASK_MDEFORMVERT;
2009}
2010
2011static void panel_draw(const bContext * /*C*/, Panel *panel)
2012{
2013 uiLayout *row;
2014 uiLayout *layout = panel->layout;
2016
2017 PointerRNA ob_ptr;
2019
2020 PointerRNA op_ptr;
2021
2022 uiLayoutSetPropSep(layout, true);
2023
2024 uiItemR(layout, ptr, "branch_smoothing", UI_ITEM_NONE, nullptr, ICON_NONE);
2025
2026 row = uiLayoutRowWithHeading(layout, true, IFACE_("Symmetry"));
2027 uiItemR(row, ptr, "use_x_symmetry", toggles_flag, nullptr, ICON_NONE);
2028 uiItemR(row, ptr, "use_y_symmetry", toggles_flag, nullptr, ICON_NONE);
2029 uiItemR(row, ptr, "use_z_symmetry", toggles_flag, nullptr, ICON_NONE);
2030
2031 uiItemR(layout, ptr, "use_smooth_shade", UI_ITEM_NONE, nullptr, ICON_NONE);
2032
2033 row = uiLayoutRow(layout, false);
2034 uiItemO(row, IFACE_("Create Armature"), ICON_NONE, "OBJECT_OT_skin_armature_create");
2035 uiItemO(row, nullptr, ICON_NONE, "MESH_OT_customdata_skin_add");
2036
2037 row = uiLayoutRow(layout, false);
2038 uiItemFullO(row,
2039 "OBJECT_OT_skin_loose_mark_clear",
2040 IFACE_("Mark Loose"),
2041 ICON_NONE,
2042 nullptr,
2045 &op_ptr);
2046 RNA_enum_set(&op_ptr, "action", 0); /* SKIN_LOOSE_MARK */
2047 uiItemFullO(row,
2048 "OBJECT_OT_skin_loose_mark_clear",
2049 IFACE_("Clear Loose"),
2050 ICON_NONE,
2051 nullptr,
2054 &op_ptr);
2055 RNA_enum_set(&op_ptr, "action", 1); /* SKIN_LOOSE_CLEAR */
2056
2057 uiItemO(layout, IFACE_("Mark Root"), ICON_NONE, "OBJECT_OT_skin_root_mark");
2058 uiItemO(layout, IFACE_("Equalize Radii"), ICON_NONE, "OBJECT_OT_skin_radii_equalize");
2059
2060 modifier_panel_end(layout, ptr);
2061}
2062
2063static void panel_register(ARegionType *region_type)
2064{
2066}
2067
2069 /*idname*/ "Skin",
2070 /*name*/ N_("Skin"),
2071 /*struct_name*/ "SkinModifierData",
2072 /*struct_size*/ sizeof(SkinModifierData),
2073 /*srna*/ &RNA_SkinModifier,
2076 /*icon*/ ICON_MOD_SKIN,
2077
2078 /*copy_data*/ BKE_modifier_copydata_generic,
2079
2080 /*deform_verts*/ nullptr,
2081 /*deform_matrices*/ nullptr,
2082 /*deform_verts_EM*/ nullptr,
2083 /*deform_matrices_EM*/ nullptr,
2084 /*modify_mesh*/ modify_mesh,
2085 /*modify_geometry_set*/ nullptr,
2086
2087 /*init_data*/ init_data,
2088 /*required_data_mask*/ required_data_mask,
2089 /*free_data*/ nullptr,
2090 /*is_disabled*/ nullptr,
2091 /*update_depsgraph*/ nullptr,
2092 /*depends_on_time*/ nullptr,
2093 /*depends_on_normals*/ nullptr,
2094 /*foreach_ID_link*/ nullptr,
2095 /*foreach_tex_link*/ nullptr,
2096 /*free_runtime_data*/ nullptr,
2097 /*panel_register*/ panel_register,
2098 /*blend_write*/ nullptr,
2099 /*blend_read*/ nullptr,
2100 /*foreach_cache*/ nullptr,
2101};
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
@ CD_CONSTRUCT
void * CustomData_bmesh_get_n(const CustomData *data, void *block, eCustomDataType type, int n)
void * CustomData_bmesh_get(const CustomData *data, void *block, eCustomDataType type)
#define ORIGINDEX_NONE
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
support for deformation groups and hooks.
void BKE_defvert_add_index_notest(MDeformVert *dv, int defgroup, float weight)
Definition deform.cc:846
void BKE_defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
Definition deform.cc:130
void BKE_id_free(Main *bmain, void *idv)
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
Mesh * BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:41
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:65
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
A min-heap / priority queue ADT.
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
void * BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1)
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
MINLINE float min_ff(float a, float b)
MINLINE float interpf(float target, float origin, float t)
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:56
bool isect_ray_tri_v3(const float ray_origin[3], const float ray_direction[3], const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2])
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void zero_m3(float m[3][3])
void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], float angle)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
void copy_vn_i(int *array_tar, int size, int val)
void mid_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)
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL()
Definition stack.c:137
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition stack.c:131
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:249
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.c:96
#define BLI_stack_new(esize, descr)
unsigned int uint
#define UNPACK4(a)
#define UNUSED_VARS(...)
#define ENUM_OPERATORS(_type, _max)
#define UNPACK4_EX(pre, a, post)
#define ELEM(...)
#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
#define CD_MASK_MVERT_SKIN
@ CD_MVERT_SKIN
@ CD_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
@ MVERT_SKIN_LOOSE
@ MVERT_SKIN_ROOT
@ eModifierMode_Editmode
struct SkinModifierData SkinModifierData
@ eModifierType_Skin
@ MOD_SKIN_SMOOTH_SHADING
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
Definition MOD_skin.cc:1970
static void skin_smooth_hulls(BMesh *bm, SkinNode *skin_nodes, int verts_num, const SkinModifierData *smd)
Definition MOD_skin.cc:1713
#define NUM_SUBDIVISIONS_MAX
static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd)
Definition MOD_skin.cc:1487
static SkinNode * build_frames(const blender::Span< blender::float3 > vert_positions, int verts_num, const MVertSkin *nodes, blender::GroupedSpan< int > emap, EMat *emat)
Definition MOD_skin.cc:658
static Mesh * subdivide_base(const Mesh *orig)
Definition MOD_skin.cc:895
static bool is_quad_symmetric(BMVert *quad[4], const SkinModifierData *smd)
Definition MOD_skin.cc:177
eSkinErrorFlag
Definition MOD_skin.cc:1815
@ SKIN_ERROR_HULL
Definition MOD_skin.cc:1817
@ SKIN_ERROR_NO_VALID_ROOT
Definition MOD_skin.cc:1816
static void create_frame(Frame *frame, const float co[3], const float radius[2], const float mat[3][3], float offset)
Definition MOD_skin.cc:496
ModifierTypeInfo modifierType_Skin
Definition MOD_skin.cc:2068
static void merge_frame_corners(Frame **frames, int totframe)
Definition MOD_skin.cc:389
static void panel_register(ARegionType *region_type)
Definition MOD_skin.cc:2063
static bool quad_crosses_symmetry_plane(BMVert *quad[4], const SkinModifierData *smd)
Definition MOD_skin.cc:211
static void connect_frames(SkinOutput *so, BMVert *frame1[4], BMVert *frame2[4])
Definition MOD_skin.cc:1048
static void calc_edge_mat(float mat[3][3], const float a[3], const float b[3])
Definition MOD_skin.cc:685
static void output_frames(BMesh *bm, SkinNode *sn, const MDeformVert *input_dvert)
Definition MOD_skin.cc:1101
static Frame ** collect_hull_frames(int v, SkinNode *frames, blender::GroupedSpan< int > emap, const blender::Span< blender::int2 > edges, int *tothullframe)
Definition MOD_skin.cc:453
static bool build_hull(SkinOutput *so, Frame **frames, int totframe)
Definition MOD_skin.cc:262
static void vert_face_normal_mark_update(BMVert *v)
Definition MOD_skin.cc:92
static void node_frames_init(SkinNode *nf, int totframe)
Definition MOD_skin.cc:483
static bool skin_output_branch_hulls(SkinOutput *so, SkinNode *skin_nodes, int verts_num, blender::GroupedSpan< int > emap, const blender::Span< blender::int2 > edges)
Definition MOD_skin.cc:1786
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
Definition MOD_skin.cc:2006
static BMesh * build_skin(SkinNode *skin_nodes, int verts_num, blender::GroupedSpan< int > emap, const blender::Span< blender::int2 > edges, const MDeformVert *input_dvert, SkinModifierData *smd, eSkinErrorFlag *r_error)
Definition MOD_skin.cc:1821
static void skin_output_connections(SkinOutput *so, SkinNode *skin_nodes, const blender::Span< blender::int2 > edges)
Definition MOD_skin.cc:1678
static void add_poly(SkinOutput *so, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4)
Definition MOD_skin.cc:1030
SkinNodeFlag
Definition MOD_skin.cc:126
@ CAP_END
Definition MOD_skin.cc:128
@ CAP_START
Definition MOD_skin.cc:127
@ SEAM_FRAME
Definition MOD_skin.cc:129
@ FLIP_NORMAL
Definition MOD_skin.cc:130
static void skin_set_orig_indices(Mesh *mesh)
Definition MOD_skin.cc:1893
static void end_node_frames(int v, SkinNode *skin_nodes, const blender::Span< blender::float3 > vert_positions, const MVertSkin *nodes, blender::GroupedSpan< int > emap, EMat *emat)
Definition MOD_skin.cc:528
static void connection_node_frames(int v, SkinNode *skin_nodes, const blender::Span< blender::float3 > vert_positions, const MVertSkin *nodes, blender::GroupedSpan< int > emap, EMat *emat)
Definition MOD_skin.cc:613
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_skin.cc:1982
static void skin_update_merged_vertices(SkinNode *skin_nodes, int verts_num)
Definition MOD_skin.cc:1583
static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_face)
Definition MOD_skin.cc:1325
static void skin_output_end_nodes(SkinOutput *so, SkinNode *skin_nodes, int verts_num)
Definition MOD_skin.cc:1631
static Mesh * base_skin(Mesh *origmesh, SkinModifierData *smd, eSkinErrorFlag *r_error)
Definition MOD_skin.cc:1906
static int connection_node_mat(float mat[3][3], int v, blender::GroupedSpan< int > emap, EMat *emat)
Definition MOD_skin.cc:580
static EMat * build_edge_mats(const MVertSkin *vs, const blender::Span< blender::float3 > vert_positions, const int verts_num, const blender::Span< blender::int2 > edges, blender::GroupedSpan< int > emap, bool *has_valid_root)
Definition MOD_skin.cc:776
static void vert_array_face_normal_update(BMVert **verts, int verts_len)
Definition MOD_skin.cc:106
static void add_quad_from_tris(SkinOutput *so, BMEdge *e, BMFace *adj[2])
Definition MOD_skin.cc:1478
static float half_v2(const float v[2])
Definition MOD_skin.cc:523
#define MAX_SKIN_NODE_FRAMES
Definition MOD_skin.cc:156
static int isect_ray_poly(const float ray_start[3], const float ray_dir[3], BMFace *f, float *r_lambda)
Definition MOD_skin.cc:1137
static Mesh * final_skin(SkinModifierData *smd, Mesh *mesh, eSkinErrorFlag *r_error)
Definition MOD_skin.cc:1952
static void skin_choose_quad_bridge_order(BMVert *a[4], BMVert *b[4], int best_order[4])
Definition MOD_skin.cc:1295
static int calc_edge_subdivisions(const blender::Span< blender::float3 > vert_positions, const MVertSkin *nodes, const blender::int2 &edge, const blender::Span< int > degree)
Definition MOD_skin.cc:838
static void panel_draw(const bContext *, Panel *panel)
Definition MOD_skin.cc:2011
static void calc_frame_center(float center[3], const Frame *frame)
Definition MOD_skin.cc:1127
static void build_emats_stack(BLI_Stack *stack, BLI_bitmap *visited_e, EMat *emat, blender::GroupedSpan< int > emap, const blender::Span< blender::int2 > edges, const MVertSkin *vs, const blender::Span< blender::float3 > vert_positions)
Definition MOD_skin.cc:720
static void skin_fix_hull_topology(BMesh *bm, SkinNode *skin_nodes, int verts_num)
Definition MOD_skin.cc:1606
static BMFace * skin_hole_target_face(BMesh *bm, Frame *frame)
Definition MOD_skin.cc:1239
static BMFace * collapse_face_corners(BMesh *bm, BMFace *f, int n, BMVert **orig_verts)
Definition MOD_skin.cc:1175
static void quad_from_tris(BMEdge *e, BMFace *adj[2], BMVert *ndx[4])
Definition MOD_skin.cc:1440
static void skin_merge_close_frame_verts(SkinNode *skin_nodes, int verts_num, blender::GroupedSpan< int > emap, const blender::Span< blender::int2 > edges)
Definition MOD_skin.cc:1565
static float frame_len(const Frame *frame)
Definition MOD_skin.cc:384
static void vert_face_normal_mark_set(BMVert *v)
Definition MOD_skin.cc:83
static void skin_hole_detach_partially_attached_frame(BMesh *bm, Frame *frame)
Definition MOD_skin.cc:1422
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
#define UI_ITEM_NONE
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
eUI_Item_Flag
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
#define BM_ALL_NOLOOP
@ BM_ELEM_SELECT
@ BM_ELEM_SMOOTH
@ BM_ELEM_TAG
void BM_face_kill(BMesh *bm, BMFace *f)
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition bmesh_core.cc:43
@ BM_CREATE_NOP
Definition bmesh_core.hh:24
@ BM_CREATE_NO_DOUBLE
Definition bmesh_core.hh:26
void BM_mesh_delete_hflag_tagged(BMesh *bm, const char hflag, const char htype)
@ BMO_ERROR_CANCEL
bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
Iterator as Array.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
const BMAllocTemplate bm_mesh_allocsize_default
Definition bmesh_mesh.cc:29
void bmesh_edit_begin(BMesh *, BMOpTypeFlag)
BMesh Begin Edit.
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
Definition bmesh_mesh.cc:81
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
BMesh End Edit.
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
#define BM_FACE
#define BM_EDGE
#define BM_VERT
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
void BMO_pop(BMesh *bm)
BMESH OPSTACK POP.
void BMO_push(BMesh *bm, BMOperator *op)
BMESH OPSTACK PUSH.
void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname)
BMESH OPSTACK INIT OP.
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
@ BMO_FLAG_RESPECT_HIDE
BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot, const void *element, void *val)
@ SUBD_CORNER_STRAIGHT_CUT
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4])
void BM_face_normal_update(BMFace *f)
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b)
BMLoop * BM_face_find_shortest_loop(BMFace *f)
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
bool BM_face_is_normal_valid(const BMFace *f)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
BMLoop * BM_face_find_longest_loop(BMFace *f)
bool BM_vert_in_face(BMVert *v, BMFace *f)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
Span< NewT > constexpr cast() const
Definition BLI_span.hh:419
void reinitialize(const int64_t new_size)
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define printf
#define powf(x, y)
int len
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
blender::gpu::Batch * quad
OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds &cone_b)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static void error(const char *str)
void count_indices(Span< int > indices, MutableSpan< int > counts)
int edge_other_vert(const int2 edge, const int vert)
Definition BKE_mesh.hh:307
GroupedSpan< int > build_vert_to_edge_map(Span< int2 > edges, int verts_num, Array< int > &r_offsets, Array< int > &r_indices)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
#define swap(a, b)
Definition sort.c:55
#define FLT_MAX
Definition stdcycles.h:14
BMVert * v1
BMVert * v2
short mat_nr
float no[3]
void * data
struct BMEdge * e
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
BMHeader head
CustomData vdata
int origin
Definition MOD_skin.cc:123
float mat[3][3]
Definition MOD_skin.cc:120
float mat[3][3]
Definition MOD_skin.cc:715
BMVert * verts[4]
Definition MOD_skin.cc:136
uint is_target
Definition MOD_skin.cc:147
struct Frame::@1331 merge[4]
Frame * frame
Definition MOD_skin.cc:143
float co[4][3]
Definition MOD_skin.cc:138
bool inside_hull[4]
Definition MOD_skin.cc:151
int corner
Definition MOD_skin.cc:144
bool detached
Definition MOD_skin.cc:153
struct MDeformWeight * dw
unsigned int def_nr
int edges_num
CustomData vert_data
int verts_num
struct uiLayout * layout
Frame frames[MAX_SKIN_NODE_FRAMES]
Definition MOD_skin.cc:158
int totframe
Definition MOD_skin.cc:159
SkinNodeFlag flag
Definition MOD_skin.cc:161
int seam_edges[2]
Definition MOD_skin.cc:164
SkinModifierData * smd
Definition MOD_skin.cc:169
BMesh * bm
Definition MOD_skin.cc:168
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138