Exemple #1
0
        /// <summary>
        /// DetectAllCollisions
        /// </summary>
        /// <param name="bodies"></param>
        /// <param name="collisionFunctor"></param>
        /// <param name="collisionPredicate"></param>
        /// <param name="collTolerance"></param>
        public override void DetectAllCollisions(List <JigLibX.Physics.Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            skinTester_.Set(this, collisionFunctor, collisionPredicate, collTolerance);

            MaybeSort();
            //  I know that each skin for the bodies is already in my list of skins.
            //  Thus, I can do collision between all skins, culling out non-active bodies.
            int nSkins = skins_.Count;

            active_.Clear();

#if WINDOWS_PHONE
            for (int i = 0; i != nSkins; ++i)
            {
                AddToActive(skins_[i], skinTester_);
            }
#else
            // BEN-OPTIMISATION: unsafe, remove array boundary checks.
            unsafe
            {
                for (int i = 0; i != nSkins; ++i)
                {
                    AddToActive(skins_[i], skinTester_);
                }
            }
#endif
        }
Exemple #2
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(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;

            // todo - proper swept test
            Capsule oldCapsule0 = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule0 = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;
            Segment oldSeg0     = new Segment(oldCapsule0.Position, oldCapsule0.Length * oldCapsule0.Orientation.Backward);
            Segment newSeg0     = new Segment(newCapsule0.Position, newCapsule0.Length * newCapsule0.Orientation.Backward);

            Capsule oldCapsule1 = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Capsule;
            Capsule newCapsule1 = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Capsule;
            Segment oldSeg1     = new Segment(oldCapsule1.Position, oldCapsule1.Length * oldCapsule1.Orientation.Backward);
            Segment newSeg1     = new Segment(newCapsule1.Position, newCapsule1.Length * newCapsule1.Orientation.Backward);

            float radSum = newCapsule0.Radius + newCapsule1.Radius;

            float oldt0, oldt1;
            float newt0, newt1;
            float oldDistSq = Distance.SegmentSegmentDistanceSq(out oldt0, out oldt1, oldSeg0, oldSeg1);
            float newDistSq = Distance.SegmentSegmentDistanceSq(out newt0, out newt1, newSeg0, newSeg1);

            if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance)))
            {
                Vector3 pos0 = oldSeg0.GetPoint(oldt0);
                Vector3 pos1 = oldSeg1.GetPoint(oldt1);

                Vector3 delta = pos0 - pos1;

                float dist  = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radSum - dist;

                if (dist > JiggleMath.Epsilon)
                {
                    delta /= dist;
                }
                else
                {
                    // todo - make this not random
                    delta = Vector3.TransformNormal(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = pos1 +
                                   (oldCapsule1.Radius - 0.5f * depth) * delta;

#if WINDOWS_PHONE
                this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);
                collisionFunctor.CollisionNotify(ref info, ref delta, this.collInfo, 1);
#else
                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);
                    collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1);
                }
#endif
            }
        }
Exemple #3
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);
        }
Exemple #4
0
        private void CollDetectOverlap(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh, ref info, collTolerance, collisionFunctor);
        }
Exemple #5
0
        public override void CollDetect(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;

            // todo - proper swept test
            Capsule oldCapsule0 = (Capsule)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Capsule newCapsule0 = (Capsule)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);
            Segment oldSeg0 = new Segment(oldCapsule0.Position, oldCapsule0.Length * oldCapsule0.Orientation.Backward);
            Segment newSeg0 = new Segment(newCapsule0.Position, newCapsule0.Length * newCapsule0.Orientation.Backward);

            Capsule oldCapsule1 = (Capsule)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            Capsule newCapsule1 = (Capsule)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);
            Segment oldSeg1 = new Segment(oldCapsule1.Position, oldCapsule1.Length * oldCapsule1.Orientation.Backward);
            Segment newSeg1 = new Segment(newCapsule1.Position, newCapsule1.Length * newCapsule1.Orientation.Backward);

            float radSum = newCapsule0.Radius + newCapsule1.Radius;

            float oldt0, oldt1;
            float newt0, newt1;
            float oldDistSq = Distance.SegmentSegmentDistanceSq(out oldt0, out oldt1, oldSeg0, oldSeg1);
            float newDistSq = Distance.SegmentSegmentDistanceSq(out newt0, out newt1, newSeg0, newSeg1);

            if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance)))
            {
                Vector3 pos0 = oldSeg0.GetPoint(oldt0);
                Vector3 pos1 = oldSeg1.GetPoint(oldt1);

                Vector3 delta = pos0 - pos1;

                float dist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radSum - dist;

                if (dist > JiggleMath.Epsilon)
                {
                    delta /= dist;
                }
                else
                {
                    // todo - make this not random
                    delta = Vector3.Transform(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = pos1 +
                    (oldCapsule1.Radius - 0.5f * depth) * delta;

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);
                    collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1);
                }

            }
        }
Exemple #6
0
        /// <summary>
        /// CollDetectSweep
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        private void CollDetectSweep(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;

            // todo - proper swept test
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            CollDetectCapsulseStaticMeshSweep(oldCapsule, newCapsule, mesh, info, collTolerance, collisionFunctor);
        }
Exemple #7
0
        /// <summary>
        /// DetectCollisions
        /// </summary>
        /// <param name="body"></param>
        /// <param name="collisionFunctor"></param>
        /// <param name="collisionPredicate"></param>
        /// <param name="collTolerance"></param>
        public override void DetectCollisions(JigLibX.Physics.Body body, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            if (!body.IsActive)
            {
                return;
            }

            CollDetectInfo info = new CollDetectInfo();

            info.Skin0 = body.CollisionSkin;
            if (info.Skin0 == null)
            {
                return;
            }

            active_.Clear();
            testing_.Clear();
            Extract(info.Skin0.WorldBoundingBox.Min, info.Skin0.WorldBoundingBox.Max, active_);

            for (int j = 0, m = info.Skin0.NumPrimitives; j != m; ++j)
            {
                testing_.Add(info.Skin0.GetPrimitiveNewWorld(j));
            }

            int nBodyPrims = testing_.Count;

            for (int i = 0, n = active_.Count; i != n; ++i)
            {
                info.Skin1 = active_[i];
                if (info.Skin0 != info.Skin1 && (collisionPredicate == null ||
                                                 collisionPredicate.ConsiderSkinPair(info.Skin0, info.Skin1)))
                {
                    int nPrim1 = info.Skin1.NumPrimitives;
                    second_.Clear();
                    for (int k = 0; k != nPrim1; ++k)
                    {
                        second_.Add(info.Skin1.GetPrimitiveNewWorld(k));
                    }
                    for (info.IndexPrim0 = 0; info.IndexPrim0 != nBodyPrims; ++info.IndexPrim0)
                    {
                        for (info.IndexPrim1 = 0; info.IndexPrim1 != nPrim1; ++info.IndexPrim1)
                        {
                            DetectFunctor f =
                                GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type,
                                                     info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type);
                            if (f != null)
                            {
                                f.CollDetect(info, collTolerance, collisionFunctor);
                            }
                        }
                    }
                }
            }
        }
Exemple #8
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            JigLibX.Geometry.Plane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JigLibX.Geometry.Plane;
            JigLibX.Geometry.Plane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JigLibX.Geometry.Plane;

            Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

            Vector3 oldSpherePos = Vector3.Transform(oldSphere.Position, oldPlaneInvTransform);
            Vector3 newSpherePos = Vector3.Transform(newSphere.Position, newPlaneInvTransform);

            // consider it a contact if either old or new are touching
            float oldDist = Distance.PointPlaneDistance(oldSpherePos, oldPlane);
            float newDist = Distance.PointPlaneDistance(newSpherePos, newPlane);

            if (System.Math.Min(newDist, oldDist) > collTolerance + newSphere.Radius)
            {
                return;
            }

            // collision - record depth using the old values
            float oldDepth = oldSphere.Radius - oldDist;

            // calc the world position based on the old position(s)
            Vector3 worldPos = oldSphere.Position - oldSphere.Radius * oldPlane.Normal;

#if WINDOWS_PHONE
            this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
            collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, this.collInfo, 1);
#else
            unsafe
            {
                SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, &collInfo, 1);
            }
#endif
        }
