Fix T95963: change thresholds in complex solidify

This fix contains two parts. There was one critical mistake where
order of two indices was wrong when removing constraint planes from
the array. The other changes are improvements to the used thresholds
to keep everything numerically stable.

Differential Revision: http://developer.blender.org/D14183
This commit is contained in:
Henrik Dick 2022-03-02 12:14:22 +01:00
parent ccf4001458
commit c2e8e68b65
Notes: blender-bot 2023-06-22 14:33:21 +02:00
Referenced by issue #95963, Solidify modifier has new artifacts
Referenced by issue #109239, Solidify (Complex, Constraints) - very rare glitch
1 changed files with 22 additions and 19 deletions

View File

@ -1468,10 +1468,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
for (uint k = 0; k < queue_index; k++) {
for (uint m = k + 1; m < queue_index; m++) {
float p = dot_v3v3(planes_queue[k], planes_queue[m]);
if (p <= min_p + FLT_EPSILON) {
if (p < min_p) {
min_p = p;
min_n0 = m;
min_n1 = k;
min_n0 = k;
min_n1 = m;
}
}
}
@ -1484,18 +1484,13 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
swap_v4_v4(planes_queue[min_n0], planes_queue[1]);
}
/* Find the third most important/different normal. */
min_p = 1;
min_n1 = 0;
float max_p = -1;
min_p = 1.0f;
min_n1 = 2;
float max_p = -1.0f;
for (uint k = 2; k < queue_index; k++) {
max_p = -1;
for (uint m = 0; m < 2; m++) {
float p = dot_v3v3(planes_queue[m], planes_queue[k]);
if (p > max_p + FLT_EPSILON) {
max_p = p;
}
}
if (max_p <= min_p + FLT_EPSILON) {
max_p = max_ff(dot_v3v3(planes_queue[0], planes_queue[k]),
dot_v3v3(planes_queue[1], planes_queue[k]));
if (max_p <= min_p) {
min_p = max_p;
min_n1 = k;
}
@ -1503,7 +1498,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
swap_v4_v4(planes_queue[min_n1], planes_queue[2]);
}
/* Remove/average duplicate normals in planes_queue. */
while (queue_index > 0) {
while (queue_index > 2) {
uint best_n0 = 0;
uint best_n1 = 0;
float best_p = -1.0f;
@ -1515,12 +1510,14 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
if (p > best_p + FLT_EPSILON || (p >= best_p && ofs_diff < best_ofs_diff)) {
best_p = p;
best_ofs_diff = ofs_diff;
best_n0 = m;
best_n1 = k;
best_n0 = k;
best_n1 = m;
}
}
}
if (best_p < 0.999f) {
/* Make sure there are no equal planes. This threshold is crucial for the
* methods below to work without numerical issues. */
if (best_p < 0.98f) {
break;
}
add_v3_v3(planes_queue[best_n0], planes_queue[best_n1]);
@ -1549,6 +1546,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
for (int m = 0; m < size; m++) {
madd_v3_v3fl(mat[k], planes_queue[m], planes_queue[m][k]);
}
/* Add a small epsilon to ensure the invert is going to work.
* This addition makes the inverse more stable and the results
* seem to get more precise. */
mat[k][k] += 5e-5f;
}
/* NOTE: this matrix invert fails if there is less than 3 different normals. */
invert_m3(mat);
@ -1597,7 +1598,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
add_v3_v3v3(nor, planes_queue[0], planes_queue[1]);
if (size == 3) {
d = dot_v3v3(planes_queue[2], move_nor);
if (LIKELY(fabsf(d) > FLT_EPSILON)) {
/* The following threshold ignores the third plane if it is almost orthogonal to
* the still free direction. */
if (fabsf(d) > 0.02f) {
float tmp[3];
madd_v3_v3v3fl(tmp, nor, planes_queue[2], -planes_queue[2][3]);
mul_v3_v3fl(tmp, move_nor, dot_v3v3(planes_queue[2], tmp) / d);