Esempio n. 1
0
        /// <summary>
        /// <para>Casts a convex shape against the space.</para>
        /// <para>Convex casts are sensitive to length; avoid extremely long convex casts for better stability and performance.</para>
        /// </summary>
        /// <param name="castShape">Shape to cast.</param>
        /// <param name="startingTransform">Initial transform of the shape.</param>
        /// <param name="sweep">Sweep to apply to the shape. Avoid extremely long convex casts for better stability and performance.</param>
        /// <param name="filter">Delegate to prune out hit candidates before performing a cast against them. Return true from the filter to process an entry or false to ignore the entry.</param>
        /// <param name="castResult">Hit data, if any.</param>
        /// <returns>Whether or not the cast hit anything.</returns>
        public bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, Func <BroadPhaseEntry, bool> filter, out RayCastResult castResult)
        {
            var  castResults = PhysicsResources.GetRayCastResultList();
            bool didHit      = ConvexCast(castShape, ref startingTransform, ref sweep, filter, castResults);

            castResult = castResults.Elements[0];
            for (int i = 1; i < castResults.Count; i++)
            {
                RayCastResult candidate = castResults.Elements[i];
                if (candidate.HitData.T < castResult.HitData.T)
                {
                    castResult = candidate;
                }
            }
            PhysicsResources.GiveBack(castResults);
            return(didHit);
        }
Esempio n. 2
0
        /// <summary>
        /// Tests a ray against the space.
        /// </summary>
        /// <param name="ray">Ray to test.</param>
        /// <param name="maximumLength">Maximum length of the ray in units of the ray direction's length.</param>
        /// <param name="filter">Delegate to prune out hit candidates before performing a ray cast against them. Return true from the filter to process an entry or false to ignore the entry.</param>
        /// <param name="result">Hit data of the ray, if any.</param>
        /// <returns>Whether or not the ray hit anything.</returns>
        public bool RayCast(Ray ray, float maximumLength, Func <BroadPhaseEntry, bool> filter, out RayCastResult result)
        {
            var  resultsList = PhysicsResources.GetRayCastResultList();
            bool didHit      = RayCast(ray, maximumLength, filter, resultsList);

            result = resultsList.Elements[0];
            for (int i = 1; i < resultsList.Count; i++)
            {
                RayCastResult candidate = resultsList.Elements[i];
                if (candidate.HitData.T < result.HitData.T)
                {
                    result = candidate;
                }
            }
            PhysicsResources.GiveBack(resultsList);

            return(didHit);
        }
Esempio n. 3
0
        /// <summary>
        /// Tests a ray against the space, possibly returning multiple hits.
        /// </summary>
        /// <param name="ray">Ray to test.</param>
        /// <param name="maximumLength">Maximum length of the ray in units of the ray direction's length.</param>
        /// <param name="filter">Delegate to prune out hit candidates before performing a cast against them. Return true from the filter to process an entry or false to ignore the entry.</param>
        /// <param name="outputRayCastResults">Hit data of the ray, if any.</param>
        /// <returns>Whether or not the ray hit anything.</returns>
        public bool RayCast(Ray ray, float maximumLength, Func <BroadPhaseEntry, bool> filter, IList <RayCastResult> outputRayCastResults)
        {
            var outputIntersections = PhysicsResources.GetBroadPhaseEntryList();

            if (BroadPhase.QueryAccelerator.RayCast(ray, maximumLength, outputIntersections))
            {
                for (int i = 0; i < outputIntersections.Count; i++)
                {
                    RayHit          rayHit;
                    BroadPhaseEntry candidate = outputIntersections.Elements[i];
                    if (candidate.RayCast(ray, maximumLength, filter, out rayHit))
                    {
                        outputRayCastResults.Add(new RayCastResult(rayHit, candidate));
                    }
                }
            }
            PhysicsResources.GiveBack(outputIntersections);
            return(outputRayCastResults.Count > 0);
        }
