/// <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); }
/// <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); }
/// <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); }
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); } }
/// <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. } } } }
/// <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); }
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); }