Exemple #9
0
 /// <summary>
 /// Set
 /// </summary>
 /// <param name="sys"></param>
 /// <param name="collisionFunctor"></param>
 /// <param name="collisionPredicate"></param>
 /// <param name="collTolerance"></param>
 internal void Set(CollisionSystem sys, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
 {
     sys_ = sys;
     collisionFunctor_   = collisionFunctor;
     collisionPredicate_ = collisionPredicate;
     if (collisionPredicate_ == null)
     {
         collisionPredicate_ = this;
     }
     collTolerance_ = collTolerance;
 }
Exemple #10
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(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;

            // todo - proper swept test
            Sphere oldSphere0 = (Sphere)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Sphere newSphere0 = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);
            Sphere oldSphere1 = (Sphere)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            Sphere newSphere1 = (Sphere)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            Vector3 oldDelta = oldSphere0.Position - oldSphere1.Position;
            Vector3 newDelta = newSphere0.Position - oldSphere1.Position;

            float oldDistSq = oldDelta.LengthSquared();
            float newDistSq = newDelta.LengthSquared();

            float radSum = newSphere0.Radius + newSphere1.Radius;

            if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance)))
            {
                float oldDist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth   = radSum - oldDist;

                if (oldDist > JiggleMath.Epsilon)
                {
                    oldDelta /= oldDist;
                }
                else
                {
                    // TODO - make this not random...!
                    oldDelta = Vector3.TransformNormal(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = oldSphere1.Position +
                                   (oldSphere1.Radius - 0.5f * depth) * oldDelta;

#if WINDOWS_PHONE
                this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);

                collisionFunctor.CollisionNotify(ref info, ref oldDelta, this.collInfo, 1);
#else
                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref oldDelta, &collInfo, 1);
                }
#endif
            }
        }
Exemple #11
0
        /// <summary>
        /// CollDetectOverlap
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        private void CollDetectOverlap(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // todo - proper swept test
            Sphere         oldSphere  = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere         newSphere  = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;
            BoundingSphere oldBSphere = new BoundingSphere(oldSphere.Position, oldSphere.Radius);
            BoundingSphere newBSphere = new BoundingSphere(newSphere.Position, newSphere.Radius);

            // todo - proper swept test
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            CollDetectSphereStaticMeshOverlap(oldBSphere, newBSphere, mesh, info, collTolerance, collisionFunctor);
        }
        public override void DetectAllCollisions(List <JigLibX.Physics.Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            skinTester_.Set(this, collisionFunctor, collisionPredicate, collTolerance);
            MaybeSort();
            //  I know that each skin for the bodies is already in my list of skins.
            //  Thus, I can do collision between all skins, culling out non-active bodies.
            int nSkins = skins_.Count;

            active_.Clear();
            //  sweep the sorted list for potential overlaps
            for (int i = 0; i != nSkins; ++i)
            {
                AddToActive(skins_[i], skinTester_);
            }
        }
Exemple #13
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere = (Sphere)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Sphere newSphere = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);

            JigLibX.Geometry.Plane oldPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            JigLibX.Geometry.Plane newPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

            Vector3 oldSpherePos = Vector3.Transform(oldSphere.Position, oldPlaneInvTransform);
            Vector3 newSpherePos = Vector3.Transform(newSphere.Position, newPlaneInvTransform);

            // consider it a contact if either old or new are touching
            float oldDist = Distance.PointPlaneDistance(oldSpherePos, oldPlane);
            float newDist = Distance.PointPlaneDistance(newSpherePos, newPlane);

            if (System.Math.Min(newDist, oldDist) > collTolerance + newSphere.Radius)
                return;

            // collision - record depth using the old values
            float oldDepth = oldSphere.Radius - oldDist;

            // calc the world position based on the old position(s)
            Vector3 worldPos = oldSphere.Position - oldSphere.Radius * oldPlane.Normal;

            unsafe
            {
                SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, &collInfo, 1);
            }
        }
        /// <summary>
        /// Detect BoxStaticMesh Collisions.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            if (info.Skin0.CollisionSystem != null && info.Skin0.CollisionSystem.UseSweepTests)
                CollDetectSweep(ref info, collTolerance, collisionFunctor);
            else
                CollDetectOverlap(ref info, collTolerance, collisionFunctor);
        }
Exemple #15
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(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;

            // todo - proper swept test
            Sphere oldSphere0 = (Sphere) info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Sphere newSphere0 = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);
            Sphere oldSphere1 = (Sphere)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            Sphere newSphere1 = (Sphere)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            Vector3 oldDelta = oldSphere0.Position - oldSphere1.Position;
            Vector3 newDelta = newSphere0.Position - oldSphere1.Position;

            float oldDistSq = oldDelta.LengthSquared;
            float newDistSq = newDelta.LengthSquared;

            float radSum = newSphere0.Radius + newSphere1.Radius;

            if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance)))
            {
                float oldDist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radSum - oldDist;

                if (oldDist > JiggleMath.Epsilon)
                {
                    oldDelta /= oldDist;
                }
                else
                {
                    // TODO - make this not random...!
                    oldDelta = Vector3Extensions.TransformNormal(Vector3Extensions.Backward, Matrix4.CreateFromAxisAngle(Vector3Extensions.Up, OpenTKHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = oldSphere1.Position +
                    (oldSphere1.Radius - 0.5f * depth) * oldDelta;

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref oldDelta, &collInfo, 1);
                }
            }
        }
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // get the skins in the order that we're expecting
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            if((info.Skin0.CollisionSystem != null) && info.Skin0.CollisionSystem.UseSweepTests)
                CollDetectSweep(info, collTolerance, collisionFunctor);
            else
                CollDetectOverlap(info, collTolerance, collisionFunctor);
        }
Exemple #17
0
        public override void DetectAllCollisions(List <Physics.Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            skinTester_.Set(this, collisionFunctor, collisionPredicate, collTolerance);

            MaybeSort();


            var nSkins = skins_.Count;

            active_.Clear();


            unsafe
            {
                for (var i = 0; i != nSkins; ++i)
                {
                    AddToActive(skins_[i], skinTester_);
                }
            }
        }
Exemple #18
0
        public override void DetectCollisions(Body body, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            if (!body.IsActive)
            {
                return;
            }

            CollDetectInfo info = new CollDetectInfo();

            info.Skin0 = body.CollisionSkin; //?!
            if (info.Skin0 == null)
            {
                return;
            }

            int bodyPrimitves = info.Skin0.NumPrimitives;
            int numSkins      = skins.Count;

            for (int skin = 0; skin < numSkins; ++skin)
            {
                info.Skin1 = skins[skin];
                if ((info.Skin0 != info.Skin1) && CheckCollidables(info.Skin0, info.Skin1))
                {
                    int primitives = info.Skin1.NumPrimitives;

                    for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitves; ++info.IndexPrim0)
                    {
                        for (info.IndexPrim1 = 0; info.IndexPrim1 < primitives; ++info.IndexPrim1)
                        {
                            DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type,
                                                                   info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type);

                            if (f != null)
                            {
                                f.CollDetect(info, collTolerance, collisionFunctor);
                            }
                        }
                    }
                }
            }
        }
Exemple #19
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere = (Sphere)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Sphere newSphere = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);

            Heightmap oldHeightmap = (Heightmap)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            Heightmap newHeightmap = (Heightmap)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            float newDist;
            Vector3 normal;
            newHeightmap.GetHeightAndNormal(out newDist, out normal,newSphere.Position);
            if (newDist < collTolerance + newSphere.Radius)
            {
                float oldDist = oldHeightmap.GetHeight(oldSphere.Position);
                float depth = oldSphere.Radius - oldDist;

                // calc the world position when it just hit
                Vector3 oldPt = oldSphere.Position - oldSphere.Radius * normal;
                unsafe
                {
                    SmallCollPointInfo ptInfo = new SmallCollPointInfo(oldPt - body0Pos, oldPt - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref normal, &ptInfo, 1);
                }
            }
        }
Exemple #20
0
        /// <summary>
        /// Detect BoxStaticMesh Collisions.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            if (info.Skin0.CollisionSystem != null && info.Skin0.CollisionSystem.UseSweepTests)
            {
                CollDetectSweep(ref info, collTolerance, collisionFunctor);
            }
            else
            {
                CollDetectOverlap(ref info, collTolerance, collisionFunctor);
            }
        }
Exemple #21
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // get the skins in the order that we're expecting
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            if ((info.Skin0.CollisionSystem != null) && info.Skin0.CollisionSystem.UseSweepTests)
            {
                CollDetectSweep(info, collTolerance, collisionFunctor);
            }
            else
            {
                CollDetectOverlap(info, collTolerance, collisionFunctor);
            }
        }
