Esempio n. 1
0
    /** 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);
        }
    }