Superclass of objects living in the collision detection pipeline that can result in contacts.
Inheritance: BroadPhaseEntry
Beispiel #1
0
        /// <summary>
        /// Computes the intersection, if any, between a ray and the objects in the character's bounding box.
        /// </summary>
        /// <param name="ray">Ray to test.</param>
        /// <param name="length">Length of the ray to use in units of the ray's length.</param>
        /// <param name="earliestHit">Earliest intersection location and information.</param>
        /// <param name="hitObject">Collidable intersected by the ray, if any.</param>
        /// <returns>Whether or not the ray hit anything.</returns>
        public bool RayCast(Ray ray, float length, out RayHit earliestHit, out Collidable hitObject)
        {
            earliestHit = new RayHit();
            earliestHit.T = float.MaxValue;
            hitObject = null;
            foreach (var collidable in characterBody.CollisionInformation.OverlappedCollidables)
            {
                //Check to see if the collidable is hit by the ray.
                float t;
                if (ray.Intersects(ref collidable.boundingBox, out t) && t < length)
                {
                    //Is it an earlier hit than the current earliest?
                    RayHit hit;
                    if (collidable.RayCast(ray, length, SupportRayFilter, out hit) && hit.T < earliestHit.T)
                    {
                        earliestHit = hit;
                        hitObject = collidable;
                    }
                }
            }
            if (earliestHit.T == float.MaxValue)
                return false;
            return true;

        }
        private void CollisionDetectedHandler(EntityCollidable sender, Collidable other, CollidablePairHandler pair)
        {
            EntityCollidable otherEntityCollidable = other as EntityCollidable;
            Terrain otherTerrain = other as Terrain;
            if (otherEntityCollidable != null &&
                otherEntityCollidable.Entity != null &&
                otherEntityCollidable.Entity.Tag != null)
            {
                int actorId = (int)(otherEntityCollidable.Entity.Tag);
                if (actorId == mOwnerActorId)
                    return;
                Actor actorHit = GameResources.ActorManager.GetActorById(actorId);
                IDamagable damage = actorHit.GetBehaviorThatImplementsType<IDamagable>();
                if (damage != null)
                {
                    damage.TakeDamage(mDamage);
                }

                Impact();
            }
            else if (otherTerrain != null)
            {
                Impact();
            }
        }
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public FishInABarrelDemo(DemosGame game)
            : base(game)
        {
            game.Camera.Position = new Vector3(0, 7, 30);

            var detector = new Box(new Vector3(0, 0, 0), 1.5f, 1.5f, 1.5f);
            detector.CollisionInformation.CollisionRules.Personal = CollisionRule.NoSolver;
            var acceptedTriggerEntity = new Box(new Vector3(5, 0, 0), 1.6f, .7f, .4f, 1);
            acceptedTrigger = acceptedTriggerEntity.CollisionInformation;

            detector.Tag = "noDisplayObject";
            acceptedTriggerEntity.Tag = "noDisplayObject";
            Space.Add(detector);
            Space.Add(acceptedTriggerEntity);

            var fish = game.Content.Load<Model>("fish");
            game.ModelDrawer.Add(new DisplayEntityModel(acceptedTriggerEntity, fish, game.ModelDrawer));

            var barrelAndPlatform = game.Content.Load<Model>("barrelAndPlatform");
            Vector3[] staticTriangleVertices;
            int[] staticTriangleIndices;
            ModelDataExtractor.GetVerticesAndIndicesFromModel(barrelAndPlatform, out staticTriangleVertices, out staticTriangleIndices);

            //Note that the final 'margin' parameter is optional, but can be used to specify a collision margin on triangles in the static triangle group.
            var fishDepositoryGroup = new StaticMesh(staticTriangleVertices, staticTriangleIndices);
            CollisionRules.AddRule(fishDepositoryGroup, detector, CollisionRule.NoBroadPhase);
            Space.Add(fishDepositoryGroup);
            game.ModelDrawer.Add(fishDepositoryGroup);

            movedBox = new Box(new Vector3(-4, 5, 0), 1, 1, 1, 1);
            detector.Space.Add(movedBox);
            detector.CollisionInformation.Events.InitialCollisionDetected += InitialCollisionDetected;
            detector.CollisionInformation.Events.CollisionEnded += CollisionEnded;
        }
 void Events_InitialCollisionDetected(EntityCollidable sender, Collidable other, CollidablePairHandler pair)
 {
     if ("Environment".Equals(other.Tag))
     {
         // do something on collision
     }
 }
        public void InitialCollisionDetected(EntityCollidable sender, Collidable other, CollidablePairHandler collisionPair)
        {
            if (other == acceptedTrigger)
            {
                //If the detector collided with the accepted trigger, move the box.
                movedBox.Position = new Vector3(4, 5, 0);
                movedBox.Orientation = Quaternion.Identity;
                movedBox.LinearVelocity = Vector3.Zero;
                movedBox.AngularVelocity = Vector3.Zero;

            }
        }
 private void InitialCollisionDetectedHandler(EntityCollidable sender, Collidable other, CollidablePairHandler pair)
 {
     EntityCollidable otherEntityCollidable = other as EntityCollidable;
     if (otherEntityCollidable != null &&
         otherEntityCollidable.Entity != null &&
         otherEntityCollidable.Entity.Tag != null &&
         mTriggerSet &&
         GameResources.ActorManager.IsPlayer((int)(otherEntityCollidable.Entity.Tag)))
     {
         mTriggerSet = false;
         GameResources.LoadNewLevelDelegate(mLevelName);
     }
 }
        ///<summary>
        /// Initializes the manifold.
        ///</summary>
        ///<param name="newCollidableA">First collidable.</param>
        ///<param name="newCollidableB">Second collidable.</param>
        public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
        {
            convex = newCollidableA as ConvexCollidable;
            mesh = newCollidableB as MobileMeshCollidable;

            if (convex == null || mesh == null)
            {
                convex = newCollidableB as ConvexCollidable;
                mesh = newCollidableA as MobileMeshCollidable;
                if (convex == null || mesh == null)
                    throw new ArgumentException("Inappropriate types used to initialize contact manifold.");
            }
        }
