Fix T88111: Skin modifier assets within invalid face normals

The skin modifier was moving vertices without updating normals for the
connected faces, this happened when smoothing and welding vertices.

Reviewed By: mont29

Ref D11397
This commit is contained in:
Campbell Barton 2021-05-26 16:06:02 +10:00 committed by Jeroen Bakker
parent cc5392b4d9
commit 8eef2f83e9
Notes: blender-bot 2023-02-14 08:28:46 +01:00
Referenced by issue #88449, Blender LTS: Maintenance Task 2.93
Referenced by issue #88111, Skin Modifier asserts on invalid normals
1 changed files with 61 additions and 2 deletions

View File

@ -90,6 +90,46 @@
#include "bmesh.h"
/* -------------------------------------------------------------------- */
/** \name Generic BMesh Utilities
* \{ */
static void vert_face_normal_mark_set(BMVert *v)
{
BMIter iter;
BMFace *f;
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
f->no[0] = FLT_MAX;
}
}
static void vert_face_normal_mark_update(BMVert *v)
{
BMIter iter;
BMFace *f;
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
if (f->no[0] == FLT_MAX) {
BM_face_normal_update(f);
}
}
}
/**
* Recalculate the normals of all faces connected to `verts`.
*/
static void vert_array_face_normal_update(BMVert **verts, int verts_len)
{
for (int i = 0; i < verts_len; i++) {
vert_face_normal_mark_set(verts[i]);
}
for (int i = 0; i < verts_len; i++) {
vert_face_normal_mark_update(verts[i]);
}
}
/** \} */
typedef struct {
float mat[3][3];
/* Vert that edge is pointing away from, no relation to
@ -1352,13 +1392,25 @@ static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_f
split_face = collapse_face_corners(bm, split_face, 4, vert_buf);
}
/* Done with dynamic array, split_face must now be a quad */
BLI_array_free(vert_buf);
/* `split_face` should now be a quad. */
BLI_assert(split_face->len == 4);
/* Account for the highly unlikely case that it's not a quad. */
if (split_face->len != 4) {
/* Reuse `vert_buf` for updating normals. */
BLI_array_clear(vert_buf);
BLI_array_grow_items(vert_buf, split_face->len);
BM_iter_as_array(bm, BM_FACES_OF_VERT, split_face, (void **)vert_buf, split_face->len);
vert_array_face_normal_update(vert_buf, split_face->len);
BLI_array_free(vert_buf);
return;
}
/* Done with dynamic array. */
BLI_array_free(vert_buf);
/* Get split face's verts */
// BM_iter_as_array(bm, BM_VERTS_OF_FACE, split_face, (void **)verts, 4);
BM_face_as_array_vert_quad(split_face, verts);
@ -1373,6 +1425,8 @@ static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_f
}
BMO_op_exec(bm, &op);
BMO_op_finish(bm, &op);
vert_array_face_normal_update(frame->verts, 4);
}
/* If the frame has some vertices that are inside the hull (detached)
@ -1731,6 +1785,11 @@ static void skin_smooth_hulls(BMesh *bm,
/* Done with original coordinates */
BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, skey);
BMFace *f;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_face_normal_update(f);
}
}
/* Returns true if all hulls are successfully built, false otherwise */