Пример #1
0
        /// <summary>
        /// CollDetectBoxStaticMeshOverlap
        /// </summary>
        /// <param name="oldBox"></param>
        /// <param name="newBox"></param>
        /// <param name="mesh"></param>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        /// <returns>bool</returns>
        private static bool CollDetectBoxStaticMeshOverlap(Box oldBox,
                                                           Box newBox,
                                                           TriangleMesh mesh,
                                                           ref CollDetectInfo info,
                                                           float collTolerance,
                                                           CollisionFunctor collisionFunctor)
        {
            float boxRadius = newBox.GetBoundingRadiusAroundCentre();

            #region REFERENCE: Vector3 boxCentre = newBox.GetCentre();
            Vector3 boxCentre;
            newBox.GetCentre(out boxCentre);
            // Deano need to trasnform the box center into mesh space
            Matrix invTransformMatrix = mesh.InverseTransformMatrix;
            Vector3.Transform(ref boxCentre, ref invTransformMatrix, out boxCentre);
            #endregion

            BoundingBox bb = BoundingBoxHelper.InitialBox;
            BoundingBoxHelper.AddBox(newBox, ref bb);

            bool collision = false;

            int[] potTriArray = IntStackAlloc();

            // aabox is done in mesh space and handles the mesh transform correctly
            int numTriangles = mesh.GetTrianglesIntersectingtAABox(potTriArray, MaxLocalStackTris, ref bb);

            for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
            {
                IndexedTriangle meshTriangle = mesh.GetTriangle(potTriArray[iTriangle]);

                // quick early test is done in mesh space
                float dist = meshTriangle.Plane.DotCoordinate(boxCentre);

                // BEN-BUG-FIX: Fixed by chaning 0.0F to -boxRadius.
                if (dist > boxRadius || dist < -boxRadius)
                {
                    continue;
                }

                if (DoOverlapBoxTriangleTest(
                        oldBox, newBox,
                        ref meshTriangle,
                        mesh,
                        ref info,
                        collTolerance,
                        collisionFunctor))
                {
                    collision = true;
                }
            }

            FreeStackAlloc(potTriArray);

            return(collision);
        }