Beispiel #8
0
 private void InitialCollisionDetectedHandler(EntityCollidable sender, Collidable other, CollidablePairHandler pair)
 {
     EntityCollidable otherEntityCollidable = other as EntityCollidable;
     if (otherEntityCollidable != null &&
         otherEntityCollidable.Entity != null &&
         otherEntityCollidable.Entity.Tag != null &&
         mTriggerSet &&
         GameResources.ActorManager.IsPlayer((int)(otherEntityCollidable.Entity.Tag)))
     {
         PlayerView finder = GameResources.ActorManager.GetPlayerViewOfAvatar((int)(otherEntityCollidable.Entity.Tag));
         finder.AvatarDesc.ObtainItem(Item);
         mTriggerSet = false;
         Owner.Despawn();
     }
 }
Beispiel #9
0
        /// <summary>
        /// Raises the appropriate ParentObject collision events depending on its CollisionType value
        /// </summary>
        /// <param name="sender">The current ISpaceObject instance</param>
        /// <param name="other">The ISpaceObject instance which collided</param>
        /// <param name="pair"/>
        protected void OnCollisionDetected(Collidable sender, Collidable other, CollidablePairHandler pair)
        {
            if (sender.Tag == null || other.Tag == null)
                return;

            ICollisionObject senderCollisionObject = (ICollisionObject) sender.Tag;
            ICollisionObject otherCollisionObject = (ICollisionObject) other.Tag;

            switch (ParentObject.CollisionType)
            {
                case CollisionType.Trigger:
                    {
                        ParentObject.OnCollisionTrigger(senderCollisionObject, otherCollisionObject);
                        break;
                    }
                case CollisionType.Collide:
                    {
                        var collisionPoint = new CollisionPoint
                                                 {
                                                     ContactObject = otherCollisionObject,
                                                     ContactPoint = pair.Contacts[0].Contact.Position,
                                                     ContactTime = pair.TimeOfImpact,
                                                     Material = null,
                                                     SurfaceNormal = pair.Contacts[0].Contact.Normal
                                                 };

                        ParentObject.OnCollisionReact(senderCollisionObject, otherCollisionObject, collisionPoint, ref _collisionHandled);
                        break;
                    }
                default:
                case CollisionType.None:
                    {
                        break;
                    }
            }
        }
        ///<summary>
        /// Updates the time of impact for the pair.
        ///</summary>
        ///<param name="requester">Collidable requesting the update.</param>
        ///<param name="dt">Timestep duration.</param>
        public override void UpdateTimeOfImpact(Collidable requester, float dt)
        {
            //Notice that we don't test for convex entity null explicitly.  The convex.IsActive property does that for us.
            if (convex.IsActive && convex.entity.PositionUpdateMode == PositionUpdateMode.Continuous)
            {
                //TODO: This system could be made more robust by using a similar region-based rejection of edges.
                //CCD events are awfully rare under normal circumstances, so this isn't usually an issue.

                //Only perform the test if the minimum radii are small enough relative to the size of the velocity.
                System.Numerics.Vector3 velocity;
                Vector3Ex.Multiply(ref convex.entity.linearVelocity, dt, out velocity);
                float velocitySquared = velocity.LengthSquared();

                var minimumRadius = convex.Shape.MinimumRadius * MotionSettings.CoreShapeScaling;
                timeOfImpact = 1;
                if (minimumRadius * minimumRadius < velocitySquared)
                {
                    var triangle = PhysicsThreadResources.GetTriangle();
                    triangle.collisionMargin = 0;
                    System.Numerics.Vector3 terrainUp = new System.Numerics.Vector3(terrain.worldTransform.LinearTransform.M21, terrain.worldTransform.LinearTransform.M22, terrain.worldTransform.LinearTransform.M23);
                    //Spherecast against all triangles to find the earliest time.
                    for (int i = 0; i < TerrainManifold.overlappedTriangles.Count; i++)
                    {
                        terrain.Shape.GetTriangle(TerrainManifold.overlappedTriangles.Elements[i], ref terrain.worldTransform, out triangle.vA, out triangle.vB, out triangle.vC);
                        //Put the triangle into 'localish' space of the convex.
                        Vector3Ex.Subtract(ref triangle.vA, ref convex.worldTransform.Position, out triangle.vA);
                        Vector3Ex.Subtract(ref triangle.vB, ref convex.worldTransform.Position, out triangle.vB);
                        Vector3Ex.Subtract(ref triangle.vC, ref convex.worldTransform.Position, out triangle.vC);

                        RayHit rayHit;
                        if (GJKToolbox.CCDSphereCast(new Ray(Toolbox.ZeroVector, velocity), minimumRadius, triangle, ref Toolbox.RigidIdentity, timeOfImpact, out rayHit) &&
                            rayHit.T > Toolbox.BigEpsilon)
                        {

                            System.Numerics.Vector3 AB, AC;
                            Vector3Ex.Subtract(ref triangle.vB, ref triangle.vA, out AB);
                            Vector3Ex.Subtract(ref triangle.vC, ref triangle.vA, out AC);
                            System.Numerics.Vector3 normal;
                            Vector3Ex.Cross(ref AC, ref AB, out normal);
                            float dot;
                            Vector3Ex.Dot(ref normal, ref terrainUp, out dot);
                            if (dot < 0)
                                Vector3Ex.Dot(ref normal, ref rayHit.Normal, out dot);
                            else
                            {
                                Vector3Ex.Dot(ref normal, ref rayHit.Normal, out dot);
                                dot = -dot;
                            }
                            //Only perform sweep if the object is in danger of hitting the object.
                            //Triangles can be one sided, so check the impact normal against the triangle normal.
                            if (dot < 0)
                            {
                                timeOfImpact = rayHit.T;
                            }
                        }
                    }
                    PhysicsThreadResources.GiveBack(triangle);
                }

            }
        }