Exemple #22
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // get the skins in the order that we're expectiing
            CollDetectInfo info = infoOrig;

            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;
            Segment oldSeg     = new Segment(oldCapsule.Position, oldCapsule.Length * oldCapsule.Orientation.Backward());
            Segment newSeg     = new Segment(newCapsule.Position, newCapsule.Length * newCapsule.Orientation.Backward());

            float radius = oldCapsule.Radius;

            Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;
            Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            float oldSegT;
            float oldBoxT0, oldBoxT1, oldBoxT2;
            float oldDistSq = Distance.SegmentBoxDistanceSq(out oldSegT, out oldBoxT0, out oldBoxT1, out oldBoxT2, oldSeg, oldBox);
            float newSegT;
            float newBoxT0, newBoxT1, newBoxT2;
            float newDistSq = Distance.SegmentBoxDistanceSq(out newSegT, out newBoxT0, out newBoxT1, out newBoxT2, newSeg, newBox);

            if (OpenTKHelper.Min(oldDistSq, newDistSq) < ((radius + collTolerance) * (radius + collTolerance)))
            {
                Vector3 segPos = oldSeg.GetPoint(oldSegT);
                Vector3 boxPos = oldBox.GetCentre() + oldBoxT0 * oldBox.Orientation.Right() +
                                 oldBoxT1 * oldBox.Orientation.Up() + oldBoxT2 * oldBox.Orientation.Backward();

                float dist  = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radius - dist;

                Vector3 dir;

                if (dist > JiggleMath.Epsilon)
                {
                    dir = segPos - boxPos;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else if ((segPos - oldBox.GetCentre()).LengthSquared > JiggleMath.Epsilon)
                {
                    dir = segPos - oldBox.GetCentre();
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else
                {
                    // todo - make this not random
                    dir = Vector3.Transform(Vector3Extensions.Backward, Matrix4.CreateFromAxisAngle(Vector3Extensions.Up, OpenTKHelper.ToRadians(random.Next(360))));
                }

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(boxPos - body0Pos, boxPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1);
                }
            }
        }
Exemple #23
0
 /// <summary>
 /// As DetectCollisions but detects for all bodies, testing each pair
 /// only once
 /// </summary>
 /// <param name="bodies"></param>
 /// <param name="collisionFunctor"></param>
 /// <param name="collisionPredicate"></param>
 /// <param name="collTolerance"></param>
 public abstract void DetectAllCollisions(List <Body> bodies, CollisionFunctor collisionFunctor,
                                          CollisionSkinPredicate2 collisionPredicate, float collTolerance);
Exemple #24
0
 /// <summary>
 /// Detects all collisions between the body and all the registered
 /// collision skins (which should have already had their
 /// positions/bounding volumes etc updated).  For each potential
 /// pair of skins then the predicate (if it exists) will be called
 /// to see whether or not to continue. If the skins are closer
 /// than collTolerance (+ve value means report objects that aren't
 /// quite colliding) then the functor will get called.
 /// You can't just loop over all your bodies calling this, because 
 /// that will double-detect collisions. Use DetectAllCollisions for 
 /// that.
 /// </summary>
 public abstract void DetectCollisions(Body body, CollisionFunctor collisionFunctor,
     CollisionSkinPredicate2 collisionPredicate, float collTolerance);
Exemple #25
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Capsule oldCapsule = (Capsule)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Capsule newCapsule = (Capsule)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);

            JigLibX.Geometry.Plane oldPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            JigLibX.Geometry.Plane newPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

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

                    // the start
                    {
                        Vector3 oldCapsuleStartPos = Vector3.Transform(oldCapsule.Position, oldPlaneInvTransform);
                        Vector3 newCapsuleStartPos = Vector3.Transform(newCapsule.Position, newPlaneInvTransform);

                        float oldDist = Distance.PointPlaneDistance(oldCapsuleStartPos, oldPlane);
                        float newDist = Distance.PointPlaneDistance(newCapsuleStartPos, newPlane);

                        if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position8(s)
                            Vector3 worldPos = oldCapsule.Position - oldCapsule.Radius * oldPlane.Normal;

                            // BEN-OPTIMISATION: Now reuses existing collPts instead of reallocating.
                            collPts[numCollPts].R0 = worldPos - body0Pos;
                            collPts[numCollPts].R1 = worldPos - body1Pos;
                            collPts[numCollPts++].InitialPenetration = oldDepth;
                        }
                    }

                    // the end
                    {
                        Vector3 oldCapsuleEndPos = Vector3.Transform(oldCapsule.GetEnd(), oldPlaneInvTransform);
                        Vector3 newCapsuleEndPos = Vector3.Transform(newCapsule.GetEnd(), newPlaneInvTransform);
                        float oldDist = Distance.PointPlaneDistance(oldCapsuleEndPos, oldPlane);
                        float newDist = Distance.PointPlaneDistance(newCapsuleEndPos, newPlane);

                        if (System.Math.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position(s)
                            Vector3 worldPos = oldCapsule.GetEnd() - oldCapsule.Radius * oldPlane.Normal;

                            // BEN-OPTIMISATION: Now reuses existing collPts instead of reallocating.
                            collPts[numCollPts].R0 = worldPos - body0Pos;
                            collPts[numCollPts].R1 = worldPos - body1Pos;
                            collPts[numCollPts++].InitialPenetration = oldDepth;
                        }

                        if (numCollPts > 0)
                        {
                            collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts);
                        }
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
Exemple #26
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);
                    }
                }
            }
        }
Exemple #27
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);
        }
Exemple #28
0
        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)
                                    {
                                        collPts[numCollPts++] = new SmallCollPointInfo(pt - body0Pos, pt - body1Pos, 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)
                                        {
                                            collPts[numCollPts++] = new SmallCollPointInfo(pt2 - body0Pos, pt2 - body1Pos, 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
            }
        }
        public override void DetectAllCollisions(List<Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            int numBodies = bodies.Count;

            CollDetectInfo info = new CollDetectInfo();

            for (int iBody = 0; iBody < numBodies; ++iBody)
            {
                Body body = bodies[iBody];
                if (!body.IsActive)
                    continue;

                info.Skin0 = body.CollisionSkin;
                if (info.Skin0 == null)
                    continue;

                tempGridLists.Clear();
                GetListsToCheck(tempGridLists, info.Skin0);

                for (int iList = tempGridLists.Count; iList-- != 0; )
                {
                    // first one is a placeholder;
                    GridEntry entry = tempGridLists[iList];
                    for (entry = entry.Next; entry != null; entry = entry.Next)
                    {
                        info.Skin1 = entry.Skin;
                        if (info.Skin1 == info.Skin0)
                            continue;

                        // CHANGE
                        if (info.Skin1 == null)
                            continue;

                        bool skinSleeping = true;

                        if ((info.Skin1.Owner != null) && (info.Skin1.Owner.IsActive))
                            skinSleeping = false;

                        // only do one per pair
                        if ((skinSleeping == false) && (info.Skin1.ID < info.Skin0.ID))
                             continue;

                        if ((collisionPredicate != null) && (!collisionPredicate.ConsiderSkinPair(info.Skin0, info.Skin1)))
                            continue;

                        // basic bbox test
                        if (BoundingBoxHelper.OverlapTest(ref info.Skin1.WorldBoundingBox,
                            ref info.Skin0.WorldBoundingBox, collTolerance))
                        {
                            if (CheckCollidables(info.Skin0, info.Skin1))
                            {
                                int bodyPrimitives = info.Skin0.NumPrimitives;
                                int primitves = info.Skin1.NumPrimitives;

                                for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0)
                                {
                                    for (info.IndexPrim1 = 0; info.IndexPrim1 < primitves; ++info.IndexPrim1)
                                    {
                                        DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type,
                                            info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type);
                                        if (f != null)
                                            f.CollDetect(info, collTolerance, collisionFunctor);
                                    }
                                }
                            } // check collidables
                        } // overlapt test
                    }// loop over entries
                } // loop over lists
            } // loop over bodies
        }
Exemple #30
0
        /// <summary>
        /// CollDetectCapsulseStaticMeshSweep
        /// </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 CollDetectCapsulseStaticMeshSweep(Capsule oldCapsule, Capsule newCapsule,
                                                       TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // really use a swept test - or overlap?
            Vector3 delta = newCapsule.Position - oldCapsule.Position;

            if (delta.LengthSquared() < (0.25f * newCapsule.Radius * newCapsule.Radius))
            {
                CollDetectCapsuleStaticMeshOverlap(oldCapsule, newCapsule, mesh, info, collTolerance, collisionFunctor);
            }
            else
            {
                float capsuleLen    = oldCapsule.Length;
                float capsuleRadius = oldCapsule.Radius;

                int nSpheres = 2 + (int)(capsuleLen / (2.0f * oldCapsule.Radius));
                for (int iSphere = 0; iSphere < nSpheres; ++iSphere)
                {
                    float          offset    = ((float)iSphere) * capsuleLen / ((float)nSpheres - 1.0f);
                    BoundingSphere oldSphere = new BoundingSphere(oldCapsule.Position + oldCapsule.Orientation.Backward * offset, capsuleRadius);
                    BoundingSphere newSphere = new BoundingSphere(newCapsule.Position + newCapsule.Orientation.Backward * offset, capsuleRadius);
                    CollDetectSphereStaticMesh.CollDetectSphereStaticMeshSweep(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor);
                }
            }
        }