Пример #2
0
        private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox,
                                                     ref IndexedTriangle triangle, TriangleMesh mesh,
                                                     ref CollDetectInfo info, float collTolerance,
                                                     CollisionFunctor collisionFunctor)
        {
            Matrix dirs0 = newBox.Orientation;

            #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2)));
            Vector3 triVec0;
            Vector3 triVec1;
            Vector3 triVec2;
            mesh.GetVertex(triangle.GetVertexIndex(0), out triVec0);
            mesh.GetVertex(triangle.GetVertexIndex(1), out triVec1);
            mesh.GetVertex(triangle.GetVertexIndex(2), out triVec2);

            // Deano move tri into world space
            Matrix transformMatrix = mesh.TransformMatrix;
            Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0);
            Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1);
            Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2);

            Triangle tri = new Triangle(ref triVec0, ref triVec1, ref triVec2);
            #endregion


            #region qqfx Vector3 triEdge0 = (tri.GetPoint(1) - tri.GetPoint(0));
            Vector3 pt0;
            Vector3 pt1;
            tri.GetPoint(0, out pt0);
            tri.GetPoint(1, out pt1);

            Vector3 triEdge0;
            Vector3.Subtract(ref pt1, ref pt1, out triEdge0);
            #endregion

            #region qqfx Vector3 triEdge1 = (tri.GetPoint(2) - tri.GetPoint(1));
            Vector3 pt2;
            tri.GetPoint(2, out pt2);

            Vector3 triEdge1;
            Vector3.Subtract(ref pt2, ref pt1, out triEdge1);
            #endregion

            #region qqfx Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2));
            Vector3 triEdge2;
            Vector3.Subtract(ref pt0, ref pt2, out triEdge2);
            #endregion

            triEdge0.Normalize();
            triEdge1.Normalize();
            triEdge2.Normalize();

            Vector3 triNormal = triangle.Plane.Normal;

            // the 15 potential separating axes
            const int numAxes = 13;
            Vector3[] axes    = new Vector3[numAxes];

            axes[0] = triNormal;
            axes[1] = dirs0.Right;
            axes[2] = dirs0.Up;
            axes[3] = dirs0.Backward;
            Vector3.Cross(ref axes[1], ref triEdge0, out axes[4]);
            Vector3.Cross(ref axes[1], ref triEdge1, out axes[5]);
            Vector3.Cross(ref axes[1], ref triEdge2, out axes[6]);
            Vector3.Cross(ref axes[2], ref triEdge0, out axes[7]);
            Vector3.Cross(ref axes[2], ref triEdge1, out axes[8]);
            Vector3.Cross(ref axes[2], ref triEdge2, out axes[9]);
            Vector3.Cross(ref axes[3], ref triEdge0, out axes[10]);
            Vector3.Cross(ref axes[3], ref triEdge1, out axes[11]);
            Vector3.Cross(ref axes[3], ref triEdge2, out axes[12]);

            // the overlap depths along each axis
            float[] overlapDepths = new float[numAxes];

            // see if the boxes are separate along any axis, and if not keep a
            // record of the depths along each axis
            int i;
            for (i = 0; i < numAxes; ++i)
            {
                overlapDepths[i] = 1.0f;
                if (Disjoint(out overlapDepths[i], axes[i], newBox, tri, collTolerance))
                {
                    return(false);
                }
            }

            // The box overlap, find the separation depth closest to 0.
            float minDepth = float.MaxValue;
            int   minAxis  = -1;

            for (i = 0; i < numAxes; ++i)
            {
                // If we can't normalise the axis, skip it
                float l2 = axes[i].LengthSquared();
                if (l2 < JiggleMath.Epsilon)
                {
                    continue;
                }

                // Normalise the separation axis and the depth
                float invl = 1.0f / (float)System.Math.Sqrt(l2);
                axes[i]          *= invl;
                overlapDepths[i] *= invl;

                // If this axis is the minimum, select it
                if (overlapDepths[i] < minDepth)
                {
                    minDepth = overlapDepths[i];
                    minAxis  = i;
                }
            }

            if (minAxis == -1)
            {
                return(false);
            }

            // Make sure the axis is facing towards the 0th box.
            // if not, invert it
            Vector3 D     = newBox.GetCentre() - tri.Centre;
            Vector3 N     = axes[minAxis];
            float   depth = overlapDepths[minAxis];

            if (Vector3.Dot(D, N) < 0.0f)
            {
                N *= -1;
            }

            Vector3 boxOldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero;
            Vector3 meshPos   = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            List <Vector3> pts = new List <Vector3>();
            //pts.Clear();

            const float combinationDist = 0.05f;
            GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist);

            // adjust the depth
            #region REFERENCE: Vector3 delta = boxNewPos - boxOldPos;
            Vector3 delta;
            Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta);
            #endregion

            #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N);
            float oldDepth;
            Vector3.Dot(ref delta, ref N, out oldDepth);
            oldDepth += depth;
            #endregion

            unsafe
            {
                // report collisions
                int numPts = pts.Count;
#if USE_STACKALLOC
                SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
#else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed(SmallCollPointInfo *collPts = collPtArray)
#endif
                {
                    if (numPts > 0)
                    {
                        if (numPts >= MaxLocalStackSCPI)
                        {
                            numPts = MaxLocalStackSCPI - 1;
                        }

                        // adjust positions
                        for (i = 0; i < numPts; ++i)
                        {
                            collPts[i] = new SmallCollPointInfo(pts[i] - boxNewPos, pts[i] - meshPos, oldDepth);
                        }

                        collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts);
#if !USE_STACKALLOC
                        FreeStackAlloc(collPtArray);
#endif
                        return(true);
                    }
                    else
                    {
#if !USE_STACKALLOC
                        FreeStackAlloc(collPtArray);
#endif
                        return(false);
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// CollDetectCapsuleStaticMeshOverlap
        /// </summary>
        /// <param name="oldCapsule"></param>
        /// <param name="newCapsule"></param>
        /// <param name="mesh"></param>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        private void CollDetectCapsuleStaticMeshOverlap(Capsule oldCapsule, Capsule newCapsule,
                                                        TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            float capsuleTolR  = collTolerance + newCapsule.Radius;
            float capsuleTolR2 = capsuleTolR * capsuleTolR;

            Vector3 collNormal = Vector3.Zero;

            BoundingBox bb = BoundingBoxHelper.InitialBox;

            BoundingBoxHelper.AddCapsule(newCapsule, ref bb);

            unsafe
            {
#if USE_STACKALLOC
                SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
                int *potentialTriangles     = stackalloc int[MaxLocalStackTris];
                {
                    {
#else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed(SmallCollPointInfo *collPts = collPtArray)
                {
                    int[] potTriArray = IntStackAlloc();
                    fixed(int *potentialTriangles = potTriArray)
                    {
#endif
                        int numCollPts = 0;

                        int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb);

                        Vector3 capsuleStart     = newCapsule.Position;
                        Vector3 capsuleEnd       = newCapsule.GetEnd();
                        Matrix  meshInvTransform = mesh.InverseTransformMatrix;

                        Vector3 meshSpaceCapsuleStart = Vector3.Transform(capsuleStart, meshInvTransform);
                        Vector3 meshSpaceCapsuleEnd   = Vector3.Transform(capsuleEnd, meshInvTransform);

                        for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
                        {
                            IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]);

                            // we do the plane test using the capsule in mesh space
                            float distToStart = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleStart);
                            float distToEnd   = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleEnd);

                            // BEN-BUG-FIX: Fixed by replacing 0.0F with -capsuleTolR.
                            if ((distToStart > capsuleTolR && distToEnd > capsuleTolR) ||
                                (distToStart < -capsuleTolR && distToEnd < -capsuleTolR))
                            {
                                continue;
                            }

                            // we now transform the triangle into world space (we could keep leave the mesh alone
                            // but at this point 3 vector transforms is probably not a major slow down)
                            int i0, i1, i2;
                            meshTriangle.GetVertexIndices(out i0, out i1, out i2);

                            Vector3 triVec0;
                            Vector3 triVec1;
                            Vector3 triVec2;
                            mesh.GetVertex(i0, out triVec0);
                            mesh.GetVertex(i1, out triVec1);
                            mesh.GetVertex(i2, out triVec2);

                            // Deano move tri into world space
                            Matrix transformMatrix = mesh.TransformMatrix;
                            Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0);
                            Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1);
                            Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2);
                            Triangle triangle = new Triangle(ref triVec0, ref triVec1, ref triVec2);

                            Segment seg = new Segment(capsuleStart, capsuleEnd - capsuleStart);

                            float tS, tT0, tT1;
                            float d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, seg, triangle);

                            if (d2 < capsuleTolR2)
                            {
                                Vector3 oldCapsuleStart = oldCapsule.Position;
                                Vector3 oldCapsuleEnd   = oldCapsule.GetEnd();
                                Segment oldSeg          = new Segment(oldCapsuleStart, oldCapsuleEnd - oldCapsuleStart);
                                d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, oldSeg, triangle);
                                // report result from old position
                                float   dist       = (float)System.Math.Sqrt(d2);
                                float   depth      = oldCapsule.Radius - dist;
                                Vector3 pt         = triangle.GetPoint(tT0, tT1);
                                Vector3 collisionN = (d2 > JiggleMath.Epsilon) ? JiggleMath.NormalizeSafe(oldSeg.GetPoint(tS) - pt) :
                                                     meshTriangle.Plane.Normal;
                                if (numCollPts < MaxLocalStackSCPI)
                                {
                                    // BEN-OPTIMISATION: Reused existing collPts.
                                    collPts[numCollPts].R0 = pt - body0Pos;
                                    collPts[numCollPts].R1 = pt - body1Pos;
                                    collPts[numCollPts++].InitialPenetration = depth;
                                }
                                collNormal += collisionN;
                            }
                        }
                        if (numCollPts > 0)
                        {
                            JiggleMath.NormalizeSafe(ref collNormal);
                            collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts);
                        }
