예제 #1
0
        static void doSupport(CollisionShape a, CollisionShape b, VIntTransform transformA, VIntTransform transformB, VInt3 dir
                              , out VInt3 supportA, out VInt3 supportB, out VInt3 support)
        {
            VInt3 dirInA = dir;

            dirInA = transformA.InverseTransformDirection(dirInA);

            VInt3 dirInB = -dir;

            dirInB = transformB.InverseTransformDirection(dirInB);

            VInt3 pInA = new VInt3();
            VInt3 qInB = new VInt3();

            pInA = a.support(dirInA);
            qInB = b.support(dirInB);

            supportA = transformA.TransformPoint(pInA);
            supportB = transformB.TransformPoint(qInB);

            support = supportA - supportB;
        }
예제 #2
0
        public static PxGJKStatus calcPenDepth(CollisionShape a, CollisionShape b, VIntTransform transformA, VIntTransform transformB,
                                               ref VInt3 pa, ref VInt3 pb, ref VInt3 normal, ref VFixedPoint penDepth)
        {
            simplexSolver.reset();
            //Do simple GJK
            VFixedPoint minMargin        = FMath.Min(a.getMargin(), b.getMargin());
            VInt3       initialSearchDir = transformA.position - transformB.position;
            VInt3       v             = initialSearchDir.sqrMagnitude > Globals.EPS2 ? initialSearchDir : VInt3.right;
            bool        notTerminated = true;
            VFixedPoint sDist         = VFixedPoint.MaxValue;
            VFixedPoint minDist       = sDist;
            int         iter          = 0;

            while (notTerminated && iter < MaxGJKIteration)
            {
                minDist = sDist;
                VInt3 supportA = transformA.TransformPoint(a.support(transformA.InverseTransformDirection(v)));
                VInt3 supportB = transformB.TransformPoint(b.support(transformB.InverseTransformDirection(-v)));
                VInt3 support  = supportA - supportB;
                simplexSolver.addVertex(support, supportA, supportB);
                VInt3 p0, p1;
                bool  con = !simplexSolver.compute_points(out p0, out p1);
                v             = p1 - p0;
                sDist         = v.sqrMagnitude;
                notTerminated = con && sDist < minDist;
                iter++;
            }

            if (notTerminated)
            {
                return(PxGJKStatus.EPA_FAIL);
            }

            simplexSolver.getSimplex(aBuf, bBuf, Q);

            VFixedPoint upper_bound = VFixedPoint.MaxValue;
            VFixedPoint lower_bound = VFixedPoint.MinValue;

            int numVertsLocal = 0;

            heap.Clear();
            facetManager.freeAll();

            switch (simplexSolver.numVertices())
            {
            case 1:
                if (!expandPoint(a, b, transformA, transformB, ref numVertsLocal, lower_bound, upper_bound))
                {
                    return(PxGJKStatus.EPA_FAIL);
                }
                break;

            case 2:
                if (!expandSegment(a, b, transformA, transformB, ref numVertsLocal, lower_bound, upper_bound))
                {
                    return(PxGJKStatus.EPA_FAIL);
                }
                break;

            case 3:
                if (!expandTriangle(a, b, transformA, transformB, ref numVertsLocal, lower_bound, upper_bound))
                {
                    return(PxGJKStatus.EPA_FAIL);
                }
                break;

            case 4:
                //check for input face normal. All face normals in this tetrahedron should be all pointing either inwards or outwards. If all face normals are pointing outward, we are good to go. Otherwise, we need to
                //shuffle the input vertexes and make sure all face normals are pointing outward
                VFixedPoint planeDist0 = calculatePlaneDist(0, 1, 2, aBuf, bBuf);
                if (planeDist0 < VFixedPoint.Zero)
                {
                    //shuffle the input vertexes
                    VInt3 tempA = aBuf[2];
                    VInt3 tempB = bBuf[2];
                    aBuf[2] = aBuf[1];
                    bBuf[2] = bBuf[1];
                    aBuf[1] = tempA;
                    bBuf[1] = tempB;
                }

                Facet f0 = addFacet(0, 1, 2, lower_bound, upper_bound);
                Facet f1 = addFacet(0, 3, 1, lower_bound, upper_bound);
                Facet f2 = addFacet(0, 2, 3, lower_bound, upper_bound);
                Facet f3 = addFacet(1, 3, 2, lower_bound, upper_bound);

                if ((f0 == null) || (f1 == null) || (f2 == null) || (f3 == null) || heap.IsEmpty())
                {
                    return(PxGJKStatus.EPA_FAIL);
                }

                f0.link(0, f1, 2);
                f0.link(1, f3, 2);
                f0.link(2, f2, 0);
                f1.link(0, f2, 2);
                f1.link(1, f3, 0);
                f2.link(1, f3, 1);
                numVertsLocal = 4;
                break;
            }

            Facet facet     = null;
            Facet bestFacet = null;

            bool  hasMoreFacets = false;
            VInt3 tempa;
            VInt3 tempb;
            VInt3 q;


            do
            {
                facetManager.processDeferredIDs();
                facet          = heap.pop(); //get the shortest distance triangle of origin from the list
                facet.m_inHeap = false;

                if (!facet.isObsolete())
                {
                    bestFacet = facet;
                    VInt3       planeNormal = facet.getPlaneNormal();
                    VFixedPoint planeDist   = facet.getPlaneDist();

                    doSupport(a, b, transformA, transformB, planeNormal, out tempa, out tempb, out q);

                    //calculate the distance from support point to the origin along the plane normal. Because the support point is search along
                    //the plane normal, which means the distance should be positive. However, if the origin isn't contained in the polytope, dist
                    //might be negative
                    VFixedPoint dist = VInt3.Dot(q, planeNormal);
                    //update the upper bound to the minimum between exisiting upper bound and the distance if distance is positive
                    upper_bound = dist >= VFixedPoint.Zero ? FMath.Min(upper_bound, dist) : upper_bound;
                    //lower bound is the plane distance, which will be the smallest among all the facets in the prority queue
                    lower_bound = planeDist;
                    //if the plane distance and the upper bound is within a small tolerance, which means we found the MTD
                    bool con0 = upper_bound != VFixedPoint.MaxValue && lower_bound != VFixedPoint.MinValue && (upper_bound - lower_bound) <= Globals.EPS2;
                    if (con0)
                    {
                        calculateContactInformation(aBuf, bBuf, facet, a, b, ref pa, ref pb, ref normal, ref penDepth);
                        return(PxGJKStatus.EPA_CONTACT);
                    }
                    //if planeDist is the same as dist, which means the support point we get out from the Mincowsky sum is one of the point
                    //in the triangle facet, we should exist because we can't progress further.
                    VFixedPoint dif = dist - planeDist;
                    bool        degeneratedCondition = dif < Globals.EPS;

                    if (degeneratedCondition)
                    {
                        return(PxGJKStatus.EPA_DEGENERATE);
                    }

                    aBuf[numVertsLocal] = tempa;
                    bBuf[numVertsLocal] = tempb;

                    int index = numVertsLocal++;

                    // Compute the silhouette cast by the new vertex
                    // Note that the new vertex is on the positive side
                    // of the current facet, so the current facet will
                    // not be in the polytope. Start local search
                    // from this facet.
                    edgeBuffer.MakeEmpty();
                    facet.silhouette(q, aBuf, bBuf, edgeBuffer, facetManager);
                    Edge edge       = edgeBuffer.Get(0);
                    int  bufferSize = edgeBuffer.Size();
                    //check to see whether we have enough space in the facet manager to create new facets
                    if (bufferSize > facetManager.getNumRemainingIDs())
                    {
                        return(PxGJKStatus.EPA_DEGENERATE);
                    }

                    Facet firstFacet = addFacet(edge.getTarget(), edge.getSource(), index, lower_bound, upper_bound);
                    firstFacet.link(0, edge.getFacet(), edge.getIndex());
                    Facet lastFacet = firstFacet;

                    bool degenerate = false;
                    for (int i = 1; (i < bufferSize) && (!degenerate); ++i)
                    {
                        edge = edgeBuffer.Get(i);
                        Facet newFacet = addFacet(edge.getTarget(), edge.getSource(), index, lower_bound, upper_bound);
                        bool  b0       = newFacet.link(0, edge.getFacet(), edge.getIndex());
                        bool  b1       = newFacet.link(2, lastFacet, 1);
                        degenerate = degenerate || !b0 || !b1;
                        lastFacet  = newFacet;
                    }

                    if (degenerate)
                    {
                        return(PxGJKStatus.EPA_DEGENERATE);
                    }
                    firstFacet.link(2, lastFacet, 1);
                }
                hasMoreFacets = (heap.size() > 0);

                if (hasMoreFacets && heap.peak().getPlaneDist() > upper_bound)
                {
                    calculateContactInformation(aBuf, bBuf, bestFacet, a, b, ref pa, ref pb, ref normal, ref penDepth);
                    return(PxGJKStatus.EPA_CONTACT);
                }
            } while (hasMoreFacets && numVertsLocal != MaxSupportPoints);

            return(PxGJKStatus.EPA_DEGENERATE);
        }
