コード例 #1
0
        //Interset segment sa, sb against cylinder specified by p, d and r
        static bool IntersectSegmentCylinder(VInt3 sa, VInt3 sb, VInt3 p, VInt3 q, VFixedPoint r, ref VInt3 normal, ref VFixedPoint t)
        {
            if (r < Globals.EPS2)
            {
                return(false);
            }

            VInt3       d = q - p, m = sa - p, n = sb - sa;
            VFixedPoint md = VInt3.Dot(m, d);
            VFixedPoint nd = VInt3.Dot(n, d);
            VFixedPoint dd = d.sqrMagnitude;

            if (md < VFixedPoint.Zero && md + nd < VFixedPoint.Zero)
            {
                return(false);
            }
            if (md > dd && md + nd > dd)
            {
                return(false);
            }

            VFixedPoint nn = n.sqrMagnitude;
            VFixedPoint mn = VInt3.Dot(m, n);
            VFixedPoint a  = dd * nn - nd * nd;
            VFixedPoint k  = m.sqrMagnitude - r * r;
            VFixedPoint c  = dd * k - md * md;

            //if start point is within cylinder, not intersect
            if (c < VFixedPoint.Zero)
            {
                return(false);
            }
            //if segment is parallel to cylinder, they do not intersect with each other
            if (a.Abs() < Globals.EPS)
            {
                return(false);
            }

            VFixedPoint b     = dd * mn - nd * md;
            VFixedPoint discr = b * b - a * c;

            if (discr < VFixedPoint.Zero)
            {
                return(false);
            }
            VFixedPoint discrSqrt = FMath.Sqrt(discr);

            t = (-b - discrSqrt) / a;
            if (t < VFixedPoint.Zero || t > VFixedPoint.One)
            {
                return(false);
            }
            //we don't need result of segment and endcap

            /*if(md + t * nd < VFixedPoint.Zero)
             * {
             *  if (nd <= VFixedPoint.Zero) return false;
             *  t = -md / nd;
             *  return k + t * (mn + t * nn) * 2 <= VFixedPoint.Zero;
             * }
             * else if(md + t * nd > dd)
             * {
             *  if (nd >= VFixedPoint.Zero) return false;
             *  t = (dd - md) / nd;
             *  return k + dd - md * 2 + t * ((md - nd) * 2 + t * nn) <= VFixedPoint.Zero;
             * }*/

            VInt3       hitPoint = sa + n * t;
            VFixedPoint param    = VFixedPoint.Zero;

            Distance.distancePointSegmentSquared(p, q, hitPoint, ref param);
            if (param <= VFixedPoint.Zero || param >= VFixedPoint.One)
            {
                return(false);
            }
            VInt3 closestPoint = p * (VFixedPoint.One - param) + q * param;

            normal = (hitPoint - closestPoint) / r;
            return(true);
        }
コード例 #2
0
        static bool sweepSphereVsTri(VInt3[] triVerts, VInt3 normal, VInt3 center, VFixedPoint radius, VInt3 dir, VFixedPoint length, ref VFixedPoint impactDistance, ref bool directHit, bool testInitialialOverlap)
        {
            directHit = false;
            VInt3 edge10 = triVerts[1] - triVerts[0];
            VInt3 edge20 = triVerts[2] - triVerts[0];

            if (testInitialialOverlap)
            {
                VInt3 cp = Distance.closestPtPointTriangle2(center, triVerts[0], triVerts[1], triVerts[2]);
                if ((cp - center).sqrMagnitude <= radius * radius)
                {
                    impactDistance = VFixedPoint.Zero;
                    return(true);
                }
            }

            VFixedPoint u = VFixedPoint.Zero, v = VFixedPoint.Zero;
            {
                VInt3 R = normal * radius;
                if (VInt3.Dot(dir, R) >= VFixedPoint.Zero)
                {
                    R *= -1;
                }

                // The first point of the sphere to hit the triangle plane is the point of the sphere nearest to
                // the triangle plane. Hence, we use center - (normal*radius) below.

                // PT: casting against the extruded triangle in direction R is the same as casting from a ray moved by -R
                VFixedPoint t = VFixedPoint.Zero;
                int         r = rayTriSpecial(center - R, dir, triVerts[0], edge10, edge20, ref t, ref u, ref v);
                if (r == 0)
                {
                    return(false);
                }
                if (r == 2)
                {
                    if (t < VFixedPoint.Zero)
                    {
                        return(false);
                    }
                    impactDistance = t;
                    directHit      = true;
                    return(true);
                }
            }

            //
            // Let's do some art!
            //
            // The triangle gets divided into the following areas (based on the barycentric coordinates (u,v)):
            //
            //               \   A0    /
            //                 \      /
            //                   \   /
            //                     \/ 0
            //            A02      *      A01
            //   u /              /   \          \ v
            //    *              /      \         *
            //                  /         \						.
            //               2 /            \ 1
            //          ------*--------------*-------
            //               /                 \				.
            //        A2    /        A12         \   A1
            //
            //
            // Based on the area where the computed triangle plane intersection point lies in, a different sweep test will be applied.
            //
            // A) A01, A02, A12  : Test sphere against the corresponding edge
            // B) A0, A1, A2     : Test sphere against the corresponding vertex
            //
            // Unfortunately, B) does not work for long, thin triangles. Hence there is some extra code which does a conservative check and
            // switches to edge tests if necessary.
            //

            bool TestSphere = false;
            int  e0 = 0, e1 = 0;

            if (u < VFixedPoint.Zero)
            {
                if (v < VFixedPoint.Zero)
                {
                    e0 = 0;
                    VInt3 intersectPoint = triVerts[1] * u + triVerts[2] * v + triVerts[0] * (VFixedPoint.One - u - v);
                    TestSphere = edgeOrVertexTest(intersectPoint, triVerts, 0, 1, 2, ref e1);
                }
                else if (u + v > VFixedPoint.One)
                {
                    e0 = 2;
                    VInt3 intersectPoint = triVerts[1] * u + triVerts[2] * v + triVerts[0] * (VFixedPoint.One - u - v);
                    TestSphere = edgeOrVertexTest(intersectPoint, triVerts, 2, 0, 1, ref e1);
                }
                else
                {
                    TestSphere = false;
                    e0         = 0; e1 = 2;
                }
            }
            else
            {
                if (v < VFixedPoint.Zero)
                {
                    if (u + v > VFixedPoint.One)
                    {
                        e0 = 1;
                        VInt3 intersectPoint = triVerts[1] * u + triVerts[2] * v + triVerts[0] * (VFixedPoint.One - u - v);
                        TestSphere = edgeOrVertexTest(intersectPoint, triVerts, 1, 0, 2, ref e1);
                    }
                    else
                    {
                        TestSphere = false;
                        e0         = 0;
                        e1         = 1;
                    }
                }
                else
                {
                    TestSphere = false;
                    e0         = 1;
                    e1         = 2;
                }
            }

            return(testRayVsSphereOrCapsule(ref impactDistance, TestSphere, center, radius, dir, length, triVerts, e0, e1));
        }