#if USE_STACKALLOC
                    }
                }
#else
                    }
                    FreeStackAlloc(potTriArray);
                }
                FreeStackAlloc(collPtArray);
#endif
            }
        }
Пример #4
0
        /// <summary>
        /// CollDetectSphereStaticMeshSweep
        /// </summary>
        /// <param name="oldSphere"></param>
        /// <param name="newSphere"></param>
        /// <param name="mesh"></param>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        internal static void CollDetectSphereStaticMeshSweep(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh,
                                                             CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // really use a swept test - or overlap?
            Vector3 delta = newSphere.Center - oldSphere.Center;

            if (delta.LengthSquared() < (0.25f * newSphere.Radius * newSphere.Radius))
            {
                CollDetectSphereStaticMeshOverlap(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor);
            }
            else
            {
                Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
                Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

                float sphereTolR = collTolerance + oldSphere.Radius;
                float sphereToR2 = sphereTolR * sphereTolR;

                Vector3 collNormal = Vector3.Zero;

                BoundingBox bb = BoundingBoxHelper.InitialBox;
                BoundingBoxHelper.AddSphere(oldSphere, ref bb);
                BoundingBoxHelper.AddSphere(newSphere, ref bb);

                // get the spheres centers in triangle mesh space
                Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix);
                Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix);

                unsafe
                {
#if USE_STACKALLOC
                    SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
                    int *potentialTriangles     = stackalloc int[MaxLocalStackTris];
                    {
                        {
#else
                    SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                    fixed(SmallCollPointInfo *collPts = collPtArray)
                    {
                        int[] potTriArray = IntStackAlloc();
                        fixed(int *potentialTriangles = potTriArray)
                        {
#endif
                            int numCollPts = 0;

                            int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb);

                            for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
                            {
                                // first test the old sphere for being on the wrong side
                                IndexedTriangle meshTriangle    = mesh.GetTriangle(potentialTriangles[iTriangle]);
                                float           distToCentreOld = meshTriangle.Plane.DotCoordinate(oldSphereCen);
                                if (distToCentreOld <= 0.0f)
                                {
                                    continue;
                                }
                                // now test the new sphere for being clear

                                float distToCentreNew = meshTriangle.Plane.DotCoordinate(newSphereCen);
                                if (distToCentreNew > sphereTolR)
                                {
                                    continue;
                                }

                                int i0, i1, i2;
                                meshTriangle.GetVertexIndices(out i0, out i1, out i2);

                                Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2));

                                // If the old sphere is intersecting, just use that result
                                float s, t;
                                float d2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle);

                                if (d2 < sphereToR2)
                                {
                                    float   dist      = (float)System.Math.Sqrt(d2);
                                    float   depth     = oldSphere.Radius - dist;
                                    Vector3 triangleN = triangle.Normal;
                                    Vector3 normSafe  = oldSphereCen - triangle.GetPoint(s, t);

                                    JiggleMath.NormalizeSafe(ref normSafe);

                                    Vector3 collisionN = (dist > float.Epsilon) ? normSafe : triangleN;
                                    // since impulse gets applied at the old position
                                    Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN;
                                    if (numCollPts < MaxLocalStackSCPI)
                                    {
                                        // BEN-OPTIMISATION: Reuse existing collPts.
                                        collPts[numCollPts].R0 = pt - body0Pos;
                                        collPts[numCollPts].R1 = pt - body1Pos;
                                        collPts[numCollPts++].InitialPenetration = depth;
                                    }
                                    collNormal += collisionN;
                                }
                                else if (distToCentreNew < distToCentreOld)
                                {
                                    // old sphere is not intersecting - do a sweep, but only if the sphere is moving into the
                                    // triangle
                                    Vector3 pt, N; // CHECK THIS
                                    float   depth;
                                    if (Intersection.SweptSphereTriangleIntersection(out pt, out N, out depth, oldSphere, newSphere, triangle,
                                                                                     distToCentreOld, distToCentreNew, Intersection.EdgesToTest.EdgeAll, Intersection.CornersToTest.CornerAll))
                                    {
                                        // collision point etc must be relative to the old position because that's
                                        //where the impulses are applied
                                        float   dist      = (float)System.Math.Sqrt(d2);
                                        float   depth2    = oldSphere.Radius - dist;
                                        Vector3 triangleN = triangle.Normal;
                                        Vector3 normSafe  = oldSphereCen - triangle.GetPoint(s, t);
                                        JiggleMath.NormalizeSafe(ref normSafe);
                                        Vector3 collisionN = (dist > JiggleMath.Epsilon) ? normSafe : triangleN;
                                        // since impulse gets applied at the old position
                                        Vector3 pt2 = oldSphere.Center - oldSphere.Radius * collisionN;
                                        if (numCollPts < MaxLocalStackSCPI)
                                        {
                                            // BEN-OPTIMISATION: Reuse existing collPts.
                                            collPts[numCollPts].R0 = pt2 - body0Pos;
                                            collPts[numCollPts].R1 = pt2 - body1Pos;
                                            collPts[numCollPts++].InitialPenetration = depth;
                                        }
                                        collNormal += collisionN;
                                    }
                                }
                            }
                            if (numCollPts > 0)
                            {
                                JiggleMath.NormalizeSafe(ref collNormal);
                                collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts);
                            }
                        }