Beispiel #11
0
        ///<summary>
        /// Initializes the manifold.
        ///</summary>
        ///<param name="newCollidableA">First collidable.</param>
        ///<param name="newCollidableB">Second collidable.</param>
        ///<exception cref="Exception">Thrown when the collidables being used are not of the proper type.</exception>
        public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
        {
            box = newCollidableA as ConvexCollidable<BoxShape>;
            sphere = newCollidableB as ConvexCollidable<SphereShape>;

            if (box == null || sphere == null)
            {
                box = newCollidableB as ConvexCollidable<BoxShape>;
                sphere = newCollidableA as ConvexCollidable<SphereShape>;
                if (box == null || sphere == null)
                {
                    throw new ArgumentException("Inappropriate types used to initialize pair.");
                }
            }

        }
        ///<summary>
        /// Initializes the manifold.
        ///</summary>
        ///<param name="newCollidableA">First collidable.</param>
        ///<param name="newCollidableB">Second collidable.</param>
        public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
        {
            collidableA = newCollidableA as ConvexCollidable;
            collidableB = newCollidableB as ConvexCollidable;
            pairTester.Initialize(newCollidableA, newCollidableB);


            if (collidableA == null || collidableB == null)
            {
                throw new Exception("Inappropriate types used to initialize pair tester.");
            }
        }
 /// <summary>
 /// Removes a collidable from the group.
 /// </summary>
 /// <param name="collidable">Collidable to remove.</param>
 public void Remove(Collidable collidable)
 {
     CollidableTree.Remove(collidable);
 }