예제 #3
0
        public static VFixedPoint distanceLineBoxSquared(VInt3 lineOrigin, VInt3 lineDirection,
                                                         VInt3 boxExtent, VIntTransform boxTransform, ref VFixedPoint lineParam, ref VInt3 boxParam)
        {
            // compute coordinates of line in box coordinate system
            VInt3 pnt = boxTransform.InverseTransformPoint(lineOrigin);
            VInt3 dir = boxTransform.InverseTransformDirection(lineDirection);

            // Apply reflections so that direction vector has nonnegative components.
            bool[] reflect = new bool[3];
            for (int i = 0; i < 3; i++)
            {
                if (dir[i] < VFixedPoint.Zero)
                {
                    pnt[i]     = -pnt[i];
                    dir[i]     = -dir[i];
                    reflect[i] = true;
                }
                else
                {
                    reflect[i] = false;
                }
            }

            VFixedPoint sqrDistance = VFixedPoint.Zero;

            if (dir.x > VFixedPoint.Zero)
            {
                if (dir.y > VFixedPoint.Zero)
                {
                    if (dir.z > VFixedPoint.Zero)
                    {
                        caseNoZero(ref pnt, dir, boxExtent, ref lineParam, ref sqrDistance);
                    }
                    else
                    {
                        case0(0, 1, 2, ref pnt, dir, boxExtent, ref lineParam, ref sqrDistance);
                    }
                }
                else
                {
                    if (dir.z > VFixedPoint.Zero)
                    {
                        case0(0, 2, 1, ref pnt, dir, boxExtent, ref lineParam, ref sqrDistance);                            // (+,0,+)
                    }
                    else
                    {
                        case00(0, 1, 2, ref pnt, dir, boxExtent, ref lineParam, ref sqrDistance);       // (+,0,0)
                    }
                }
            }
            else
            {
                if (dir.y > VFixedPoint.Zero)
                {
                    if (dir.z > VFixedPoint.Zero)
                    {
                        case0(1, 2, 0, ref pnt, dir, boxExtent, ref lineParam, ref sqrDistance);                            // (0,+,+)
                    }
                    else
                    {
                        case00(1, 0, 2, ref pnt, dir, boxExtent, ref lineParam, ref sqrDistance);   // (0,+,0)
                    }
                }
                else
                {
                    if (dir.z > VFixedPoint.Zero)
                    {
                        case00(2, 0, 1, ref pnt, dir, boxExtent, ref lineParam, ref sqrDistance);                           // (0,0,+)
                    }
                    else
                    {
                        case000(ref pnt, boxExtent, ref sqrDistance);                                       // (0,0,0)
                        lineParam = VFixedPoint.Zero;
                    }
                }
            }

            for (int i = 0; i < 3; i++)
            {
                boxParam[i] = pnt[i] * (reflect[i] ? -1 : 1);
            }

            return(sqrDistance);
        }