#if USE_STACKALLOC
                    }
                }
#else
                        FreeStackAlloc(potTriArray);
                    }

                    FreeStackAlloc(collPtArray);
                }
#endif
            }
        }
Пример #5
0
        /// <summary>
        /// CollDetectSphereStaticMeshOverlap
        /// </summary>
        /// <param name="oldSphere"></param>
        /// <param name="newSphere"></param>
        /// <param name="mesh"></param>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public static void CollDetectSphereStaticMeshOverlap(BoundingSphere oldSphere, BoundingSphere newSphere,
                                                             TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            float sphereTolR  = collTolerance + newSphere.Radius;
            float sphereTolR2 = sphereTolR * sphereTolR;

            SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
            int[] potTriArray = IntStackAlloc();

            int numCollPts = 0;

            Vector3 collNormal = Vector3.Zero;

            BoundingBox bb = BoundingBoxHelper.InitialBox;

            BoundingBoxHelper.AddSphere(newSphere, ref bb);
            int numTriangles = mesh.GetTrianglesIntersectingtAABox(potTriArray, MaxLocalStackTris, ref bb);

            // Deano : get the spheres centers in triangle mesh space
            Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix);
            Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix);

            for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
            {
                IndexedTriangle meshTriangle = mesh.GetTriangle(potTriArray[iTriangle]);
                float           distToCentre = meshTriangle.Plane.DotCoordinate(newSphereCen);

                // BEN-BUG-FIX: Replaced 0.0f with -sphereTolR.
                if (distToCentre < -sphereTolR || distToCentre > sphereTolR)
                {
                    continue;
                }

                int i0, i1, i2;
                meshTriangle.GetVertexIndices(out i0, out i1, out i2);

                Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2));

                float s, t;
                float newD2 = Distance.PointTriangleDistanceSq(out s, out t, newSphereCen, triangle);

                if (newD2 < sphereTolR2)
                {
                    // have overlap - but actually report the old intersection
                    float oldD2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle);
                    float dist  = (float)System.Math.Sqrt((float)oldD2);
                    float depth = oldSphere.Radius - dist;

                    Vector3 triPointSTNorm = oldSphereCen - triangle.GetPoint(s, t);
                    JiggleMath.NormalizeSafe(ref triPointSTNorm);

                    Vector3 collisionN = (dist > float.Epsilon) ? triPointSTNorm : triangle.Normal;

                    // since impulse get applied at the old position
                    Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN;

                    if (numCollPts < MaxLocalStackSCPI)
                    {
                        // BEN-OPTIMISATION: Reuse existing collPts.
                        collPtArray[numCollPts].R0 = pt - body0Pos;
                        collPtArray[numCollPts].R1 = pt - body1Pos;
                        collPtArray[numCollPts++].InitialPenetration = depth;
                    }
                    collNormal += collisionN;
                }
            }

            if (numCollPts > 0)
            {
                JiggleMath.NormalizeSafe(ref collNormal);
                collisionFunctor.CollisionNotify(ref info, ref collNormal, collPtArray, numCollPts);
            }
            FreeStackAlloc(potTriArray);
            FreeStackAlloc(collPtArray);
        }