Beispiel #14
0
 ///<summary>
 /// Initializes the manifold.
 ///</summary>
 ///<param name="newCollidableA">First collidable.</param>
 ///<param name="newCollidableB">Second collidable.</param>
 public abstract void Initialize(Collidable newCollidableA, Collidable newCollidableB);
        ///<summary>
        /// Updates the time of impact for the pair.
        ///</summary>
        ///<param name="requester">Collidable requesting the update.</param>
        ///<param name="dt">Timestep duration.</param>
        public override void UpdateTimeOfImpact(Collidable requester, float dt)
        {
            var collidableA = CollidableA as ConvexCollidable;
            var collidableB = CollidableB as ConvexCollidable;
            var modeA = collidableA.entity == null ? PositionUpdateMode.Discrete : collidableA.entity.PositionUpdateMode;
            var modeB = collidableB.entity == null ? PositionUpdateMode.Discrete : collidableB.entity.PositionUpdateMode;

            var overlap = BroadPhaseOverlap;
            if (
                    (overlap.entryA.IsActive || overlap.entryB.IsActive) && //At least one has to be active.
                    (
                        (
                            modeA == PositionUpdateMode.Continuous &&   //If both are continuous, only do the process for A.
                            modeB == PositionUpdateMode.Continuous &&
                            overlap.entryA == requester
                        ) ||
                        (
                            modeA == PositionUpdateMode.Continuous ^   //If only one is continuous, then we must do it.
                            modeB == PositionUpdateMode.Continuous
                        )

                    )
                )
            {
                //Only perform the test if the minimum radii are small enough relative to the size of the velocity.
                //Discrete objects have already had their linear motion integrated, so don't use their velocity.
                Vector3 velocity;
                if (modeA == PositionUpdateMode.Discrete)
                {
                    //CollidableA is static for the purposes of this continuous test.
                    velocity = collidableB.entity.linearVelocity;
                }
                else if (modeB == PositionUpdateMode.Discrete)
                {
                    //CollidableB is static for the purposes of this continuous test.
                    Vector3.Negate(ref collidableA.entity.linearVelocity, out velocity);
                }
                else
                {
                    //Both objects are moving.
                    Vector3.Subtract(ref collidableB.entity.linearVelocity, ref collidableA.entity.linearVelocity, out velocity);
                }
                Vector3.Multiply(ref velocity, dt, out velocity);
                float velocitySquared = velocity.LengthSquared();

                var minimumRadiusA = collidableA.Shape.MinimumRadius * MotionSettings.CoreShapeScaling;
                timeOfImpact = 1;
                if (minimumRadiusA * minimumRadiusA < velocitySquared)
                {
                    //Spherecast A against B.
                    RayHit rayHit;
                    if (GJKToolbox.CCDSphereCast(new Ray(collidableA.worldTransform.Position, -velocity), minimumRadiusA, collidableB.Shape, ref collidableB.worldTransform, timeOfImpact, out rayHit))
                        timeOfImpact = rayHit.T;
                }

                var minimumRadiusB = collidableB.Shape.MinimumRadius * MotionSettings.CoreShapeScaling;
                if (minimumRadiusB * minimumRadiusB < velocitySquared)
                {
                    //Spherecast B against A.
                    RayHit rayHit;
                    if (GJKToolbox.CCDSphereCast(new Ray(collidableB.worldTransform.Position, velocity), minimumRadiusB, collidableA.Shape, ref collidableA.worldTransform, timeOfImpact, out rayHit))
                        timeOfImpact = rayHit.T;
                }

                //If it's intersecting, throw our hands into the air and give up.
                //This is generally a perfectly acceptable thing to do, since it's either sitting
                //inside another object (no ccd makes sense) or we're still in an intersecting case
                //from a previous frame where CCD took place and a contact should have been created
                //to deal with interpenetrating velocity.  Sometimes that contact isn't sufficient,
                //but it's good enough.
                if (timeOfImpact == 0)
                    timeOfImpact = 1;
            }
        }
        /// <summary>
        /// Finds a supporting entity, the contact location, and the contact normal.
        /// </summary>
        /// <param name="location">Contact point between the wheel and the support.</param>
        /// <param name="normal">Contact normal between the wheel and the support.</param>
        /// <param name="suspensionLength">Length of the suspension at the contact.</param>
        /// <param name="supportingCollidable">Collidable supporting the wheel, if any.</param>
        /// <param name="entity">Supporting object.</param>
        /// <param name="material">Material of the wheel.</param>
        /// <returns>Whether or not any support was found.</returns>
        protected internal override bool FindSupport(out Vector3 location, out Vector3 normal, out float suspensionLength, out Collidable supportingCollidable, out Entity entity, out Material material)
        {
            suspensionLength = float.MaxValue;
            location = Toolbox.NoVector;
            supportingCollidable = null;
            entity = null;
            normal = Toolbox.NoVector;
            material = null;

            Collidable testCollidable;
            RayHit rayHit;

            bool hit = false;

            for (int i = 0; i < detector.CollisionInformation.pairs.Count; i++)
            {
                var pair = detector.CollisionInformation.pairs[i];
                testCollidable = (pair.BroadPhaseOverlap.entryA == detector.CollisionInformation ? pair.BroadPhaseOverlap.entryB : pair.BroadPhaseOverlap.entryA) as Collidable;
                if (testCollidable != null)
                {
                    if (CollisionRules.CollisionRuleCalculator(this, testCollidable) == CollisionRule.Normal &&
                        testCollidable.RayCast(new Ray(wheel.suspension.worldAttachmentPoint, wheel.suspension.worldDirection), wheel.suspension.restLength, out rayHit) &&
                        rayHit.T < suspensionLength)
                    {
                        suspensionLength = rayHit.T;
                        EntityCollidable entityCollidable;
                        if ((entityCollidable = testCollidable as EntityCollidable) != null)
                        {
                            entity = entityCollidable.Entity;
                            material = entityCollidable.Entity.Material;
                        }
                        else
                        {
                            entity = null;
                            supportingCollidable = testCollidable;
                            var materialOwner = testCollidable as IMaterialOwner;
                            if (materialOwner != null)
                                material = materialOwner.Material;
                        }
                        location = rayHit.Location;
                        normal = rayHit.Normal;
                        hit = true;
                    }
                }
            }
            if (hit)
            {
                if (suspensionLength > 0)
                    normal.Normalize();
                else
                    Vector3.Negate(ref wheel.suspension.worldDirection, out normal);
                return true;
            }
            return false;
        }
        ///<summary>
        /// Initializes the manifold.
        ///</summary>
        ///<param name="newCollidableA">First collidable.</param>
        ///<param name="newCollidableB">Second collidable.</param>
        ///<exception cref="Exception">Thrown when the collidables being used are not of the proper type.</exception>
        public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
        {
            boxA = (ConvexCollidable<BoxShape>)newCollidableA;
            boxB = (ConvexCollidable<BoxShape>)newCollidableB;


            if (boxA == null || boxB == null)
            {
                throw new ArgumentException("Inappropriate types used to initialize pair tester.");
            }
        }