Exemple #31
0
        private void CollDetectSweep(CollDetectInfo info, float collTolerance,
            CollisionFunctor collisionFunctor)
        {
            // todo - proper swept test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;
            BoundingSphere oldBSphere = new BoundingSphere(oldSphere.Position, oldSphere.Radius);
            BoundingSphere newBSphere = new BoundingSphere(newSphere.Position, newSphere.Radius);

            // todo - proper swept test
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            CollDetectSphereStaticMeshSweep(oldBSphere, newBSphere, mesh, info, collTolerance, collisionFunctor);
        }
Exemple #32
0
        /// <summary>
        /// Detect BoxBox Collisions.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Box box0 = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;
            Box box1 = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            Box oldBox0 = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box oldBox1 = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;

            Matrix dirs0 = box0.Orientation;
            Matrix dirs1 = box1.Orientation;


            seperatingAxes[0] = dirs0.Right;
            seperatingAxes[1] = dirs0.Up;
            seperatingAxes[2] = dirs0.Backward;
            seperatingAxes[3] = dirs1.Right;
            seperatingAxes[4] = dirs1.Up;
            seperatingAxes[5] = dirs1.Backward;
            Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[3], out seperatingAxes[6]);
            Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[4], out seperatingAxes[7]);
            Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[5], out seperatingAxes[8]);
            Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[3], out seperatingAxes[9]);
            Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[4], out seperatingAxes[10]);
            Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[5], out seperatingAxes[11]);
            Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[3], out seperatingAxes[12]);
            Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[4], out seperatingAxes[13]);
            Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[5], out seperatingAxes[14]);


            // 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 < 15; ++i)
            {
                // If we can't normalise the axis, skip it
                float l2 = seperatingAxes[i].LengthSquared();

                if (l2 < JiggleMath.Epsilon)
                {
                    continue;
                }

                overlapDepth[i] = float.MaxValue;

                if (Disjoint(out overlapDepth[i], ref seperatingAxes[i], box0, box1, collTolerance))
                {
                    return;
                }
            }

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

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

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

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

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

            // Make sure the axis is facing towards the 0th box.
            // if not, invert it
            Vector3 D     = box1.GetCentre() - box0.GetCentre();
            Vector3 N     = seperatingAxes[minAxis];
            float   depth = overlapDepth[minAxis];

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

            float minA = MathHelper.Min(box0.SideLengths.X, MathHelper.Min(box0.SideLengths.Y, box0.SideLengths.Z));
            float minB = MathHelper.Min(box1.SideLengths.X, MathHelper.Min(box1.SideLengths.Y, box1.SideLengths.Z));

            float combinationDist = 0.05f * MathHelper.Min(minA, minB);

            // the contact points
            bool contactPointsFromOld = true;

            contactPts.Clear();

            if (depth > -JiggleMath.Epsilon)
            {
                GetBoxBoxIntersectionPoints(contactPts, oldBox0, oldBox1, combinationDist, collTolerance);
            }

            int numPts = contactPts.Count;

            if (numPts == 0)
            {
                contactPointsFromOld = false;
                GetBoxBoxIntersectionPoints(contactPts, box0, box1, combinationDist, collTolerance);
            }
            numPts = contactPts.Count;

            Vector3 body0OldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1OldPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;
            Vector3 body0NewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero;
            Vector3 body1NewPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.Position : Vector3.Zero;

            #region REFERENCE: Vector3 bodyDelta = body0NewPos - body0OldPos - body1NewPos + body1OldPos;
            Vector3 bodyDelta;
            Vector3.Subtract(ref body0NewPos, ref body0OldPos, out bodyDelta);
            Vector3.Subtract(ref bodyDelta, ref body1NewPos, out bodyDelta);
            Vector3.Add(ref bodyDelta, ref body1OldPos, out bodyDelta);
            #endregion

            #region REFERENCE: float bodyDeltaLen = Vector3.Dot(bodyDelta,N);
            float bodyDeltaLen;
            Vector3.Dot(ref bodyDelta, ref N, out bodyDeltaLen);
            #endregion

            float oldDepth = depth + bodyDeltaLen;

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

                    Vector3 SATPoint;

                    switch (minAxis)
                    {
                    // Box0 face, Box1 corner collision
                    case 0:
                    case 1:
                    case 2:
                    {
                        // Get the lowest point on the box1 along box1 normal
                        GetSupportPoint(out SATPoint, box1, -N);
                        break;
                    }

                    // We have a Box2 corner/Box1 face collision
                    case 3:
                    case 4:
                    case 5:
                    {
                        // Find with vertex on the triangle collided
                        GetSupportPoint(out SATPoint, box0, N);
                        break;
                    }

                    // We have an edge/edge collision
                    case 6:
                    case 7:
                    case 8:
                    case 9:
                    case 10:
                    case 11:
                    case 12:
                    case 13:
                    case 14:
                    {
                        {
                            // Retrieve which edges collided.
                            i = minAxis - 6;
                            int ia = i / 3;
                            int ib = i - ia * 3;
                            // find two P0, P1 point on both edges.
                            Vector3 P0, P1;
                            GetSupportPoint(out P0, box0, N);
                            GetSupportPoint(out P1, box1, -N);
                            // Find the edge intersection.
                            // plane along N and F, and passing through PB
                            Vector3 box0Orient, box1Orient;
                            JiggleUnsafe.Get(ref box0.transform.Orientation, ia, out box0Orient);
                            JiggleUnsafe.Get(ref box1.transform.Orientation, ib, out box1Orient);

                            #region REFERENCE: Vector3 planeNormal = Vector3.Cross(N, box1Orient[ib]);
                            Vector3 planeNormal;
                            Vector3.Cross(ref N, ref box1Orient, out planeNormal);
                            #endregion

                            #region REFERENCE: float planeD = Vector3.Dot(planeNormal, P1);
                            float planeD;
                            Vector3.Dot(ref planeNormal, ref P1, out planeD);
                            #endregion

                            // find the intersection t, where Pintersection = P0 + t*box edge dir
                            #region REFERENCE: float div = Vector3.Dot(box0Orient, planeNormal);
                            float div;
                            Vector3.Dot(ref box0Orient, ref planeNormal, out div);
                            #endregion

                            // plane and ray colinear, skip the intersection.
                            if (System.Math.Abs(div) < JiggleMath.Epsilon)
                            {
                                return;
                            }

                            float t = (planeD - Vector3.Dot(P0, planeNormal)) / div;

                            // point on edge of box0
                            #region REFERENCE: P0 += box0Orient * t;
                            P0 = Vector3.Add(Vector3.Multiply(box0Orient, t), P0);
                            #endregion

                            #region REFERENCE: SATPoint = (P0 + (0.5f * depth) * N);
                            Vector3.Multiply(ref N, 0.5f * depth, out SATPoint);
                            Vector3.Add(ref SATPoint, ref P0, out SATPoint);
                            #endregion
                        }
                        break;
                    }

                    default:
                        throw new Exception("Impossible switch");
                    }

                    // distribute the depth according to the distance to the SAT point
                    if (numPts > 0)
                    {
                        float minDist = float.MaxValue;
                        float maxDist = float.MinValue;
                        for (i = 0; i < numPts; ++i)
                        {
                            float dist = Distance.PointPointDistance(contactPts[i].Pos, SATPoint);
                            if (dist < minDist)
                            {
                                minDist = dist;
                            }
                            if (dist > maxDist)
                            {
                                maxDist = dist;
                            }
                        }

                        if (maxDist < minDist + JiggleMath.Epsilon)
                        {
                            maxDist = minDist + JiggleMath.Epsilon;
                        }

                        // got some intersection points
                        for (i = 0; i < numPts; ++i)
                        {
                            float minDepthScale = 0.0f;
                            float dist          = Distance.PointPointDistance(contactPts[i].Pos, SATPoint);

                            float depthDiv   = System.Math.Max(JiggleMath.Epsilon, maxDist - minDist);
                            float depthScale = (dist - minDist) / depthDiv;

                            depth = (1.0f - depthScale) * oldDepth + minDepthScale * depthScale * oldDepth;

                            if (contactPointsFromOld)
                            {
                                if (numCollPts < MaxLocalStackSCPI)
                                {
                                    collPts[numCollPts++] = new SmallCollPointInfo(contactPts[i].Pos - body0OldPos, contactPts[i].Pos - body1OldPos, depth);
                                }
                            }
                            else
                            {
                                if (numCollPts < MaxLocalStackSCPI)
                                {
                                    collPts[numCollPts++] = new SmallCollPointInfo(contactPts[i].Pos - body0NewPos, contactPts[i].Pos - body1NewPos, depth);
                                }
                            }
                        }
                    }
                    else
                    {
                        #region REFERENCE: collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth));
                        //collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth));
                        Vector3 cp0;
                        Vector3.Subtract(ref SATPoint, ref body0NewPos, out cp0);

                        Vector3 cp1;
                        Vector3.Subtract(ref SATPoint, ref body1NewPos, out cp1);

                        if (numCollPts < MaxLocalStackSCPI)
                        {
                            collPts[numCollPts++] = new SmallCollPointInfo(ref cp0, ref cp1, oldDepth);
                        }
                        #endregion
                    }

                    // report Collisions
                    collisionFunctor.CollisionNotify(ref info, ref N, collPts, numCollPts);
                }

