Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Dick <weasel>2020-01-21 22:02:12 +0300
committerCampbell Barton <ideasman42@gmail.com>2020-01-21 22:12:38 +0300
commitbda0c0847b5ef89b31d56b0d88705bafaef90616 (patch)
treef9ee8f15321d00bdd9d0be52608b2b21474fe21f /source/blender/modifiers
parent56c7ee99b85833006bbda9c8f8ca4452278aae84 (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')
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c133
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;
+ }
}
}
}