Beispiel #18
0
		public override void UpdateTimeOfImpact( Collidable requester, float dt )
		{
			//Complicated and not vital. Leaving it out for simplicity. Check out InstancedMeshPairHandler for an example implementation.
			//Notice that we don't test for convex entity null explicitly.  The convex.IsActive property does that for us.
			if( convex.IsActive && convex.Entity.PositionUpdateMode == PositionUpdateMode.Continuous )
			{
				//Only perform the test if the minimum radii are small enough relative to the size of the velocity.
				Vector3 velocity = convex.Entity.LinearVelocity * dt;
				float velocitySquared = velocity.LengthSquared();

				var minimumRadius = convex.Shape.MinimumRadius * MotionSettings.CoreShapeScaling;
				timeOfImpact = 1;
				if( minimumRadius * minimumRadius < velocitySquared )
				{
					for( int i = 0; i < contactManifold.ActivePairs.Count; ++i )
					{
						var pair = contactManifold.ActivePairs.Values[i];
						//In the contact manifold, the box collidable is always put into the second slot.
						var boxCollidable = (ReusableBoxCollidable)pair.CollidableB;
						RayHit rayHit;
						var worldTransform = boxCollidable.WorldTransform;
						if( GJKToolbox.CCDSphereCast( new Ray( convex.WorldTransform.Position, velocity ), minimumRadius, boxCollidable.Shape, ref worldTransform, timeOfImpact, out rayHit ) &&
							rayHit.T > Toolbox.BigEpsilon )
						{
							timeOfImpact = rayHit.T;
						}
					}
				}
			}
		}
Beispiel #19
0
		public override void Initialize( Collidable newCollidableA, Collidable newCollidableB )
		{
			convex = newCollidableA as ConvexCollidable;
			voxelBlob = newCollidableB as VoxelBlob;


			if( convex == null || voxelBlob == null )
			{
				convex = newCollidableB as ConvexCollidable;
				voxelBlob = newCollidableA as VoxelBlob;
				if( convex == null || voxelBlob == null )
					throw new ArgumentException( "Inappropriate types used to initialize contact manifold." );
			}
			ActivePairs = new QuickDictionary<Int3, GeneralConvexPairTester>( BufferPools<Int3>.Locking, BufferPools<GeneralConvexPairTester>.Locking, BufferPools<int>.Locking, 3 );
			activePairsBackBuffer = new QuickDictionary<Int3, GeneralConvexPairTester>( BufferPools<Int3>.Locking, BufferPools<GeneralConvexPairTester>.Locking, BufferPools<int>.Locking, 3 );

		}
Beispiel #20
0
 void Events_ContactCreated(EntityCollidable sender, Collidable other, BEPUphysics.NarrowPhaseSystems.Pairs.CollidablePairHandler pair, ContactData contact)
 {
     this.Collided.Execute(other, pair.Contacts);
 }