Пример #6
0
        /// <summary>
        /// DoOverlapBoxTriangleTest
        /// </summary>
        /// <param name="oldBox"></param>
        /// <param name="newBox"></param>
        /// <param name="triangle"></param>
        /// <param name="mesh"></param>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        /// <returns>bool</returns>
        private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox,
                                                     ref IndexedTriangle triangle, TriangleMesh mesh,
                                                     ref CollDetectInfo info, float collTolerance,
                                                     CollisionFunctor collisionFunctor)
        {
            Matrix4 dirs0 = newBox.Orientation;

            #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2)));
            Vector3 triVec0;
            Vector3 triVec1;
            Vector3 triVec2;
            mesh.GetVertex(triangle.GetVertexIndex(0), out triVec0);
            mesh.GetVertex(triangle.GetVertexIndex(1), out triVec1);
            mesh.GetVertex(triangle.GetVertexIndex(2), out triVec2);

            // Deano move tri into world space
            Matrix4 transformMatrix = mesh.TransformMatrix;
            Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0);
            Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1);
            Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2);

            Triangle tri = new Triangle(ref triVec0, ref triVec1, ref triVec2);
            #endregion


            #region REFERENCE Vector3 triEdge0 = (tri.GetPoint(1) - tri.GetPoint(0));
            Vector3 pt0;
            Vector3 pt1;
            tri.GetPoint(0, out pt0);
            tri.GetPoint(1, out pt1);

            Vector3 triEdge0;
            Vector3.Subtract(ref pt1, ref pt0, out triEdge0);
            #endregion

            #region REFERENCE Vector3 triEdge1 = (tri.GetPoint(2) - tri.GetPoint(1));
            Vector3 pt2;
            tri.GetPoint(2, out pt2);

            Vector3 triEdge1;
            Vector3.Subtract(ref pt2, ref pt1, out triEdge1);
            #endregion

            #region REFERENCE Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2));
            Vector3 triEdge2;
            Vector3.Subtract(ref pt0, ref pt2, out triEdge2);
            #endregion

            triEdge0.Normalize();
            triEdge1.Normalize();
            triEdge2.Normalize();


            // BEN-OPTIMISATION: Replaced loops with code that requires no looping.
            //                   The new code is faster, has less allocations and math especially
            //                   since the method returns as soon as it finds a non-overlapping axis,
            //                   i.e. Before irreleveat allocations occur.
            #region "Old (less efficient) code"

            /*Vector3 triNormal = triangle.Plane.Normal;
             *
             * // the 15 potential separating axes
             * const int numAxes = 13;
             * Vector3[] axes = new Vector3[numAxes];
             *
             * axes[0] = triNormal;
             * axes[1] = dirs0.Right;
             * axes[2] = dirs0.Up;
             * axes[3] = dirs0.Backward;
             * Vector3.Cross(ref axes[1], ref triEdge0, out axes[4]);
             * Vector3.Cross(ref axes[1], ref triEdge1, out axes[5]);
             * Vector3.Cross(ref axes[1], ref triEdge2, out axes[6]);
             * Vector3.Cross(ref axes[2], ref triEdge0, out axes[7]);
             * Vector3.Cross(ref axes[2], ref triEdge1, out axes[8]);
             * Vector3.Cross(ref axes[2], ref triEdge2, out axes[9]);
             * Vector3.Cross(ref axes[3], ref triEdge0, out axes[10]);
             * Vector3.Cross(ref axes[3], ref triEdge1, out axes[11]);
             * Vector3.Cross(ref axes[3], ref triEdge2, out axes[12]);
             *
             * // the overlap depths along each axis
             * float[] overlapDepths = new float[numAxes];
             *
             * // see if the boxes are separate along any axis, and if not keep a
             * // record of the depths along each axis
             * int i;
             * for (i = 0; i < numAxes; ++i)
             * {
             *  overlapDepths[i] = 1.0f;
             *  if (Disjoint(out overlapDepths[i], axes[i], newBox, tri, collTolerance))
             *      return false;
             * }
             *
             * // The box overlap, find the separation depth closest to 0.
             * float minDepth = float.MaxValue;
             * int minAxis = -1;
             *
             * for (i = 0; i < numAxes; ++i)
             * {
             *  // If we can't normalise the axis, skip it
             *  float l2 = axes[i].LengthSquared;
             *  if (l2 < JiggleMath.Epsilon)
             *      continue;
             *
             *  // Normalise the separation axis and the depth
             *  float invl = 1.0f / (float)System.Math.Sqrt(l2);
             *  axes[i] *= invl;
             *  overlapDepths[i] *= invl;
             *
             *  // If this axis is the minimum, select it
             *  if (overlapDepths[i] < minDepth)
             *  {
             *      minDepth = overlapDepths[i];
             *      minAxis = i;
             *  }
             * }
             *
             * if (minAxis == -1)
             *  return false;
             *
             * // Make sure the axis is facing towards the 0th box.
             * // if not, invert it
             * Vector3 D = newBox.GetCentre() - tri.Centre;
             * Vector3 N = axes[minAxis];
             * float depth = overlapDepths[minAxis];*/
            #endregion
            #region "Optimised code"
            Vector3 triNormal = triangle.Plane.Normal;
            Vector3 right     = dirs0.Right();
            Vector3 up        = dirs0.Up();
            Vector3 backward  = dirs0.Backward();

            float testDepth;

            if (Disjoint(out testDepth, ref triNormal, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            float   depth = testDepth;
            Vector3 N     = triNormal;

            if (Disjoint(out testDepth, ref right, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            if (testDepth < depth)
            {
                depth = testDepth;
                N     = right;
            }

            if (Disjoint(out testDepth, ref up, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            if (testDepth < depth)
            {
                depth = testDepth;
                N     = up;
            }

            if (Disjoint(out testDepth, ref backward, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            if (testDepth < depth)
            {
                depth = testDepth;
                N     = backward;
            }

            Vector3 axis;

            Vector3.Cross(ref right, ref triEdge0, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref right, ref triEdge1, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref right, ref triEdge2, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref up, ref triEdge0, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref up, ref triEdge1, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref up, ref triEdge2, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref backward, ref triEdge0, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref backward, ref triEdge1, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref backward, ref triEdge2, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            /*if (N == Vector3.Zero)
             *  return (false);*/

            Vector3 D = newBox.GetCentre() - tri.Centre;
            N.Normalize();
            int i;

            #endregion

            if (Vector3.Dot(D, N) < 0.0f)
            {
                N *= -1;
            }

            Vector3 boxOldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero;
            Vector3 meshPos   = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            List <Vector3> pts = new List <Vector3>();
            //pts.Clear();

            const float combinationDist = 0.05f;
            GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist);

            // adjust the depth
            #region REFERENCE: Vector3 delta = boxNewPos - boxOldPos;
            Vector3 delta;
            Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta);
            #endregion

            #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N);
            float oldDepth;
            Vector3.Dot(ref delta, ref N, out oldDepth);
            oldDepth += depth;
            #endregion

            unsafe
            {
                // report collisions
                int numPts = pts.Count;
#if USE_STACKALLOC
                SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
#else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed(SmallCollPointInfo *collPts = collPtArray)
#endif
                {
                    if (numPts > 0)
                    {
                        if (numPts >= MaxLocalStackSCPI)
                        {
                            numPts = MaxLocalStackSCPI - 1;
                        }

                        // adjust positions
                        for (i = 0; i < numPts; ++i)
                        {
                            // BEN-OPTIMISATION: Reused existing SmallCollPointInfo and inlined vector substraction.
                            collPts[i].R0.X = pts[i].X - boxNewPos.X;
                            collPts[i].R0.Y = pts[i].Y - boxNewPos.Y;
                            collPts[i].R0.Z = pts[i].Z - boxNewPos.Z;

                            collPts[i].R1.X = pts[i].X - meshPos.X;
                            collPts[i].R1.Y = pts[i].Y - meshPos.Y;
                            collPts[i].R1.Z = pts[i].Z - meshPos.Z;

                            collPts[i].InitialPenetration = oldDepth;
                        }

                        collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts);
#if !USE_STACKALLOC
                        FreeStackAlloc(collPtArray);
#endif
                        return(true);
                    }
                    else
                    {
#if !USE_STACKALLOC
                        FreeStackAlloc(collPtArray);
#endif
                        return(false);
                    }
                }
            }
        }
Пример #7
0
        /// <summary>
        /// GetLocalSkinWireframe
        /// </summary>
        /// <param name="skin"></param>
        /// <returns>VertexPositionColor[]</returns>
        public static VertexPositionColor[] GetLocalSkinWireframe(this CollisionSkin skin)
        {
            List <VertexPositionColor> wireframe = new List <VertexPositionColor>();

            // skip if there is no collision skin
            if (skin == null)
            {
                return(wireframe.ToArray());
            }


            for (int i = 0; i < skin.NumPrimitives; i++)
            {
                Primitive p     = skin.GetPrimitiveLocal(i);
                Matrix    trans = p.TransformMatrix;

                if (p is Sphere)
                {
                    Sphere np = (Sphere)p;

                    List <Vector3> SpherePoints = calcCirclePoints(np.Radius);

                    AddShapeToWireframe(SpherePoints, wireframe, trans, Color.Blue);
                    AddShapeToWireframe(SpherePoints, wireframe, Matrix.CreateRotationY(MathHelper.PiOver2) * trans, Color.Red);
                    AddShapeToWireframe(SpherePoints, wireframe, Matrix.CreateRotationX(MathHelper.PiOver2) * trans, Color.Green);
                }
                else if (p is Capsule)
                {
                    Capsule np = (Capsule)p;

                    List <Vector3> Ball         = calcCirclePoints(np.Radius);
                    List <Vector3> CylPoints    = new List <Vector3>();
                    List <Vector3> CirclePoints = new List <Vector3>();
                    List <Vector3> SidePoints   = new List <Vector3>();

                    // Create LongWays profile slice
                    foreach (Vector3 v in Ball)
                    {
                        Vector3 t = Vector3.Transform(v, Matrix.CreateRotationX(MathHelper.PiOver2));
                        CylPoints.Add(t);
                    }

                    float len = np.Length;

                    SidePoints.Add(Vector3.Transform(new Vector3(np.Radius, len, 0), Matrix.CreateRotationX(MathHelper.PiOver2)));
                    SidePoints.Add(Vector3.Transform(new Vector3(np.Radius, 0, 0), Matrix.CreateRotationX(MathHelper.PiOver2)));
                    SidePoints.Add(Vector3.Transform(new Vector3(-np.Radius, 0, 0), Matrix.CreateRotationX(MathHelper.PiOver2)));
                    SidePoints.Add(Vector3.Transform(new Vector3(-np.Radius, len, 0), Matrix.CreateRotationX(MathHelper.PiOver2)));

                    // Create Y Rungs
                    AddShapeToWireframe(Ball, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0.0f * len)) * trans, Color.Green);
                    AddShapeToWireframe(Ball, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0.5f * np.Length)) * trans, Color.Green);
                    AddShapeToWireframe(Ball, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 1.0f * np.Length)) * trans, Color.Green);

                    // Create Z Profile
                    Matrix Zmat = Matrix.CreateRotationZ(MathHelper.PiOver2);
                    AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, np.Length)) * Zmat * trans, Color.Blue);
                    AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0)) * Zmat * trans, Color.Blue);
                    AddLineToWireframe(SidePoints[0], SidePoints[1], wireframe, Zmat * trans, Color.Blue);
                    AddLineToWireframe(SidePoints[2], SidePoints[3], wireframe, Zmat * trans, Color.Blue);

                    //// Create X Profile
                    Matrix Xmat = Matrix.Identity;
                    AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, np.Length)) * Xmat * trans, Color.Red);
                    AddShapeToWireframe(CylPoints, wireframe, Matrix.CreateTranslation(new Vector3(0, 0, 0)) * Xmat * trans, Color.Red);
                    AddLineToWireframe(SidePoints[0], SidePoints[1], wireframe, Xmat * trans, Color.Red);
                    AddLineToWireframe(SidePoints[2], SidePoints[3], wireframe, Xmat * trans, Color.Red);
                }
                else if (p is Box)
                {
                    Box np = (Box)p;

                    List <Vector3> xPoints = new List <Vector3>();
                    List <Vector3> yPoints = new List <Vector3>();
                    List <Vector3> zPoints = new List <Vector3>();

                    Vector3 slen = np.SideLengths;

                    xPoints.Add(new Vector3(slen.X, slen.Y, slen.Z));
                    xPoints.Add(new Vector3(0, slen.Y, slen.Z));
                    xPoints.Add(new Vector3(slen.X, 0, slen.Z));
                    xPoints.Add(new Vector3(0, 0, slen.Z));
                    xPoints.Add(new Vector3(slen.X, slen.Y, 0));
                    xPoints.Add(new Vector3(0, slen.Y, 0));
                    xPoints.Add(new Vector3(slen.X, 0, 0));
                    xPoints.Add(new Vector3(0, 0, 0));

                    yPoints.Add(new Vector3(slen.X, slen.Y, slen.Z));
                    yPoints.Add(new Vector3(slen.X, 0, slen.Z));
                    yPoints.Add(new Vector3(0, slen.Y, slen.Z));
                    yPoints.Add(new Vector3(0, 0, slen.Z));
                    yPoints.Add(new Vector3(slen.X, slen.Y, 0));
                    yPoints.Add(new Vector3(slen.X, 0, 0));
                    yPoints.Add(new Vector3(0, slen.Y, 0));
                    yPoints.Add(new Vector3(0, 0, 0));

                    zPoints.Add(new Vector3(slen.X, slen.Y, slen.Z));
                    zPoints.Add(new Vector3(slen.X, slen.Y, 0));
                    zPoints.Add(new Vector3(0, slen.Y, slen.Z));
                    zPoints.Add(new Vector3(0, slen.Y, 0));
                    zPoints.Add(new Vector3(slen.X, 0, slen.Z));
                    zPoints.Add(new Vector3(slen.X, 0, 0));
                    zPoints.Add(new Vector3(0, 0, slen.Z));
                    zPoints.Add(new Vector3(0, 0, 0));

                    AddLinesToWireframe(xPoints, wireframe, trans, Color.Red);
                    AddLinesToWireframe(yPoints, wireframe, trans, Color.Green);
                    AddLinesToWireframe(zPoints, wireframe, trans, Color.Blue);
                }
                else if (p is AABox)
                {
                }
                else if (p is Heightmap)
                {
                    Heightmap hm = (Heightmap)p;
                    Vector3   point, normal;

                    for (int e = 0; e < hm.Heights.Nx; e += 5)
                    {
                        for (int j = 0; j < hm.Heights.Nz; j += 5)
                        {
                            hm.GetSurfacePosAndNormal(out point, out normal, e, j);
                            AddLineToWireframe(point, point - 0.5f * normal, wireframe, trans, Color.GreenYellow);
                        }
                    }
                }
                else if (p is JigLibX.Geometry.Plane)
                {
                }
                else if (p is TriangleMesh)
                {
                    TriangleMesh np = (TriangleMesh)p;

                    for (int j = 0; j < np.GetNumTriangles(); j++)
                    {
                        IndexedTriangle t = np.GetTriangle(j);

                        Vector3 p1 = np.GetVertex(t.GetVertexIndex(0));
                        Vector3 p2 = np.GetVertex(t.GetVertexIndex(1));
                        Vector3 p3 = np.GetVertex(t.GetVertexIndex(2));

                        List <Vector3> tPoints = new List <Vector3>();

                        tPoints.Add(p1);
                        tPoints.Add(p2);
                        tPoints.Add(p3);
                        tPoints.Add(p1);

                        AddShapeToWireframe(tPoints, wireframe, trans, Color.Red);
                    }
                }
            }

            return(wireframe.ToArray());
        }