#if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
#endif
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;

            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;

            Heightmap oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Heightmap;
            Heightmap newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Heightmap;

            unsafe
            {

            #if USE_STACKALLOC
                SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI];
            #else
                SmallCollPointInfo[] collPtArray = SCPIStackAlloc();
                fixed (SmallCollPointInfo* collPts = collPtArray)
            #endif
                {
                    int numCollPts = 0;
                    Vector3 averageNormal = Vector3.Zero;

                    // the start
                    {
                        float oldDist, newDist;
                        Vector3 normal;
                        oldHeightmap.GetHeightAndNormal(out oldDist, out normal, oldCapsule.Position);
                        newHeightmap.GetHeightAndNormal(out newDist, out normal, newCapsule.Position);

                        if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position(s)
                            Vector3 worldPos = oldCapsule.Position - oldCapsule.Radius * normal;
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                            }
                            averageNormal += normal;
                        }
                    }
                    // the end
                    {
                        Vector3 oldEnd = oldCapsule.GetEnd();
                        Vector3 newEnd = newCapsule.GetEnd();
                        float oldDist, newDist;
                        Vector3 normal;
                        oldHeightmap.GetHeightAndNormal(out oldDist, out normal, oldEnd);
                        newHeightmap.GetHeightAndNormal(out newDist, out normal, newEnd);
                        if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius)
                        {
                            float oldDepth = oldCapsule.Radius - oldDist;
                            // calc the world position based on the old position(s)
                            Vector3 worldPos = oldEnd - oldCapsule.Radius * normal;
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth);
                            }
                            averageNormal += normal;
                        }
                    }

                    if (numCollPts > 0)
                    {
                        JiggleMath.NormalizeSafe(ref averageNormal);
                        collisionFunctor.CollisionNotify(ref info, ref averageNormal, collPts, numCollPts);
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
        public override void DetectCollisions(Body body, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            if (!body.IsActive)
                return;

            CollDetectInfo info = new CollDetectInfo();

            info.Skin0 = body.CollisionSkin;
            if (info.Skin0 == null)
                return;

            int bodyPrimitives = info.Skin0.NumPrimitives;
            int numSkins = skins.Count;

            for (int skin = 0; skin < numSkins; ++skin)
            {
                info.Skin1 = skins[skin];
                if ((info.Skin0 != info.Skin1) && CheckCollidables(info.Skin0, info.Skin1))
                {
                    int primitives = info.Skin1.NumPrimitives;

                    for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0)
                    {
                        for (info.IndexPrim1 = 0; info.IndexPrim1 < primitives; ++info.IndexPrim1)
                        {
                            DetectFunctor f =
                                GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type,
                                info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type);
                            if (f != null)
                                f.CollDetect(info, collTolerance, collisionFunctor);
                        }
                    }
                }
            }
        }
        /// <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);
                    }
                }
            }
        }
        /// <summary>
        /// CollDetectSweep
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        private void CollDetectSweep(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // todo - proper swept test
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            Vector3 oldCentre;
            oldBox.GetCentre(out oldCentre);
            Vector3 newCentre;
            newBox.GetCentre(out newCentre);

            Vector3 delta;
            Vector3.Subtract(ref newCentre, ref oldCentre, out delta);

            float boxMinLen = 0.5f * System.Math.Min(newBox.SideLengths.X, System.Math.Min(newBox.SideLengths.Y, newBox.SideLengths.Z));
            int nPositions = 1 + (int)(delta.Length / boxMinLen);
            // limit the max positions...
            if (nPositions > 50)
            {
                System.Diagnostics.Debug.WriteLine("Warning - clamping max positions in swept box test");
                nPositions = 50;
            }
            if (nPositions == 1)
            {
                CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh,ref info, collTolerance, collisionFunctor);
            }
            else
            {
                BoundingBox bb = BoundingBoxHelper.InitialBox;
                BoundingBoxHelper.AddBox(oldBox, ref bb);
                BoundingBoxHelper.AddBox(newBox, ref bb);
                unsafe
                {
            #if USE_STACKALLOC
                    int* potentialTriangles = stackalloc int[MaxLocalStackTris];
                    {
            #else
                    int[] potTriArray = IntStackAlloc();
                    fixed( int* potentialTriangles = potTriArray)
                    {
            #endif
                        int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb);
                        if (numTriangles > 0)
                        {
                            for (int i = 0; i <= nPositions; ++i)
                            {
                                float frac = ((float)i) / nPositions;
                                Vector3 centre;
                                Vector3.Multiply(ref delta, frac, out centre);
                                Vector3.Add(ref centre, ref oldCentre, out centre);

                                Matrix4 orient = Matrix4Extensions.Add(Matrix4Extensions.Multiply(oldBox.Orientation, 1.0f - frac), Matrix4Extensions.Multiply(newBox.Orientation, frac));

                                Box box = new Box(centre - 0.5f * Vector3Extensions.TransformNormal(newBox.SideLengths, orient), orient, newBox.SideLengths);
                                // ideally we'd break if we get one collision... but that stops us getting multiple collisions
                                // when we enter a corner (two walls meeting) - can let us pass through
                                CollDetectBoxStaticMeshOverlap(oldBox, box, mesh, ref info, collTolerance, collisionFunctor);
                            }
                        }
            #if USE_STACKALLOC
                    }
            #else
                    }
                    FreeStackAlloc(potTriArray);
            #endif
                }
            }
        }
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;

            // get the skins in the order that we're expecting
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            Capsule oldCapsule = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Capsule;
            Capsule newCapsule = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Capsule;

            Segment oldSeg = new Segment(oldCapsule.Position, oldCapsule.Length * oldCapsule.Orientation.Backward());
            Segment newSeg = new Segment(oldCapsule.Position, newCapsule.Length * newCapsule.Orientation.Backward());

            float radSum = newCapsule.Radius + newSphere.Radius;

            float oldt, newt;
            float oldDistSq = Distance.PointSegmentDistanceSq(out oldt, oldSphere.Position, oldSeg);
            float newDistSq = Distance.PointSegmentDistanceSq(out newt, newSphere.Position, newSeg);

            if (OpenTKHelper.Min(oldDistSq, newDistSq) < (radSum + collTolerance) * (radSum + collTolerance))
            {
                Vector3 segPos = oldSeg.GetPoint(oldt);
                Vector3 delta = oldSphere.Position - segPos;

                float dist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radSum - dist;

                if (dist > JiggleMath.Epsilon)
                {
                    delta /= dist;
                }
                else
                {
                    // todo - make this not random
                    delta = Vector3Extensions.TransformNormal(Vector3Extensions.Backward, Matrix4.CreateFromAxisAngle(Vector3Extensions.Up, OpenTKHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = segPos +
                    ((oldCapsule.Radius - 0.5f * depth) * delta);
                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos,
                        worldPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1);
                }
            }
        }
        /// <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();
                        Matrix4 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
                            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 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
            }
        }
Exemple #39
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
            }
        }
Exemple #40
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="info"></param>
 /// <param name="collTolerance"></param>
 /// <param name="collisionFunctor"></param>
 public abstract void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor);