Beispiel #21
0
        ///<summary>
        /// Initializes the manifold.
        ///</summary>
        ///<param name="newCollidableA">First collidable.</param>
        ///<param name="newCollidableB">Second collidable.</param>
        ///<exception cref="Exception">Thrown when the collidables being used are not of the proper type.</exception>
        public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
        {
            sphereA = (ConvexCollidable<SphereShape>)newCollidableA;
            sphereB = (ConvexCollidable<SphereShape>)newCollidableB;

            if (sphereA == null || sphereB == null)
            {
                throw new ArgumentException("Inappropriate types used to initialize pair.");
            }

        }
        ///<summary>
        /// Updates the time of impact for the pair.
        ///</summary>
        ///<param name="requester">Collidable requesting the update.</param>
        ///<param name="dt">Timestep duration.</param>
        public override void UpdateTimeOfImpact(Collidable requester, float dt)
        {
            var overlap = BroadPhaseOverlap;
            var triangleMode = triangle.entity == null ? PositionUpdateMode.Discrete : triangle.entity.PositionUpdateMode;
            var convexMode = convex.entity == null ? PositionUpdateMode.Discrete : convex.entity.PositionUpdateMode;
            if (
                    (overlap.entryA.IsActive || overlap.entryB.IsActive) && //At least one has to be active.
                    (
                        (
                            convexMode == PositionUpdateMode.Continuous &&   //If both are continuous, only do the process for A.
                            triangleMode == PositionUpdateMode.Continuous &&
                            overlap.entryA == requester
                        ) ||
                        (
                            convexMode == PositionUpdateMode.Continuous ^   //If only one is continuous, then we must do it.
                            triangleMode == PositionUpdateMode.Continuous
                        )
                    )
                )
            {

                //Only perform the test if the minimum radii are small enough relative to the size of the velocity.
                Vector3 velocity;
                if (convexMode == PositionUpdateMode.Discrete)
                {
                    //Triangle is static for the purposes of this continuous test.
                    velocity = triangle.entity.linearVelocity;
                }
                else if (triangleMode == PositionUpdateMode.Discrete)
                {
                    //Convex is static for the purposes of this continuous test.
                    Vector3.Negate(ref convex.entity.linearVelocity, out velocity);
                }
                else
                {
                    //Both objects are moving.
                    Vector3.Subtract(ref triangle.entity.linearVelocity, ref convex.entity.linearVelocity, out velocity);
                }
                Vector3.Multiply(ref velocity, dt, out velocity);
                float velocitySquared = velocity.LengthSquared();

                var minimumRadiusA = convex.Shape.MinimumRadius * MotionSettings.CoreShapeScaling;
                timeOfImpact = 1;
                if (minimumRadiusA * minimumRadiusA < velocitySquared)
                {
                    //Spherecast A against B.
                    RayHit rayHit;
                    if (GJKToolbox.CCDSphereCast(new Ray(convex.worldTransform.Position, -velocity), minimumRadiusA, triangle.Shape, ref triangle.worldTransform, timeOfImpact, out rayHit))
                    {
                        if (triangle.Shape.sidedness != TriangleSidedness.DoubleSided)
                        {
                            //Only perform sweep if the object is in danger of hitting the object.
                            //Triangles can be one sided, so check the impact normal against the triangle normal.
                            Vector3 AB, AC;
                            Vector3.Subtract(ref triangle.Shape.vB, ref triangle.Shape.vA, out AB);
                            Vector3.Subtract(ref triangle.Shape.vC, ref triangle.Shape.vA, out AC);
                            Vector3 normal;
                            Vector3.Cross(ref AB, ref AC, out normal);

                            float dot;
                            Vector3.Dot(ref rayHit.Normal, ref normal, out dot);
                            if (triangle.Shape.sidedness == TriangleSidedness.Counterclockwise && dot < 0 ||
                                triangle.Shape.sidedness == TriangleSidedness.Clockwise && dot > 0)
                            {
                                timeOfImpact = rayHit.T;
                            }
                        }
                        else
                        {
                            timeOfImpact = rayHit.T;
                        }
                    }
                }

                //TECHNICALLY, the triangle should be casted too.  But, given the way triangles are usually used and their tiny minimum radius, ignoring it is usually just fine.
                //var minimumRadiusB = triangle.minimumRadius * MotionSettings.CoreShapeScaling;
                //if (minimumRadiusB * minimumRadiusB < velocitySquared)
                //{
                //    //Spherecast B against A.
                //    RayHit rayHit;
                //    if (GJKToolbox.SphereCast(new Ray(triangle.entity.position, velocity), minimumRadiusB, convex.Shape, ref convex.worldTransform, 1, out rayHit) &&
                //        rayHit.T < timeOfImpact)
                //    {
                //        if (triangle.Shape.sidedness != TriangleSidedness.DoubleSided)
                //        {
                //            float dot;
                //            Vector3.Dot(ref rayHit.Normal, ref normal, out dot);
                //            if (dot > 0)
                //            {
                //                timeOfImpact = rayHit.T;
                //            }
                //        }
                //        else
                //        {
                //            timeOfImpact = rayHit.T;
                //        }
                //    }
                //}

                //If it's intersecting, throw our hands into the air and give up.
                //This is generally a perfectly acceptable thing to do, since it's either sitting
                //inside another object (no ccd makes sense) or we're still in an intersecting case
                //from a previous frame where CCD took place and a contact should have been created
                //to deal with interpenetrating velocity.  Sometimes that contact isn't sufficient,
                //but it's good enough.
                if (timeOfImpact == 0)
                    timeOfImpact = 1;
            }
        }
