diff options
author | Henrik Dick <weasel> | 2020-01-21 22:02:12 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2020-01-21 22:07:09 +0300 |
commit | 71f39c45a7b962ae7fa54dc2540768ec558377f3 (patch) | |
tree | 0f9ced2d3c3fad5bf0453942be6c8a11d4d07942 /source/blender/modifiers/intern | |
parent | 0de07c98143ad5b3581018b2e7e2e3ffdf3dc828 (diff) |
Fix numerical instabilities of solidify with complex constraints
Sometimes on flat open vertices the thickness would suddenly start
to be jumping in powers of 2, also when bending a plane there is a
noticeable jump in the geometry.
When offset is set to -1 or 1 weird glitches happen.
See D6559 for test cases that failed.
Diffstat (limited to 'source/blender/modifiers/intern')
-rw-r--r-- | source/blender/modifiers/intern/MOD_solidify_nonmanifold.c | 133 |
1 files changed, 56 insertions, 77 deletions
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index be7bbb86e4d..144ba25c8fa 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -163,6 +163,8 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset; const float ofs_back = ofs_front - smd->offset * smd->offset_fac; + const float ofs_front_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? ofs_front : ofs_back)); + const float ofs_back_clamped = max_ff(1e-5f, fabsf(smd->offset > 0 ? ofs_back : ofs_front)); const float offset_fac_vg = smd->offset_fac_vg; const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg; const float offset = fabsf(smd->offset) * smd->offset_clamp; @@ -1262,15 +1264,16 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, NewFaceRef *face = edge->faces[l]; if (face && (first_edge == NULL || (first_edge->faces[0] != face && first_edge->faces[1] != face))) { + const float ofs = face->reversed ? ofs_back_clamped : ofs_front_clamped; if (!null_faces[face->index]) { mul_v3_v3fl(normals_queue[queue_index], poly_nors[face->index], face->reversed ? -1 : 1); - normals_queue[queue_index++][3] = face->reversed ? ofs_back : ofs_front; + normals_queue[queue_index++][3] = ofs; } else { mul_v3_v3fl(face_nors[0], poly_nors[face->index], face->reversed ? -1 : 1); - nor_ofs[0] = face->reversed ? ofs_back : ofs_front; + nor_ofs[0] = ofs; } } } @@ -1280,7 +1283,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, } } uint face_nors_len = 0; - const float stop_explosion = 1 - fabsf(smd->offset_fac) * 0.05f; + const float stop_explosion = 0.999f - fabsf(smd->offset_fac) * 0.05f; while (queue_index > 0) { if (face_nors_len == 0) { if (queue_index <= 2) { @@ -1371,50 +1374,23 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, } MEM_freeN(normals_queue); /* When up to 3 constraint normals are found. */ - float d, q; - switch (face_nors_len) { - case 0: - mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]); - disable_boundary_fix = true; - break; - case 1: - mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]); - disable_boundary_fix = true; - break; - case 2: - q = dot_v3v3(face_nors[0], face_nors[1]); - d = 1.0f - q * q; - if (LIKELY(d > FLT_EPSILON) && q < stop_explosion) { - d = 1.0f / d; - mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d); - mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d); - add_v3_v3v3(nor, face_nors[0], face_nors[1]); - } - else { - mul_v3_fl(face_nors[0], nor_ofs[0] * 0.5f); - mul_v3_fl(face_nors[1], nor_ofs[1] * 0.5f); - add_v3_v3v3(nor, face_nors[0], face_nors[1]); - } - if (!disable_boundary_fix) { - cross_v3_v3v3(move_nor, face_nors[0], face_nors[1]); - } - break; - case 3: - q = dot_v3v3(face_nors[0], face_nors[1]); - d = 1.0f - q * q; - float *free_nor = move_nor; /* No need to allocate a new array. */ - cross_v3_v3v3(free_nor, face_nors[0], face_nors[1]); - if (LIKELY(d > FLT_EPSILON) && q < stop_explosion) { - d = 1.0f / d; - mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d); - mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d); - add_v3_v3v3(nor, face_nors[0], face_nors[1]); - } - else { - mul_v3_fl(face_nors[0], nor_ofs[0] * 0.5f); - mul_v3_fl(face_nors[1], nor_ofs[1] * 0.5f); - add_v3_v3v3(nor, face_nors[0], face_nors[1]); - } + if (ELEM(face_nors_len, 2, 3)) { + const float q = dot_v3v3(face_nors[0], face_nors[1]); + float d = 1.0f - q * q; + cross_v3_v3v3(move_nor, face_nors[0], face_nors[1]); + if (d > FLT_EPSILON * 10 && q < stop_explosion) { + d = 1.0f / d; + mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d); + mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d); + } + else { + d = 1.0f / (fabsf(q) + 1.0f); + mul_v3_fl(face_nors[0], nor_ofs[0] * d); + mul_v3_fl(face_nors[1], nor_ofs[1] * d); + } + add_v3_v3v3(nor, face_nors[0], face_nors[1]); + if (face_nors_len == 3) { + float *free_nor = move_nor; mul_v3_fl(face_nors[2], nor_ofs[2]); d = dot_v3v3(face_nors[2], free_nor); if (LIKELY(fabsf(d) > FLT_EPSILON)) { @@ -1423,9 +1399,12 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, sub_v3_v3(nor, free_nor); } disable_boundary_fix = true; - break; - default: - BLI_assert(0); + } + } + else { + BLI_assert(face_nors_len < 2); + mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]); + disable_boundary_fix = true; } } /* Simple/Even Method. */ @@ -1447,8 +1426,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, if (face && (first_edge == NULL || (first_edge->faces[0] != face && first_edge->faces[1] != face))) { float angle = 1.0f; - float ofs = face->reversed ? -max_ff(1.0e-5f, ofs_back) : - max_ff(1.0e-5f, ofs_front); + float ofs = face->reversed ? -ofs_back_clamped : ofs_front_clamped; if (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) { MLoop *ml_next = orig_mloop + face->face->loopstart; @@ -1495,17 +1473,16 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, /* Set normal length with selected method. */ if (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) { - float d = dot_v3v3(nor, nor_back); if (has_front) { - float length = len_squared_v3(nor); - if (LIKELY(length > FLT_EPSILON)) { - mul_v3_fl(nor, total_angle / length); + float length_sq = len_squared_v3(nor); + if (LIKELY(length_sq > FLT_EPSILON)) { + mul_v3_fl(nor, total_angle / length_sq); } } if (has_back) { - float length = len_squared_v3(nor_back); - if (LIKELY(length > FLT_EPSILON)) { - mul_v3_fl(nor_back, total_angle_back / length); + float length_sq = len_squared_v3(nor_back); + if (LIKELY(length_sq > FLT_EPSILON)) { + mul_v3_fl(nor_back, total_angle_back / length_sq); } if (!has_front) { copy_v3_v3(nor, nor_back); @@ -1518,7 +1495,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, if (LIKELY(fabsf(q) > FLT_EPSILON)) { q /= nor_length * nor_back_length; } - d = 1.0f - q * q; + float d = 1.0f - q * q; if (LIKELY(d > FLT_EPSILON)) { d = 1.0f / d; if (LIKELY(nor_length > FLT_EPSILON)) { @@ -1625,24 +1602,26 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, /* Do clamping. */ if (do_clamp) { if (do_angle_clamp) { - float min_length = 0; - float angle = 0.5f * M_PI; - uint k = 0; - for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) { - float length = orig_edge_lengths[(*p)->old_edge]; - float e_ang = (*p)->angle; - if (e_ang > angle) { - angle = e_ang; - } - if (length < min_length || k == 0) { - min_length = length; + if (g->edges_len > 2) { + float min_length = 0; + float angle = 0.5f * M_PI; + uint k = 0; + for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) { + float length = orig_edge_lengths[(*p)->old_edge]; + float e_ang = (*p)->angle; + if (e_ang > angle) { + angle = e_ang; + } + if (length < min_length || k == 0) { + min_length = length; + } } - } - float cos_ang = cosf(angle * 0.5f); - if (cos_ang > 0) { - float max_off = min_length * 0.5f / cos_ang; - if (max_off < offset * 0.5f) { - scalar_vgroup *= max_off / offset * 2; + float cos_ang = cosf(angle * 0.5f); + if (cos_ang > 0) { + float max_off = min_length * 0.5f / cos_ang; + if (max_off < offset * 0.5f) { + scalar_vgroup *= max_off / offset * 2; + } } } } |