diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-07-12 16:06:59 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-07-12 16:13:04 +0300 |
commit | 457596d4df7be80c8ed47dd2d07952588771192d (patch) | |
tree | 354e0066d835c006bf12a0d0e524338308f024a2 /source/blender | |
parent | 87164114a306d5dc9f609695c0c6a8e36d79673d (diff) |
BMesh: move safe loop-normal-calc to own function
This makes sense when we want to avoid float precision error
for near co-linear edges. OTOH, this is an arbitrary decision,
so keep functions separate.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/intern/editderivedmesh.c | 2 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_queries.c | 48 | ||||
-rw-r--r-- | source/blender/bmesh/intern/bmesh_queries.h | 4 |
3 files changed, 45 insertions, 9 deletions
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index a91983c001c..ab614b8f460 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -2641,7 +2641,7 @@ static void statvis_calc_distort( vertexCos[BM_elem_index_get(l_iter->next->v)]); } else { - BM_loop_calc_face_normal(l_iter, no_corner); + BM_loop_calc_face_normal_safe(l_iter, no_corner); } /* simple way to detect (what is most likely) concave */ if (dot_v3v3(f_no, no_corner) < 0.0f) { diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index f5c14304ea3..5e8ae696db2 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -1511,12 +1511,11 @@ float BM_loop_calc_face_angle(const BMLoop *l) * Calculate the normal at this loop corner or fallback to the face normal on straight lines. * * \param l The loop to calculate the normal at + * \param epsilon: Value to avoid numeric errors (1e-5f works well). * \param r_normal Resulting normal */ -void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) +float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, float epsilon_sq, float r_normal[3]) { -#define FEPSILON 1e-5f - /* Note: we cannot use result of normal_tri_v3 here to detect colinear vectors (vertex on a straight line) * from zero value, because it does not normalize both vectors before making crossproduct. * Instead of adding two costly normalize computations, just check ourselves for colinear case. */ @@ -1525,20 +1524,55 @@ void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) sub_v3_v3v3(v1, l->prev->v->co, l->v->co); sub_v3_v3v3(v2, l->next->v->co, l->v->co); - const float fac = (v2[0] == 0.0f) ? ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : v1[1] / v2[1]) : v1[0] / v2[0]; + const float fac = + ((v2[0] == 0.0f) ? + ((v2[1] == 0.0f) ? + ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : v1[1] / v2[1]) : v1[0] / v2[0]); mul_v3_v3fl(v_tmp, v2, fac); sub_v3_v3(v_tmp, v1); - if (fac != 0.0f && !is_zero_v3(v1) && len_manhattan_v3(v_tmp) > FEPSILON) { + if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) { /* Not co-linear, we can compute crossproduct and normalize it into normal. */ cross_v3_v3v3(r_normal, v1, v2); - normalize_v3(r_normal); + return normalize_v3(r_normal); } else { copy_v3_v3(r_normal, l->f->no); + return 0.0f; } +} + +/** + * #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon. + * + * Since this doesn't scale baed on triangle size, fixed value works well. + */ +float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) +{ + return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal); +} -#undef FEPSILON +/** + * \brief BM_loop_calc_face_normal + * + * Calculate the normal at this loop corner or fallback to the face normal on straight lines. + * + * \param l The loop to calculate the normal at + * \param r_normal Resulting normal + * \return The length of the cross product (double the area). + */ +float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) +{ + float v1[3], v2[3]; + sub_v3_v3v3(v1, l->prev->v->co, l->v->co); + sub_v3_v3v3(v2, l->next->v->co, l->v->co); + + cross_v3_v3v3(r_normal, v1, v2); + const float len = normalize_v3(r_normal); + if (UNLIKELY(len == 0.0f)) { + copy_v3_v3(r_normal, l->f->no); + } + return len; } /** diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 903fdc59cb8..83977fa8be0 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -113,7 +113,9 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq); float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3]) ATTR_NONNULL(); void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]); void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]); |