Exemple #41
0
        private void CollDetectSweep(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // todo - proper swept test
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            Vector3 oldCentre;

            oldBox.GetCentre(out oldCentre);
            Vector3 newCentre;

            newBox.GetCentre(out newCentre);

            Vector3 delta;

            Vector3.Subtract(ref newCentre, ref oldCentre, out delta);

            float boxMinLen  = 0.5f * System.Math.Min(newBox.SideLengths.X, System.Math.Min(newBox.SideLengths.Y, newBox.SideLengths.Z));
            int   nPositions = 1 + (int)(delta.Length() / boxMinLen);

            // limit the max positions...
            if (nPositions > 50)
            {
                System.Diagnostics.Debug.WriteLine("Warning - clamping max positions in swept box test");
                nPositions = 50;
            }
            if (nPositions == 1)
            {
                CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh, ref info, collTolerance, collisionFunctor);
            }
            else
            {
                BoundingBox bb = BoundingBoxHelper.InitialBox;
                BoundingBoxHelper.AddBox(oldBox, ref bb);
                BoundingBoxHelper.AddBox(newBox, ref bb);
                unsafe
                {
#if USE_STACKALLOC
                    int *potentialTriangles = stackalloc int[MaxLocalStackTris];
                    {
#else
                    int[] potTriArray = IntStackAlloc();
                    fixed(int *potentialTriangles = potTriArray)
                    {
#endif
                        int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb);
                        if (numTriangles > 0)
                        {
                            for (int i = 0; i <= nPositions; ++i)
                            {
                                float   frac = ((float)i) / nPositions;
                                Vector3 centre;
                                Vector3.Multiply(ref delta, frac, out centre);
                                Vector3.Add(ref centre, ref oldCentre, out centre);

                                Matrix orient = Matrix.Add(Matrix.Multiply(oldBox.Orientation, 1.0f - frac), Matrix.Multiply(newBox.Orientation, frac));

                                Box box = new Box(centre - 0.5f * Vector3.Transform(newBox.SideLengths, orient), orient, newBox.SideLengths);
                                // ideally we'd break if we get one collision... but that stops us getting multiple collisions
                                // when we enter a corner (two walls meeting) - can let us pass through
                                CollDetectBoxStaticMeshOverlap(oldBox, box, mesh, ref info, collTolerance, collisionFunctor);
                            }
                        }
#if USE_STACKALLOC
                    }
#else
                    }
                    FreeStackAlloc(potTriArray);
#endif
                }
            }
        }
        /// <summary>
        /// CollDetectSweep
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        private void CollDetectSweep(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;

            // todo - proper swept test
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            CollDetectCapsulseStaticMeshSweep(oldCapsule, newCapsule, mesh, info, collTolerance, collisionFunctor);
        }
Exemple #43
0
 /// <summary>
 /// As DetectCollisions but detects for all bodies, testing each pair 
 /// only once
 /// </summary>
 /// <param name="bodies"></param>
 /// <param name="collisionFunctor"></param>
 /// <param name="collisionPredicate"></param>
 /// <param name="collTolerance"></param>
 public abstract void DetectAllCollisions(List<Body> bodies, CollisionFunctor collisionFunctor,
     CollisionSkinPredicate2 collisionPredicate, float collTolerance);
Exemple #44
0
        /// <summary>
        /// Detect BoxPlane Collisions.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            JPlane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JPlane;
            JPlane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JPlane;

            Matrix  newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Vector3 newBoxCen            = Vector3.Transform(newBox.GetCentre(), newPlaneInvTransform);

            // quick check
            float centreDist = Distance.PointPlaneDistance(newBoxCen, newPlane);

            if (centreDist > collTolerance + newBox.GetBoundingRadiusAroundCentre())
            {
                return;
            }

            Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

            Vector3[] newPts;
            newBox.GetCornerPoints(out newPts);
            Vector3[] oldPts;
            oldBox.GetCornerPoints(out oldPts);

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

                    for (int i = 0; i < 8; ++i)
                    {
                        Vector3.Transform(ref oldPts[i], ref oldPlaneInvTransform, out oldTransPts[i]);
                        Vector3.Transform(ref newPts[i], ref newPlaneInvTransform, out newPts[i]);

                        float oldDepth = -Distance.PointPlaneDistance(ref oldTransPts[i], oldPlane);
                        float newDepth = -Distance.PointPlaneDistance(ref newPts[i], newPlane);

                        if (MathHelper.Max(oldDepth, newDepth) > -collTolerance)
                        {
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                // BEN-OPTIMISATION: Now reuses instead of reallocating.
                                collPts[numCollPts].R0 = oldPts[i] - body0Pos;
                                collPts[numCollPts].R1 = oldPts[i] - body1Pos;
                                collPts[numCollPts++].InitialPenetration = oldDepth;
                            }
                        }
                    }

                    if (numCollPts > 0)
                    {
                        collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts);
                    }
                }

#if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
#endif
            }
        }
Exemple #45
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;

            // get the skins in the order that we're expecting
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            Capsule oldCapsule = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Capsule;
            Capsule newCapsule = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Capsule;

            Segment oldSeg = new Segment(oldCapsule.Position, oldCapsule.Length * oldCapsule.Orientation.Backward);
            Segment newSeg = new Segment(oldCapsule.Position, newCapsule.Length * newCapsule.Orientation.Backward);

            float radSum = newCapsule.Radius + newSphere.Radius;

            float oldt, newt;
            float oldDistSq = Distance.PointSegmentDistanceSq(out oldt, oldSphere.Position, oldSeg);
            float newDistSq = Distance.PointSegmentDistanceSq(out newt, newSphere.Position, newSeg);

            if (MathHelper.Min(oldDistSq, newDistSq) < (radSum + collTolerance) * (radSum + collTolerance))
            {
                Vector3 segPos = oldSeg.GetPoint(oldt);
                Vector3 delta  = oldSphere.Position - segPos;

                float dist  = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radSum - dist;

                if (dist > JiggleMath.Epsilon)
                {
                    delta /= dist;
                }
                else
                {
                    // todo - make this not random
                    delta = Vector3.TransformNormal(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360))));
                }

                Vector3 worldPos = segPos +
                                   ((oldCapsule.Radius - 0.5f * depth) * delta);

#if WINDOWS_PHONE
                this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos,
                                                          worldPos - body1Pos, depth);

                collisionFunctor.CollisionNotify(ref info, ref delta, this.collInfo, 1);
#else
                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos,
                                                                         worldPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1);
                }
#endif
            }
        }
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // get the skins in the order that we're expecting
            CollDetectInfo info = infoOrig;

            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper sweep test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;
            Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            Vector3 oldBoxPoint;
            Vector3 newBoxPoint;

            float oldDist = oldBox.GetDistanceToPoint(out oldBoxPoint, oldSphere.Position);
            float newDist = newBox.GetDistanceToPoint(out newBoxPoint, newSphere.Position);

            // normally point will be outside
            float oldDepth = oldSphere.Radius - oldDist;
            float newDepth = newSphere.Radius - newDist;

            if (System.Math.Max(oldDepth, newDepth) > -collTolerance)
            {
                Vector3 dir;
                if (oldDist < -JiggleMath.Epsilon)
                {
                    dir = oldBoxPoint - oldSphere.Position - oldBoxPoint;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else if (oldDist > JiggleMath.Epsilon)
                {
                    dir = oldSphere.Position - oldBoxPoint;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else
                {
                    dir = oldSphere.Position - oldBox.GetCentre();
                    JiggleMath.NormalizeSafe(ref dir);
                }

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(oldBoxPoint - body0Pos,
                                                                         oldBoxPoint - body1Pos, oldDepth);


                    collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1);
                }
            }
            #endregion
        }