Beispiel #23
0
 static bool DefaultCCDFilter(Entity entity, Collidable other, CollidablePairHandler pair)
 {
     return pair.broadPhaseOverlap.collisionRule < CollisionRule.NoSolver;
 }
        /// <summary>
        /// Finds a supporting entity, the contact location, and the contact normal.
        /// </summary>
        /// <param name="location">Contact point between the wheel and the support.</param>
        /// <param name="normal">Contact normal between the wheel and the support.</param>
        /// <param name="suspensionLength">Length of the suspension at the contact.</param>
        /// <param name="supportingCollidable">Collidable supporting the wheel, if any.</param>
        /// <param name="entity">Supporting object.</param>
        /// <param name="material">Material of the wheel.</param>
        /// <returns>Whether or not any support was found.</returns>
        protected internal override bool FindSupport(out Vector3 location, out Vector3 normal, out float suspensionLength, out Collidable supportingCollidable, out Entity entity, out Material material)
        {
            suspensionLength = float.MaxValue;
            location = Toolbox.NoVector;
            supportingCollidable = null;
            entity = null;
            normal = Toolbox.NoVector;
            material = null;

            Collidable testCollidable;
            RayHit rayHit;

            bool hit = false;

            Quaternion localSteeringTransform;
            Quaternion.CreateFromAxisAngle(ref wheel.suspension.localDirection, steeringAngle, out localSteeringTransform);
            var startingTransform = new RigidTransform
            {
                Position = wheel.suspension.worldAttachmentPoint,
                Orientation = Quaternion.Concatenate(Quaternion.Concatenate(LocalWheelOrientation, IncludeSteeringTransformInCast ? localSteeringTransform : Quaternion.Identity), wheel.vehicle.Body.orientation)
            };
            Vector3 sweep;
            Vector3.Multiply(ref wheel.suspension.worldDirection, wheel.suspension.restLength, out sweep);

            for (int i = 0; i < detector.CollisionInformation.pairs.Count; i++)
            {
                var pair = detector.CollisionInformation.pairs[i];
                testCollidable = (pair.BroadPhaseOverlap.entryA == detector.CollisionInformation ? pair.BroadPhaseOverlap.entryB : pair.BroadPhaseOverlap.entryA) as Collidable;
                if (testCollidable != null)
                {
                    if (CollisionRules.CollisionRuleCalculator(this, testCollidable) == CollisionRule.Normal &&
                        testCollidable.ConvexCast(shape, ref startingTransform, ref sweep, out rayHit) &&
                        rayHit.T * wheel.suspension.restLength < suspensionLength)
                    {
                        suspensionLength = rayHit.T * wheel.suspension.restLength;
                        EntityCollidable entityCollidable;
                        if ((entityCollidable = testCollidable as EntityCollidable) != null)
                        {
                            entity = entityCollidable.Entity;
                            material = entityCollidable.Entity.Material;
                        }
                        else
                        {
                            entity = null;
                            supportingCollidable = testCollidable;
                            var materialOwner = testCollidable as IMaterialOwner;
                            if (materialOwner != null)
                                material = materialOwner.Material;
                        }
                        location = rayHit.Location;
                        normal = rayHit.Normal;
                        hit = true;
                    }
                }
            }
            if (hit)
            {
                if (suspensionLength > 0)
                {
                    float dot;
                    Vector3.Dot(ref normal, ref wheel.suspension.worldDirection, out dot);
                    if (dot > 0)
                    {
                        //The cylinder cast produced a normal which is opposite of what we expect.
                        Vector3.Negate(ref normal, out normal);
                    }
                    normal.Normalize();
                }
                else
                    Vector3.Negate(ref wheel.suspension.worldDirection, out normal);
                return true;
            }
            return false;
        }
