From 83cb3879442ab29cbfc7a0c56af48bef823aa826 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 21 Apr 2018 18:34:20 +0200 Subject: BLI math: clamped barycentric weight calculation --- source/blender/blenlib/BLI_math_geom.h | 18 ++++++++++------ source/blender/blenlib/intern/math_geom.c | 36 +++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index ffe0ce11cef..ff80d15ea5d 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -356,12 +356,18 @@ void transform_point_by_seg_v3( const float l_dst_p1[3], const float l_dst_p2[3], const float l_src_p1[3], const float l_src_p2[3]); -void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], - const float co[2], float w[3]); -void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], - const float co[2], float w[3]); -void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const float v3[2], const float v4[2], - const float co[2], float w[4]); +void barycentric_weights_v2( + const float v1[2], const float v2[2], const float v3[2], + const float co[2], float w[3]); +void barycentric_weights_v2_clamped( + const float v1[2], const float v2[2], const float v3[2], + const float co[2], float w[3]); +void barycentric_weights_v2_persp( + const float v1[4], const float v2[4], const float v3[4], + const float co[2], float w[3]); +void barycentric_weights_v2_quad( + const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const float co[2], float w[4]); bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]); int barycentric_inside_triangle_v2(const float w[3]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index e179447936a..ee6a3dcc9b3 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -3021,7 +3021,9 @@ bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[ * \note This is *exactly* the same calculation as #resolve_tri_uv_v2, * although it has double precision and is used for texture baking, so keep both. */ -void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) +void barycentric_weights_v2( + const float v1[2], const float v2[2], const float v3[2], + const float co[2], float w[3]) { float wtot; @@ -3038,11 +3040,36 @@ void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3 } } +/** + * A version of #barycentric_weights_v2 that doesn't allow negative weights. + * Useful when negative values cause problems and points are only ever slightly outside of the triangle. + */ +void barycentric_weights_v2_clamped( + const float v1[2], const float v2[2], const float v3[2], + const float co[2], float w[3]) +{ + float wtot; + + w[0] = max_ff(cross_tri_v2(v2, v3, co), 0.0f); + w[1] = max_ff(cross_tri_v2(v3, v1, co), 0.0f); + w[2] = max_ff(cross_tri_v2(v1, v2, co), 0.0f); + wtot = w[0] + w[1] + w[2]; + + if (wtot != 0.0f) { + mul_v3_fl(w, 1.0f / wtot); + } + else { /* dummy values for zero area face */ + copy_v3_fl(w, 1.0f / 3.0f); + } +} + /** * still use 2D X,Y space but this works for verts transformed by a perspective matrix, * using their 4th component as a weight */ -void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3]) +void barycentric_weights_v2_persp( + const float v1[4], const float v2[4], const float v3[4], + const float co[2], float w[3]) { float wtot; @@ -3064,8 +3091,9 @@ void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const fl * note: untested for values outside the quad's bounds * this is #interp_weights_poly_v2 expanded for quads only */ -void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const float v3[2], const float v4[2], - const float co[2], float w[4]) +void barycentric_weights_v2_quad( + const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const float co[2], float w[4]) { /* note: fabsf() here is not needed for convex quads (and not used in interp_weights_poly_v2). * but in the case of concave/bow-tie quads for the mask rasterizer it gives unreliable results -- cgit v1.2.3