Пример #8
0
 public static void WriteInAllocatedMemoryImpl(BinaryWriter writer, MemoryPool memory, IndexedTriangle t)
 {
     writer.Write((UInt16)t.IDX0);
     writer.Write((UInt16)t.IDX1);
     writer.Write((UInt16)t.IDX2);
 }
Пример #9
0
 public static uint GetElementSizeImpl(IndexedTriangle t) => 2 * 3;
Пример #10
0
        private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox, ref IndexedTriangle triangle, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            var dirs0 = newBox.Orientation;

            mesh.GetVertex(triangle.GetVertexIndex(0), out var triVec0);
            mesh.GetVertex(triangle.GetVertexIndex(1), out var triVec1);
            mesh.GetVertex(triangle.GetVertexIndex(2), out var triVec2);


            var transformMatrix = mesh.TransformMatrix;

            Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0);
            Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1);
            Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2);

            var tri = new Triangle(ref triVec0, ref triVec1, ref triVec2);


            tri.GetPoint(0, out var pt0);
            tri.GetPoint(1, out var pt1);

            Vector3.Subtract(ref pt1, ref pt0, out var triEdge0);

            tri.GetPoint(2, out var pt2);

            Vector3.Subtract(ref pt2, ref pt1, out var triEdge1);

            Vector3.Subtract(ref pt0, ref pt2, out var triEdge2);

            triEdge0.Normalize();
            triEdge1.Normalize();
            triEdge2.Normalize();

            var triNormal = triangle.Plane.Normal;
            var right     = dirs0.Right;
            var up        = dirs0.Up;
            var backward  = dirs0.Backward;

            if (Disjoint(out var testDepth, ref triNormal, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            var depth = testDepth;
            var N     = triNormal;

            if (Disjoint(out testDepth, ref right, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            if (testDepth < depth)
            {
                depth = testDepth;
                N     = right;
            }

            if (Disjoint(out testDepth, ref up, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            if (testDepth < depth)
            {
                depth = testDepth;
                N     = up;
            }

            if (Disjoint(out testDepth, ref backward, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            if (testDepth < depth)
            {
                depth = testDepth;
                N     = backward;
            }

            Vector3.Cross(ref right, ref triEdge0, out var axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref right, ref triEdge1, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref right, ref triEdge2, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref up, ref triEdge0, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref up, ref triEdge1, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref up, ref triEdge2, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref backward, ref triEdge0, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref backward, ref triEdge1, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            Vector3.Cross(ref backward, ref triEdge2, out axis);
            if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance))
            {
                return(false);
            }

            testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
            if (testDepth < depth)
            {
                depth = testDepth;
                N     = axis;
            }

            var D = newBox.GetCentre() - tri.Centre;

            N.Normalize();
            int i;

            if (Vector3.Dot(D, N) < 0.0f)
            {
                N *= -1;
            }

            var boxOldPos = info.Skin0.Owner?.OldPosition ?? Vector3.Zero;
            var boxNewPos = info.Skin0.Owner?.Position ?? Vector3.Zero;
            var meshPos   = info.Skin1.Owner?.OldPosition ?? Vector3.Zero;

            var pts = new List <Vector3>();


            const float combinationDist = 0.05f;

            GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist);


            Vector3.Subtract(ref boxNewPos, ref boxOldPos, out var delta);

            Vector3.Dot(ref delta, ref N, out var oldDepth);
            oldDepth += depth;

            unsafe
            {
                var numPts  = pts.Count;
                var collPts = stackalloc SmallCollPointInfo[MaxLocalStackScpi];
                {
                    if (numPts > 0)
                    {
                        if (numPts >= MaxLocalStackScpi)
                        {
                            numPts = MaxLocalStackScpi - 1;
                        }


                        for (i = 0; i < numPts; ++i)
                        {
                            collPts[i].R0.X = pts[i].X - boxNewPos.X;
                            collPts[i].R0.Y = pts[i].Y - boxNewPos.Y;
                            collPts[i].R0.Z = pts[i].Z - boxNewPos.Z;

                            collPts[i].R1.X = pts[i].X - meshPos.X;
                            collPts[i].R1.Y = pts[i].Y - meshPos.Y;
                            collPts[i].R1.Z = pts[i].Z - meshPos.Z;

                            collPts[i].InitialPenetration = oldDepth;
                        }

                        collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts);
                        return(true);
                    }
                    return(false);
                }
            }
        }
Пример #11
0
        public MeshData Convert(PlyReader reader, PlyHeader header)
        {
            var normalizedHeader = new PlyHeaderNormalizer(header);

            var elements = normalizedHeader.BaseHeader.Elements;

            var faces = new List <IndexedTriangle>(elements[normalizedHeader.FacesId].InstanceCount);

            var meshData = new MeshData
            {
                Vertices = new Vector3[elements[normalizedHeader.VerticesId].InstanceCount],
                Faces    = null,
                Normals  = new Vector3[normalizedHeader.NormalsId == -1 ? 0 : elements[normalizedHeader.NormalsId].InstanceCount]
            };

            int currVertex            = 0;
            int currVertexPropWritten = 0;
            int currNormal            = 0;
            int currNormalPropWritten = 0;
            int currFace = 0;

            // calling progressReporter.Report is expensive, limit it.
            long totalLoad            = meshData.Vertices.Length + faces.Capacity + meshData.Normals.Length;
            int  lastProgressReported = 10;

            // since the structure of the file is not known
            // and will be determined at the runtime
            // we don't know what elements and properties come first.
            // not the prettiest but definitely the fastest way to do this.
            for (int i = 0; i < elements.Count; ++i)
            {
                for (int j = 0; j < elements[i].InstanceCount; ++j)
                {
                    // call the progressReporter function on every 10% progress
                    int progress = (int)((currVertex + currNormal + currFace) * 100 / totalLoad);
                    if (progress > lastProgressReported + 10 && ProgressReporter != null)
                    {
                        ProgressReporter.Report(progress);
                        lastProgressReported = progress;
                    }

                    // go through every property of the current element
                    for (int k = 0; k < elements[i].Properties.Count; ++k)
                    {
                        bool ignored = true;

                        // if the current element was found by the normalizedHeader
                        // to be a vertex element, parse the vertices
                        if (i == normalizedHeader.VerticesId)
                        {
                            if (k == normalizedHeader.VertexX)
                            {
                                meshData.Vertices[currVertex].X = reader.ReadProperty <float>();
                                currVertexPropWritten++;
                                ignored = false;
                            }
                            else if (k == normalizedHeader.VertexY)
                            {
                                meshData.Vertices[currVertex].Y = reader.ReadProperty <float>();
                                currVertexPropWritten++;
                                ignored = false;
                            }
                            else if (k == normalizedHeader.VertexZ)
                            {
                                meshData.Vertices[currVertex].Z = reader.ReadProperty <float>();
                                currVertexPropWritten++;
                                ignored = false;
                            }
                            if (currVertexPropWritten == 3)
                            {
                                currVertexPropWritten = 0;
                                currVertex++;
                            }
                        }
                        // if it is a normal element..
                        if (i == normalizedHeader.NormalsId)
                        {
                            if (k == normalizedHeader.NormalX)
                            {
                                meshData.Normals[currNormal].X = reader.ReadProperty <float>();
                                currNormalPropWritten++;
                                ignored = false;
                            }
                            else if (k == normalizedHeader.NormalY)
                            {
                                meshData.Normals[currNormal].X = reader.ReadProperty <float>();
                                currNormalPropWritten++;
                                ignored = false;
                            }
                            else if (k == normalizedHeader.NormalZ)
                            {
                                meshData.Normals[currNormal].X = reader.ReadProperty <float>();
                                currNormalPropWritten++;
                                ignored = false;
                            }
                            if (currNormalPropWritten == 3)
                            {
                                currNormal++;
                                currNormalPropWritten = 0;
                            }
                        }
                        // if it is a face element..
                        if (i == normalizedHeader.FacesId)
                        {
                            if (k == normalizedHeader.VerticesId)
                            {
                                // read the vertices of a face
                                List <int> verts = new List <int>(3);
                                foreach (int index in reader.ReadArray <int>())
                                {
                                    verts.Add(index);
                                }

                                // if we got 3 vertices, its a normal triangle
                                // and the triangle to the list
                                if (verts.Count == 3)
                                {
                                    var t = new IndexedTriangle
                                    {
                                        Vertex1 = verts[0],
                                        Vertex2 = verts[1],
                                        Vertex3 = verts[2]
                                    };
                                    faces.Add(t);
                                }
                                else if (verts.Count == 4)
                                {
                                    faces.Add(new IndexedTriangle(verts[0], verts[1], verts[3]));
                                    faces.Add(new IndexedTriangle(verts[1], verts[2], verts[3]));
                                }
                                else
                                {
                                    throw new NotSupportedException("Only triangular faces are currently supported.");
                                }
                                currFace++;
                                ignored = false;
                            }
                        }
                        if (ignored)
                        {
                            reader.SkipProperty();
                        }
                    }
                }
            }

            meshData.Faces = faces.ToArray();

            if (meshData.Normals.Length == 0)
            {
                meshData.Normals = null;
            }

            ProgressReporter?.Report(100);
            return(meshData);
        }