Beispiel #25
0
 public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
 {
     convex = newCollidableA as ConvexCollidable;
     mesh = newCollidableB as FullChunkObject;
     if (convex == null || mesh == null)
     {
         convex = newCollidableB as ConvexCollidable;
         mesh = newCollidableA as FullChunkObject;
         if (convex == null || mesh == null)
         {
             throw new ArgumentException("Inappropriate types used to initialize contact manifold.");
         }
     }
     ActivePairs = new QuickDictionary<Vector3i, GeneralConvexPairTester>(BufferPools<Vector3i>.Locking, BufferPools<GeneralConvexPairTester>.Locking, BufferPools<int>.Locking, 3);
     activePairsBackBuffer = new QuickDictionary<Vector3i, GeneralConvexPairTester>(BufferPools<Vector3i>.Locking, BufferPools<GeneralConvexPairTester>.Locking, BufferPools<int>.Locking, 3);
 }
        public override void Initialize(Collidable newCollidableA, Collidable newCollidableB)
        {
            convex = newCollidableA as ConvexCollidable;
            triangle = newCollidableB as ConvexCollidable<TriangleShape>;


            if (convex == null || triangle == null)
            {
                convex = newCollidableB as ConvexCollidable;
                triangle = newCollidableA as ConvexCollidable<TriangleShape>;
                if (convex == null || triangle == null)
                    throw new ArgumentException("Inappropriate types used to initialize contact manifold.");
            }

            pairTester.Initialize(convex.Shape);
        }
 public void CollisionEnded(EntityCollidable sender, Collidable other, CollidablePairHandler collisionPair)
 {
     if (other == acceptedTrigger)
     {
         //If the detector ceases to collide, get rid of the spawned box.
         movedBox.Position = new Vector3(-4, 5, 0);
         movedBox.Orientation = Quaternion.Identity;
         movedBox.LinearVelocity = Vector3.Zero;
         movedBox.AngularVelocity = Vector3.Zero;
     }
 }
 /// <summary>
 /// Adds a new collidable to the group.
 /// </summary>
 /// <param name="collidable">Collidable to remove.</param>
 public void Add(Collidable collidable)
 {
     CollidableTree.Add(collidable);
 }
Beispiel #29
0
 /// <summary>
 /// Finds a supporting entity, the contact location, and the contact normal.
 /// </summary>
 /// <param name="location">Contact point between the wheel and the support.</param>
 /// <param name="normal">Contact normal between the wheel and the support.</param>
 /// <param name="suspensionLength">Length of the suspension at the contact.</param>
 /// <param name="supportCollidable">Collidable supporting the wheel, if any.</param>
 /// <param name="entity">Entity supporting the wheel, if any.</param>
 /// <param name="material">Material of the support.</param>
 /// <returns>Whether or not any support was found.</returns>
 protected internal abstract bool FindSupport(out Vector3 location, out Vector3 normal, out float suspensionLength, out Collidable supportCollidable, out Entity entity, out Material material);
Beispiel #30
0
		float GetSubmergedHeight(Collidable info, float maxLength, float boundingBoxHeight, ref Vector3 rayOrigin, ref Vector3 xSpacing, ref Vector3 zSpacing, int i, int j, out Vector3 volumeCenter)
		{
			Ray ray;
			Vector3.Multiply(ref xSpacing, i, out ray.Position);
			Vector3.Multiply(ref zSpacing, j, out ray.Direction);
			Vector3.Add(ref ray.Position, ref ray.Direction, out ray.Position);
			Vector3.Add(ref ray.Position, ref rayOrigin, out ray.Position);
			ray.Direction = upVector;
			//do a bottom-up raycast.
			BEPUutilities.RayHit rayHit;
			//Only go up to maxLength.  If it's further away than maxLength, then it's above the water and it doesn't contribute anything.
			if (info.RayCast(ray, maxLength, out rayHit))
			{
				//Position the ray to point from the other side.
				Vector3.Multiply(ref ray.Direction, boundingBoxHeight, out ray.Direction);
				Vector3.Add(ref ray.Position, ref ray.Direction, out ray.Position);
				Vector3.Negate(ref upVector, out ray.Direction);
				float bottomY = rayHit.Location.Y;
				float bottom = rayHit.T;
				Vector3 bottomPosition = rayHit.Location;
				if (info.RayCast(ray, boundingBoxHeight - rayHit.T, out rayHit))
				{
					Vector3.Add(ref rayHit.Location, ref bottomPosition, out volumeCenter);
					Vector3.Multiply(ref volumeCenter, .5f, out volumeCenter);
					return Math.Min(surfacePlaneHeight - bottomY, boundingBoxHeight - rayHit.T - bottom);
				}
				//This inner raycast should always hit, but just in case it doesn't due to some numerical problem, give it a graceful way out.
				volumeCenter = Vector3.Zero;
				return 0;
			}
			volumeCenter = Vector3.Zero;
			return 0;
		}