/** Closest point on the triangle \a abc to the point \a p. * \see 'Real Time Collision Detection' by Christer Ericson, chapter 5.1, page 141 * 需要考虑溢出原因,所以平方和的单精度只放大10倍 */ public static VInt3 ClosestPointOnTriangle(VInt3 a, VInt3 b, VInt3 c, VInt3 p) { // Check if p is in vertex region outside A var ab = b - a; var ac = c - a; var ap = p - a; var d1 = VInt3.DotLongSafe(ab, ap); var d2 = VInt3.DotLongSafe(ac, ap); // Barycentric coordinates (1,0,0) if (d1 <= 0 && d2 <= 0) { return(a); } // Check if p is in vertex region outside B var bp = p - b; var d3 = VInt3.DotLongSafe(ab, bp); var d4 = VInt3.DotLongSafe(ac, bp); // Barycentric coordinates (0,1,0) if (d3 >= 0 && d4 <= d3) { return(b); } /*CheckIntOverFlow(d1); * CheckIntOverFlow(d2); * CheckIntOverFlow(d3); * CheckIntOverFlow(d4);*/ // Check if p is in edge region outside AB, if so return a projection of p onto AB var vc = d1 * d4 - d3 * d2; if (d1 >= 0 && d3 <= 0 && vc <= 0) { // Barycentric coordinates (1-v, v, 0) /*var v = d1 / (d1 - d3); * return a + ab * v;*/ //Modify VFactor vf = new VFactor(d1, d1 - d3); //Debug.Log("==type 1==" + (a + ab * vf)); return(a + ab * vf); } // Check if p is in vertex region outside C var cp = p - c; var d5 = VInt3.DotLongSafe(ab, cp); var d6 = VInt3.DotLongSafe(ac, cp); /*CheckIntOverFlow(d5); * CheckIntOverFlow(d6);*/ // Barycentric coordinates (0,0,1) if (d6 >= 0 && d5 <= d6) { return(c); } // Check if p is in edge region of AC, if so return a projection of p onto AC var vb = d5 * d2 - d1 * d6; if (d2 >= 0 && d6 <= 0 && vb <= 0) { // Barycentric coordinates (1-v, 0, v) /*var v = d2 / (d2 - d6); * return a + ac * v;*/ //Modify VFactor vf = new VFactor(d2, d2 - d6); //Debug.Log("==type 2==" + (a + ac * vf)); return(a + ac * vf); } // Check if p is in edge region of BC, if so return projection of p onto BC var va = d3 * d6 - d5 * d4; if ((d4 - d3) >= 0 && (d5 - d6) >= 0 && va <= 0) { /*var v = (d4 - d3) / ((d4 - d3) + (d5 - d6)); * return b + (c - b) * v;*/ //Modify VFactor vf = new VFactor((d4 - d3), (d4 - d3) + (d5 - d6)); //Debug.Log("==type 3==" + (b + (c - b) * vf)); return(b + (c - b) * vf); } else { // P is inside the face region. Compute the point using its barycentric coordinates (u, v, w) //var denom = 1f / (va + vb + vc); //var v = vb * denom; //var w = vc * denom; //Modify VFactor vf = new VFactor(1, va + vb + vc); var v = vf * vb; var w = vf * vc; // This is equal to: u*a + v*b + w*c, u = va*denom = 1 - v - w; //Debug.Log("==type 4==" + (a + ab * v + ac * w)); return(a + ab * v + ac * w); } }