fix [#33106] Decimate modifier/collapse give bad result

FLT_EPSILON was too small to use when checking if the edge collapse result is an error.

add invert_m3_m3_ex(), invert_m3_ex() functiosn which take an epsilon to check the determinant, saves calculating it twice per edge collapse.
This commit is contained in:
Campbell Barton 2012-11-07 09:28:59 +00:00
parent efc44d0c4d
commit f727448e10
5 changed files with 61 additions and 18 deletions

@ -98,6 +98,9 @@ void mul_m3_fl(float R[3][3], float f);
void mul_m4_fl(float R[4][4], float f);
void mul_mat3_m4_fl(float R[4][4], float f);
int invert_m3_ex(float m[3][3], const float epsilon);
int invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon);
int invert_m3(float R[3][3]);
int invert_m3_m3(float R[3][3], float A[3][3]);
int invert_m4(float R[4][4]);

@ -51,6 +51,6 @@ void BLI_quadric_mul(Quadric *a, const float scalar);
/* solve */
float BLI_quadric_evaluate(const Quadric *q, const float v[3]);
int BLI_quadric_optimize(const Quadric *q, float v[3]);
int BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon);
#endif /* __BLI_QUADRIC_H__ */

@ -504,6 +504,51 @@ void sub_m4_m4m4(float m1[][4], float m2[][4], float m3[][4])
m1[i][j] = m2[i][j] - m3[i][j];
}
/* why not make this a standard part of the API? */
static float determinant_m3_local(float m[3][3])
{
return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
}
int invert_m3_ex(float m[3][3], const float epsilon)
{
float tmp[3][3];
int success;
success = invert_m3_m3_ex(tmp, m, epsilon);
copy_m3_m3(m, tmp);
return success;
}
int invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon)
{
float det;
int a, b, success;
BLI_assert(epsilon >= 0.0f);
/* calc adjoint */
adjoint_m3_m3(m1, m2);
/* then determinant old matrix! */
det = determinant_m3_local(m2);
success = (fabsf(det) > epsilon);
if (LIKELY(det != 0.0f)) {
det = 1.0f / det;
for (a = 0; a < 3; a++) {
for (b = 0; b < 3; b++) {
m1[a][b] *= det;
}
}
}
return success;
}
int invert_m3(float m[3][3])
{
float tmp[3][3];
@ -524,17 +569,16 @@ int invert_m3_m3(float m1[3][3], float m2[3][3])
adjoint_m3_m3(m1, m2);
/* then determinant old matrix! */
det = (m2[0][0] * (m2[1][1] * m2[2][2] - m2[1][2] * m2[2][1]) -
m2[1][0] * (m2[0][1] * m2[2][2] - m2[0][2] * m2[2][1]) +
m2[2][0] * (m2[0][1] * m2[1][2] - m2[0][2] * m2[1][1]));
det = determinant_m3_local(m2);
success = (det != 0);
success = (det != 0.0f);
if (det == 0) det = 1;
det = 1 / det;
for (a = 0; a < 3; a++) {
for (b = 0; b < 3; b++) {
m1[a][b] *= det;
if (LIKELY(det != 0.0f)) {
det = 1.0f / det;
for (a = 0; a < 3; a++) {
for (b = 0; b < 3; b++) {
m1[a][b] *= det;
}
}
}

@ -107,18 +107,13 @@ float BLI_quadric_evaluate(const Quadric *q, const float v[3])
q->d2);
}
int BLI_quadric_optimize(const Quadric *q, float v[3])
int BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon)
{
float m[3][3];
float det;
BLI_quadric_to_tensor_m3(q, m);
det = determinant_m3(m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2]);
if (fabsf(det) > FLT_EPSILON) {
invert_m3(m);
if (invert_m3_ex(m, epsilon)) {
BLI_quadric_to_vector_v3(q, v);
mul_m3_v3(m, v);
negate_v3(v);

@ -51,6 +51,7 @@
#define USE_SAFETY_CHECKS
#define BOUNDARY_PRESERVE_WEIGHT 100.0f
#define OPTIMIZE_EPS 0.01f /* FLT_EPSILON is too small, see [#33106] */
typedef enum CD_UseFlag {
CD_DO_VERT = (1 << 0),
@ -123,7 +124,7 @@ static void bm_decim_calc_target_co(BMEdge *e, float optimize_co[3],
&vquadrics[BM_elem_index_get(e->v2)]);
if (BLI_quadric_optimize(&q, optimize_co)) {
if (BLI_quadric_optimize(&q, optimize_co, OPTIMIZE_EPS)) {
return; /* all is good */
}
else {