Exemple #47
0
        /// <summary>
        /// Detect BoxPlane Collisions.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            JPlane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JPlane;
            JPlane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JPlane;

            Matrix4 newPlaneInvTransform = newPlane.InverseTransformMatrix;
            Vector3 newBoxCen = Vector3.Transform(newBox.GetCentre(), newPlaneInvTransform);

            // quick check
            float centreDist = Distance.PointPlaneDistance(newBoxCen, newPlane);
            if (centreDist > collTolerance + newBox.GetBoundingRadiusAroundCentre())
                return;

            Matrix4 oldPlaneInvTransform = oldPlane.InverseTransformMatrix;

            Vector3[] newPts;
            newBox.GetCornerPoints(out newPts);
            Vector3[] oldPts;
            oldBox.GetCornerPoints(out oldPts);

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

                    for (int i = 0; i < 8; ++i)
                    {
                        Vector3.Transform(ref oldPts[i], ref oldPlaneInvTransform, out oldTransPts[i]);
                        Vector3.Transform(ref newPts[i], ref newPlaneInvTransform, out newPts[i]);

                        float oldDepth = -Distance.PointPlaneDistance(ref oldTransPts[i], oldPlane);
                        float newDepth = -Distance.PointPlaneDistance(ref newPts[i], newPlane);

                        if (OpenTKHelper.Max(oldDepth, newDepth) > -collTolerance)
                        {
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                // BEN-OPTIMISATION: Now reuses instead of reallocating.
                                collPts[numCollPts].R0 = oldPts[i] - body0Pos;
                                collPts[numCollPts].R1 = oldPts[i] - body1Pos;
                                collPts[numCollPts++].InitialPenetration = oldDepth;
                            }
                        }
                    }

                    if (numCollPts > 0)
                    {
                        collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts);
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
Exemple #48
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
           // get the skins in the order that we're expecting
            CollDetectInfo info = infoOrig;

            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper sweep test
            Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere;
            Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere;

            Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;
            Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            Vector3 oldBoxPoint;
            Vector3 newBoxPoint;

            float oldDist = oldBox.GetDistanceToPoint(out oldBoxPoint, oldSphere.Position);
            float newDist = newBox.GetDistanceToPoint(out newBoxPoint, newSphere.Position);

            // normally point will be outside
            float oldDepth = oldSphere.Radius - oldDist;
            float newDepth = newSphere.Radius - newDist;

            if (System.Math.Max(oldDepth, newDepth) > -collTolerance)
            {
                Vector3 dir;
                if (oldDist < -JiggleMath.Epsilon)
                {
                    dir = oldBoxPoint - oldSphere.Position - oldBoxPoint;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else if (oldDist > JiggleMath.Epsilon)
                {
                    dir = oldSphere.Position - oldBoxPoint;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else
                {
                    dir = oldSphere.Position - oldBox.GetCentre();
                    JiggleMath.NormalizeSafe(ref dir);
                }

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(oldBoxPoint - body0Pos,
                        oldBoxPoint - body1Pos, oldDepth);

                    
                    collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1);
                }

            }
        #endregion

        }
Exemple #49
0
 /// <summary>
 /// Detects all collisions between the body and all the registered
 /// collision skins (which should have already had their
 /// positions/bounding volumes etc updated).  For each potential
 /// pair of skins then the predicate (if it exists) will be called
 /// to see whether or not to continue. If the skins are closer
 /// than collTolerance (+ve value means report objects that aren't
 /// quite colliding) then the functor will get called.
 /// You can't just loop over all your bodies calling this, because
 /// that will double-detect collisions. Use DetectAllCollisions for
 /// that.
 /// </summary>
 public abstract void DetectCollisions(Body body, CollisionFunctor collisionFunctor,
                                       CollisionSkinPredicate2 collisionPredicate, float collTolerance);
        public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            var oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            var newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;

            var oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as CubeHeightmapCollisionShape;
            var newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as CubeHeightmapCollisionShape;

            Vector3[] oldPoints = new Vector3[2];
            Vector3[] newPoints = new Vector3[2];
            oldPoints[0] = oldCapsule.Position;
            oldPoints[1] = oldCapsule.GetEnd();
            newPoints[0] = newCapsule.Position;
            newPoints[1] = newCapsule.GetEnd();

            if (capsuleBoxDetectFunctor == null)
            {
                capsuleBoxDetectFunctor = PhysicsSystem.CurrentPhysicsSystem.CollisionSystem.GetCollDetectFunctor(
                    (int) PrimitiveType.Capsule, (int) PrimitiveType.Box);
            }

            oldHeightmap.GetMapPositions(oldPoints, oldMapPositions);
            newHeightmap.GetMapPositions(newPoints, newMapPositions);
            // TODO: needed ?
            foreach (var oldMapPosition in oldMapPositions)
            {
                if (!newMapPositions.Contains(oldMapPosition))
                {
                    newMapPositions.Add(oldMapPosition);
                }
            }

            bool sameHeight = true;
            float prevHeight = newHeightmap.GetHeight(newMapPositions[0]);
            for (int i = 1; i < newMapPositions.Count; i++)
            {
                if (prevHeight != newHeightmap.GetHeight(newMapPositions[i]))
                {
                    sameHeight = false;
                    break;
                }
            }

            #region As plane

            if (sameHeight)
            {
                virtualPlaneSkin.SetMaterialProperties(0, info.Skin1.GetMaterialProperties(info.IndexPrim1));

                var vcdi = new CollDetectInfo()
                {
                    Skin0 = info.Skin0,
                    Skin1 = virtualPlaneSkin,
                    IndexPrim0 = info.IndexPrim0,
                    IndexPrim1 = 0
                };

                virtualCollisionFunctor.CollisionFunctorEntity = collisionFunctor;
                virtualCollisionFunctor.CollDetectInfoEntity = info;

                var oldPlane = virtualPlaneSkin.GetPrimitiveOldWorld(0) as JPlane;
                var newPlane = virtualPlaneSkin.GetPrimitiveNewWorld(0) as JPlane;
                oldHeightmap.PrepareVirtualPlane(newMapPositions[0], oldPlane);
                newHeightmap.PrepareVirtualPlane(newMapPositions[0], newPlane);

                if (capsulePlaneDetectFunctor == null)
                {
                    var collisionSystem = PhysicsSystem.CurrentPhysicsSystem.CollisionSystem;
                    capsulePlaneDetectFunctor = collisionSystem.GetCollDetectFunctor(
                        (int) PrimitiveType.Capsule,
                        (int) PrimitiveType.Plane);
                }

                virtualCollisionFunctor.CollisionFunctorEntity = collisionFunctor;
                virtualCollisionFunctor.CollDetectInfoEntity = info;

                capsulePlaneDetectFunctor.CollDetect(vcdi, collTolerance, virtualCollisionFunctor);

                return;
            }

            #endregion

            #region As boxes

            virtualBoxSkin.SetMaterialProperties(0, info.Skin1.GetMaterialProperties(info.IndexPrim1));

            CollDetectInfo virtualCollDetectInfo = new CollDetectInfo()
            {
                Skin0 = info.Skin0,
                Skin1 = virtualBoxSkin,
                IndexPrim0 = info.IndexPrim0,
                IndexPrim1 = 0
            };

            virtualCollisionFunctor.CollisionFunctorEntity = collisionFunctor;
            virtualCollisionFunctor.CollDetectInfoEntity = info;

            foreach (var newMapPosition in newMapPositions)
            {
                var oldPrimitive = virtualBoxSkin.GetPrimitiveOldWorld(0) as Box;
                var newPrimitive = virtualBoxSkin.GetPrimitiveNewWorld(0) as Box;
                oldHeightmap.PrepareVirtualBox(newMapPosition, oldPrimitive);
                newHeightmap.PrepareVirtualBox(newMapPosition, newPrimitive);

                capsuleBoxDetectFunctor.CollDetect(virtualCollDetectInfo, collTolerance, virtualCollisionFunctor);
            }

            #endregion
        }