Esempio n. 4
0
        void UpdateConnectedMembers()
        {
            //Since we're about to change this updateable's connections, make sure the
            //simulation islands hear about it.  This is NOT thread safe.
            var deactivationManager = simulationIslandConnection.DeactivationManager;

            //Orphan the simulation island connection since it's about to get replaced.
            //There's three possible situations here:
            //1) We belong to the DeactivationManager.
            //2) We don't belong to a DeactivationManager and the connection is slated for removal (we were in the deactivation manager before).
            //   This can happen when a solver updateable associated with a pair gets removed and cleaned up.
            //3) We don't belong to a DeactivationManager and the connection is not slated for removal (we weren't in a deactivation manager before).

            //In Case #1, all we have to do is orphan the connection and remove it from the manager. This performs any splits necessary. The replacement connection will force any necessary merges.
            //In Case #2, we were just removed but the connection is still considered to have an owner.
            //It won't get cleaned up by the removal, and doing it here would be premature: orphan the connection so the next deactivation manager splits flush cleans it up!
            //In Case #3, we have full control over the simulation island connection because there is no interaction with a deactivation manager. We can just get rid of it directly.
            simulationIslandConnection.Owner = null;
            if (deactivationManager != null)
            {
                deactivationManager.Remove(simulationIslandConnection);
            }
            else if (!simulationIslandConnection.SlatedForRemoval)     //If it's already been removed, cleaning it ourselves would prevent proper simulation island splits in the deactivation manager split flush.
            {
                PhysicsResources.GiveBack(simulationIslandConnection); //Well, since we're going to orphan the connection, we'll need to take care of its trash.
            }
            //The SimulationIslandConnection is immutable.
            //So create a new one!
            //Assume we've already dealt with the old connection.
            simulationIslandConnection = PhysicsResources.GetSimulationIslandConnection();
            for (int i = 0; i < involvedEntities.Count; i++)
            {
                simulationIslandConnection.Add(involvedEntities.Elements[i].activityInformation);
            }
            simulationIslandConnection.Owner = this;


            //Add the new reference back.
            if (deactivationManager != null)
            {
                deactivationManager.Add(simulationIslandConnection);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// <para>Casts a convex shape against the space.</para>
        /// <para>Convex casts are sensitive to length; avoid extremely long convex casts for better stability and performance.</para>
        /// </summary>
        /// <param name="castShape">Shape to cast.</param>
        /// <param name="startingTransform">Initial transform of the shape.</param>
        /// <param name="sweep">Sweep to apply to the shape. Avoid extremely long convex casts for better stability and performance.</param>
        /// <param name="filter">Delegate to prune out hit candidates before performing a cast against them. Return true from the filter to process an entry or false to ignore the entry.</param>
        /// <param name="outputCastResults">Hit data, if any.</param>
        /// <returns>Whether or not the cast hit anything.</returns>
        public bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, Func <BroadPhaseEntry, bool> filter, IList <RayCastResult> outputCastResults)
        {
            var         overlappedElements = PhysicsResources.GetBroadPhaseEntryList();
            BoundingBox boundingBox;

            castShape.GetSweptBoundingBox(ref startingTransform, ref sweep, out boundingBox);

            BroadPhase.QueryAccelerator.GetEntries(boundingBox, overlappedElements);
            for (int i = 0; i < overlappedElements.Count; ++i)
            {
                RayHit hit;
                if (overlappedElements.Elements[i].ConvexCast(castShape, ref startingTransform, ref sweep, filter, out hit))
                {
                    outputCastResults.Add(new RayCastResult {
                        HitData = hit, HitObject = overlappedElements.Elements[i]
                    });
                }
            }
            PhysicsResources.GiveBack(overlappedElements);
            return(outputCastResults.Count > 0);
        }
        void FlushSplits()
        {
            //Only do a portion of the total splits.
            int maxAttempts = Math.Max(minimumSplitAttempts, (int)(splitAttempts.Count * maximumSplitAttemptsFraction));
            int attempts    = 0;
            SimulationIslandConnection attempt;

            while (attempts < maxAttempts && splitAttempts.TryUnsafeDequeueFirst(out attempt))
            {
                if (attempt.SlatedForRemoval)         //If it was re-added, don't split!
                {
                    attempt.SlatedForRemoval = false; //Reset the removal state so that future adds will add back references, since we're about to remove them.
                    attempt.RemoveReferencesFromConnectedMembers();
                    bool triedToSplit = false;
                    for (int i = 0; i < attempt.entries.Count; i++)
                    {
                        for (int j = i + 1; j < attempt.entries.Count; j++)
                        {
                            triedToSplit |= TryToSplit(attempt.entries.Elements[i].Member, attempt.entries.Elements[j].Member);
                        }
                    }
                    //Only count the split if it does any work.
                    if (triedToSplit)
                    {
                        attempts++;
                    }
                    if (attempt.Owner == null)
                    {
                        //It's an orphan connection.  No one owns it, and now that it's been dequeued from the deactivation manager,
                        //it has no home at all.
                        //Don't let it rot- return it to the pool!
                        PhysicsResources.GiveBack(attempt);
                        //This occurs when a constraint changes members.
                        //Because connections need to be immutable for this scheme to work,
                        //the old connection is orphaned and put into the deactivation manager's removal queue
                        //while a new one from the pool takes its place.
                    }
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Tests a ray against the collidable.
        /// </summary>
        /// <param name="ray">Ray to test.</param>
        /// <param name="maximumLength">Maximum length, in units of the ray's direction's length, to test.</param>
        /// <param name="result">Hit data, if any.</param>
        /// <returns>Whether or not the ray hit the entry.</returns>
        public bool RayCast(Ray ray, float maximumLength, out RayCastResult result)
        {
            var outputOverlappedElements = PhysicsResources.GetCollidableList();

            CollidableTree.GetOverlaps(ray, maximumLength, outputOverlappedElements);
            result           = new RayCastResult();
            result.HitData.T = float.MaxValue;
            for (int i = 0; i < outputOverlappedElements.Count; ++i)
            {
                RayHit hit;
                if (outputOverlappedElements.Elements[i].RayCast(ray, maximumLength, out hit))
                {
                    if (hit.T < result.HitData.T)
                    {
                        result.HitData   = hit;
                        result.HitObject = outputOverlappedElements.Elements[i];
                    }
                }
            }
            PhysicsResources.GiveBack(outputOverlappedElements);
            return(result.HitData.T < float.MaxValue);
        }
        protected override TriangleCollidable GetOpposingCollidable(int index)
        {
            //Construct a TriangleCollidable from the static mesh.
            var     toReturn  = PhysicsResources.GetTriangleCollidable();
            Vector3 terrainUp = new Vector3(mesh.worldTransform.LinearTransform.M21, mesh.worldTransform.LinearTransform.M22, mesh.worldTransform.LinearTransform.M23);
            float   dot;
            Vector3 AB, AC, normal;
            var     shape = toReturn.Shape;

            mesh.Shape.GetTriangle(index, ref mesh.worldTransform, out shape.vA, out shape.vB, out shape.vC);
            Vector3 center;

            Vector3.Add(ref shape.vA, ref shape.vB, out center);
            Vector3.Add(ref center, ref shape.vC, out center);
            Vector3.Multiply(ref center, 1 / 3f, out center);
            Vector3.Subtract(ref shape.vA, ref center, out shape.vA);
            Vector3.Subtract(ref shape.vB, ref center, out shape.vB);
            Vector3.Subtract(ref shape.vC, ref center, out shape.vC);

            //The bounding box doesn't update by itself.
            toReturn.worldTransform.Position    = center;
            toReturn.worldTransform.Orientation = Quaternion.Identity;
            toReturn.UpdateBoundingBoxInternal(0);

            Vector3.Subtract(ref shape.vB, ref shape.vA, out AB);
            Vector3.Subtract(ref shape.vC, ref shape.vA, out AC);
            Vector3.Cross(ref AB, ref AC, out normal);
            Vector3.Dot(ref terrainUp, ref normal, out dot);
            if (dot > 0)
            {
                shape.sidedness = TriangleSidedness.Clockwise;
            }
            else
            {
                shape.sidedness = TriangleSidedness.Counterclockwise;
            }
            shape.collisionMargin = mobileMesh.Shape.MeshCollisionMargin;
            return(toReturn);
        }
Esempio n. 9
0
        protected override TriangleCollidable GetOpposingCollidable(int index)
        {
            //Construct a TriangleCollidable from the static mesh.
            var toReturn = PhysicsResources.GetTriangleCollidable();
            var shape    = toReturn.Shape;

            mesh.Mesh.Data.GetTriangle(index, out shape.vA, out shape.vB, out shape.vC);
            Vector3 center;

            Vector3.Add(ref shape.vA, ref shape.vB, out center);
            Vector3.Add(ref center, ref shape.vC, out center);
            Vector3.Multiply(ref center, 1 / 3f, out center);
            Vector3.Subtract(ref shape.vA, ref center, out shape.vA);
            Vector3.Subtract(ref shape.vB, ref center, out shape.vB);
            Vector3.Subtract(ref shape.vC, ref center, out shape.vC);
            //The bounding box doesn't update by itself.
            toReturn.worldTransform.Position    = center;
            toReturn.worldTransform.Orientation = Quaternion.Identity;
            toReturn.UpdateBoundingBoxInternal(0);
            shape.sidedness       = mesh.sidedness;
            shape.collisionMargin = mobileMesh.Shape.MeshCollisionMargin;
            return(toReturn);
        }
 /// <summary>
 /// Cleans up the collidable.
 /// </summary>
 /// <param name="collidable">Collidable to clean up.</param>
 protected virtual void CleanUpCollidable(TriangleCollidable collidable)
 {
     PhysicsResources.GiveBack(collidable);
 }