Exemple #51
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;

            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;


            // todo - proper swept test
            Sphere oldSphere = (Sphere)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0);
            Sphere newSphere = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0);

            Heightmap oldHeightmap = (Heightmap)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1);
            Heightmap newHeightmap = (Heightmap)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1);

            float   newDist;
            Vector3 normal;

            newHeightmap.GetHeightAndNormal(out newDist, out normal, newSphere.Position);
            if (newDist < collTolerance + newSphere.Radius)
            {
                float oldDist = oldHeightmap.GetHeight(oldSphere.Position);
                float depth   = oldSphere.Radius - oldDist;

                // calc the world position when it just hit
                Vector3 oldPt = oldSphere.Position - oldSphere.Radius * normal;
                unsafe
                {
                    SmallCollPointInfo ptInfo = new SmallCollPointInfo(oldPt - body0Pos, oldPt - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref normal, &ptInfo, 1);
                }
            }
        }
        /// <summary>
        /// CollDetectCapsulseStaticMeshSweep
        /// </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 CollDetectCapsulseStaticMeshSweep(Capsule oldCapsule, Capsule newCapsule,
            TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // really use a swept test - or overlap?
            Vector3 delta = newCapsule.Position - oldCapsule.Position;
            if (delta.LengthSquared < (0.25f * newCapsule.Radius * newCapsule.Radius))
            {
                CollDetectCapsuleStaticMeshOverlap(oldCapsule, newCapsule, mesh, info, collTolerance, collisionFunctor);
            }
            else
            {
                float capsuleLen = oldCapsule.Length;
                float capsuleRadius = oldCapsule.Radius;

                int nSpheres = 2 + (int)(capsuleLen / (2.0f * oldCapsule.Radius));
                for (int iSphere = 0; iSphere < nSpheres; ++iSphere)
                {
                    float offset = ((float)iSphere) * capsuleLen / ((float)nSpheres - 1.0f);
                    BoundingSphere oldSphere = new BoundingSphere(oldCapsule.Position + oldCapsule.Orientation.Backward() * offset, capsuleRadius);
                    BoundingSphere newSphere = new BoundingSphere(newCapsule.Position + newCapsule.Orientation.Backward() * offset, capsuleRadius);
                    CollDetectSphereStaticMesh.CollDetectSphereStaticMeshSweep(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor);
                }
            }
        }
        /// <summary>
        /// Detect BoxHeightmap Collisions.
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            CollDetectInfo info = infoOrig;
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            Heightmap oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Heightmap;
            Heightmap newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Heightmap;

            Vector3[] oldPts, newPts;
            oldBox.GetCornerPoints(out oldPts);
            newBox.GetCornerPoints(out newPts);

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

                    Vector3 collNormal = Vector3.Zero;

                    for (int i = 0; i < 8; ++i)
                    {
                        Vector3 newPt = newPts[i];
                        float newDist;
                        Vector3 normal;
                        newHeightmap.GetHeightAndNormal(out newDist, out normal, newPt);

                        if (newDist < collTolerance)
                        {
                            Vector3 oldPt = oldPts[i];
                            float oldDist = oldHeightmap.GetHeight(oldPt);

                            #region REFERENCE: collPts.Add(new CollPointInfo(oldPt - body0Pos, oldPt - body1Pos, -oldDist));
                            Vector3 pt0;
                            Vector3 pt1;
                            Vector3.Subtract(ref oldPt, ref body0Pos, out pt0);
                            Vector3.Subtract(ref oldPt, ref body1Pos, out pt1);
                            if (numCollPts < MaxLocalStackSCPI)
                            {
                                collPts[numCollPts++] = new SmallCollPointInfo(ref pt0, ref pt1, -oldDist);
                            }
                            #endregion

                            #region REFERENCE: collNormal += normal;
                            Vector3.Add(ref collNormal, ref normal, out collNormal);
                            #endregion
                        }
                    }

                    if (numCollPts > 0)
                    {
                        JiggleMath.NormalizeSafe(ref collNormal);
                        collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts);
                    }
                }
            #if !USE_STACKALLOC
                FreeStackAlloc(collPtArray);
            #endif
            }
        }
        /// <summary>
        /// DetectAllCollisions
        /// </summary>
        /// <param name="bodies"></param>
        /// <param name="collisionFunctor"></param>
        /// <param name="collisionPredicate"></param>
        /// <param name="collTolerance"></param>
        public override void DetectAllCollisions(List<Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance)
        {
            int numSkins = skins.Count;
            int numBodies = bodies.Count;

            CollDetectInfo info = new CollDetectInfo();

            for (int ibody = 0; ibody < numBodies; ++ibody)
            {
                Body body = bodies[ibody];
                if(!body.IsActive)
                    continue;

                info.Skin0 = body.CollisionSkin;
                if (info.Skin0 == null)
                    continue;

                for (int skin = 0; skin < numSkins; ++skin)
                {
                    info.Skin1 = skins[skin];
                    if (info.Skin0 == info.Skin1)
                        continue;

                    // CHANGE
                    if (info.Skin1 == null)
                        continue;

                    bool skinSleeping = true;

                    if (info.Skin1.Owner != null && info.Skin1.Owner.IsActive)
                        skinSleeping = false;

                    if ((skinSleeping == false) && (info.Skin1.ID < info.Skin0.ID))
                        continue;

                    if((collisionPredicate != null) &&
                        collisionPredicate.ConsiderSkinPair(info.Skin0,info.Skin1) == false)
                    continue;

                    // basic bbox test
                    if(BoundingBoxHelper.OverlapTest(ref info.Skin0.WorldBoundingBox,
                        ref info.Skin1.WorldBoundingBox,collTolerance))
                    {
                        if (CheckCollidables(info.Skin0,info.Skin1))
                        {
                            int bodyPrimitives = info.Skin0.NumPrimitives;
                            int primitves = info.Skin1.NumPrimitives;

                            for(info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0)
                            {
                                for (info.IndexPrim1 = 0; info.IndexPrim1 < primitves; ++info.IndexPrim1)
                                {
                                    DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type,
                                        info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type);
                                    if (f != null)
                                        f.CollDetect(info, collTolerance, collisionFunctor);
                                }
                            }
                        }
                    } // overlapt test
                } // loop over skins
            } // loop over bodies
        }
        /// <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;
                    }
                }

            }
        }
Exemple #56
0
        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;

            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;

                        Vector3 collNormal = Vector3.Zero;

                        BoundingBox bb = BoundingBoxHelper.InitialBox;
                        BoundingBoxHelper.AddSphere(newSphere, ref bb);
                        int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, 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(potentialTriangles[iTriangle]);
                            float distToCentre = meshTriangle.Plane.DotCoordinate(newSphereCen);

                            if (distToCentre <= 0.0f)
                                continue;
                            if (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)
                                {
                                    collPts[numCollPts++] = new SmallCollPointInfo(pt - body0Pos, pt - body1Pos, 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
            }
        }
        /// <summary>
        /// CollDetectOverlap
        /// </summary>
        /// <param name="info"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        private void CollDetectOverlap(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // note - mesh is static and its triangles are in world space
            TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh;

            Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box;
            Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box;

            CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh, ref info, collTolerance, collisionFunctor);
        }
Exemple #58
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
            }
        }
        /// <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
            Matrix4 invTransformMatrix = mesh.InverseTransformMatrix;
            Vector3.Transform(ref boxCentre, ref invTransformMatrix, out boxCentre);
            #endregion

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

            unsafe
            {
                bool collision = false;

            #if USE_STACKALLOC
                int* potentialTriangles = stackalloc int[MaxLocalStackTris];
                {
            #else
                int[] potTriArray = IntStackAlloc();
                fixed( int* potentialTriangles = potTriArray)
                {
            #endif
                    // aabox is done in mesh space and handles the mesh transform correctly
                    int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb);

                    for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle)
                    {
                        IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[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;
                        }
                    }
            #if USE_STACKALLOC
                }
            #else
                }
                FreeStackAlloc(potTriArray);
            #endif
                return collision;
            }
        }
Exemple #60
0
        /// <summary>
        /// CollDetect
        /// </summary>
        /// <param name="infoOrig"></param>
        /// <param name="collTolerance"></param>
        /// <param name="collisionFunctor"></param>
        public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor)
        {
            // get the skins in the order that we're expectiing
            CollDetectInfo info = infoOrig;
            if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1)
            {
                CollisionSkin skinSwap = info.Skin0;
                info.Skin0 = info.Skin1;
                info.Skin1 = skinSwap;
                int primSwap = info.IndexPrim0;
                info.IndexPrim0 = info.IndexPrim1;
                info.IndexPrim1 = primSwap;
            }

            Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero;
            Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero;

            // todo - proper swept test
            Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule;
            Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule;
            Segment oldSeg = new Segment(oldCapsule.Position, oldCapsule.Length * oldCapsule.Orientation.Backward);
            Segment newSeg = new Segment(newCapsule.Position, newCapsule.Length * newCapsule.Orientation.Backward);

            float radius = oldCapsule.Radius;

            Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box;
            Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box;

            float oldSegT;
            float oldBoxT0, oldBoxT1, oldBoxT2;
            float oldDistSq = Distance.SegmentBoxDistanceSq(out oldSegT, out oldBoxT0, out oldBoxT1, out oldBoxT2,oldSeg, oldBox);
            float newSegT;
            float newBoxT0, newBoxT1, newBoxT2;
            float newDistSq = Distance.SegmentBoxDistanceSq(out newSegT, out newBoxT0, out newBoxT1, out newBoxT2,newSeg, newBox);

            if (MathHelper.Min(oldDistSq, newDistSq) < ((radius + collTolerance) * (radius + collTolerance)))
            {
                Vector3 segPos = oldSeg.GetPoint(oldSegT);
                Vector3 boxPos = oldBox.GetCentre() + oldBoxT0 * oldBox.Orientation.Right +
                    oldBoxT1 * oldBox.Orientation.Up + oldBoxT2 * oldBox.Orientation.Backward;

                float dist = (float)System.Math.Sqrt((float)oldDistSq);
                float depth = radius - dist;

                Vector3 dir;

                if (dist > JiggleMath.Epsilon)
                {
                    dir = segPos - boxPos;
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else if ((segPos - oldBox.GetCentre()).LengthSquared() > JiggleMath.Epsilon)
                {
                    dir = segPos - oldBox.GetCentre();
                    JiggleMath.NormalizeSafe(ref dir);
                }
                else
                {
                    // todo - make this not random
                    dir = Vector3.Transform(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360))));
                }

                unsafe
                {
                    SmallCollPointInfo collInfo = new SmallCollPointInfo(boxPos - body0Pos, boxPos - body1Pos, depth);

                    collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1);
                }

            }
        }