PageRenderTime 213ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/BEPUphysics/NarrowPhaseSystems/Pairs/MobileMeshPairHandler.cs

#
C# | 267 lines | 187 code | 43 blank | 37 comment | 43 complexity | 0d16a97b91e70a96711e80b66b4240d0 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. using System;
  2. using BEPUphysics.BroadPhaseEntries;
  3. using BEPUphysics.BroadPhaseEntries.MobileCollidables;
  4. using BEPUphysics.CollisionTests.CollisionAlgorithms.GJK;
  5. using BEPUphysics.CollisionTests.Manifolds;
  6. using BEPUphysics.Constraints.Collision;
  7. using BEPUphysics.DataStructures;
  8. using BEPUutilities.DataStructures;
  9. using BEPUphysics.PositionUpdating;
  10. using BEPUphysics.Settings;
  11. using Microsoft.Xna.Framework;
  12. using BEPUutilities;
  13. namespace BEPUphysics.NarrowPhaseSystems.Pairs
  14. {
  15. ///<summary>
  16. /// Handles a mobile mesh-convex collision pair.
  17. ///</summary>
  18. public abstract class MobileMeshPairHandler : StandardPairHandler
  19. {
  20. MobileMeshCollidable mobileMesh;
  21. ConvexCollidable convex;
  22. NonConvexContactManifoldConstraint contactConstraint = new NonConvexContactManifoldConstraint();
  23. public override Collidable CollidableA
  24. {
  25. get { return convex; }
  26. }
  27. public override Collidable CollidableB
  28. {
  29. get { return mobileMesh; }
  30. }
  31. public override Entities.Entity EntityA
  32. {
  33. get { return convex.entity; }
  34. }
  35. public override Entities.Entity EntityB
  36. {
  37. get { return mobileMesh.entity; }
  38. }
  39. /// <summary>
  40. /// Gets the contact manifold used by the pair handler.
  41. /// </summary>
  42. public override ContactManifold ContactManifold
  43. {
  44. get { return MeshManifold; }
  45. }
  46. /// <summary>
  47. /// Gets the contact constraint used by the pair handler.
  48. /// </summary>
  49. public override ContactManifoldConstraint ContactConstraint
  50. {
  51. get { return contactConstraint; }
  52. }
  53. protected internal abstract MobileMeshContactManifold MeshManifold { get; }
  54. ///<summary>
  55. /// Initializes the pair handler.
  56. ///</summary>
  57. ///<param name="entryA">First entry in the pair.</param>
  58. ///<param name="entryB">Second entry in the pair.</param>
  59. public override void Initialize(BroadPhaseEntry entryA, BroadPhaseEntry entryB)
  60. {
  61. mobileMesh = entryA as MobileMeshCollidable;
  62. convex = entryB as ConvexCollidable;
  63. if (mobileMesh == null || convex == null)
  64. {
  65. mobileMesh = entryB as MobileMeshCollidable;
  66. convex = entryA as ConvexCollidable;
  67. if (mobileMesh == null || convex == null)
  68. throw new Exception("Inappropriate types used to initialize pair.");
  69. }
  70. //Contact normal goes from A to B.
  71. broadPhaseOverlap.entryA = convex;
  72. broadPhaseOverlap.entryB = mobileMesh;
  73. //It's possible that the convex does not have an entity if it is a proxy for a non-entity collidable.
  74. //Similarly, the mesh could be a query object.
  75. UpdateMaterialProperties(convex.entity != null ? convex.entity.material : null, mobileMesh.entity != null ? mobileMesh.entity.material : null);
  76. base.Initialize(entryA, entryB);
  77. }
  78. ///<summary>
  79. /// Cleans up the pair handler.
  80. ///</summary>
  81. public override void CleanUp()
  82. {
  83. base.CleanUp();
  84. mobileMesh = null;
  85. convex = null;
  86. }
  87. ///<summary>
  88. /// Updates the time of impact for the pair.
  89. ///</summary>
  90. ///<param name="requester">Collidable requesting the update.</param>
  91. ///<param name="dt">Timestep duration.</param>
  92. public override void UpdateTimeOfImpact(Collidable requester, float dt)
  93. {
  94. var overlap = BroadPhaseOverlap;
  95. var meshMode = mobileMesh.entity == null ? PositionUpdateMode.Discrete : mobileMesh.entity.PositionUpdateMode;
  96. var convexMode = convex.entity == null ? PositionUpdateMode.Discrete : convex.entity.PositionUpdateMode;
  97. if (
  98. (mobileMesh.IsActive || convex.IsActive) && //At least one has to be active.
  99. (
  100. (
  101. convexMode == PositionUpdateMode.Continuous && //If both are continuous, only do the process for A.
  102. meshMode == PositionUpdateMode.Continuous &&
  103. overlap.entryA == requester
  104. ) ||
  105. (
  106. convexMode == PositionUpdateMode.Continuous ^ //If only one is continuous, then we must do it.
  107. meshMode == PositionUpdateMode.Continuous
  108. )
  109. )
  110. )
  111. {
  112. //TODO: This system could be made more robust by using a similar region-based rejection of edges.
  113. //CCD events are awfully rare under normal circumstances, so this isn't usually an issue.
  114. //Only perform the test if the minimum radii are small enough relative to the size of the velocity.
  115. Vector3 velocity;
  116. if (convexMode == PositionUpdateMode.Discrete)
  117. {
  118. //Convex is static for the purposes of CCD.
  119. Vector3.Negate(ref mobileMesh.entity.linearVelocity, out velocity);
  120. }
  121. else if (meshMode == PositionUpdateMode.Discrete)
  122. {
  123. //Mesh is static for the purposes of CCD.
  124. velocity = convex.entity.linearVelocity;
  125. }
  126. else
  127. {
  128. //Both objects can move.
  129. Vector3.Subtract(ref convex.entity.linearVelocity, ref mobileMesh.entity.linearVelocity, out velocity);
  130. }
  131. Vector3.Multiply(ref velocity, dt, out velocity);
  132. float velocitySquared = velocity.LengthSquared();
  133. var minimumRadius = convex.Shape.minimumRadius * MotionSettings.CoreShapeScaling;
  134. timeOfImpact = 1;
  135. if (minimumRadius * minimumRadius < velocitySquared)
  136. {
  137. TriangleSidedness sidedness = mobileMesh.Shape.Sidedness;
  138. Matrix3x3 orientation;
  139. Matrix3x3.CreateFromQuaternion(ref mobileMesh.worldTransform.Orientation, out orientation);
  140. var triangle = PhysicsResources.GetTriangle();
  141. triangle.collisionMargin = 0;
  142. //Spherecast against all triangles to find the earliest time.
  143. for (int i = 0; i < MeshManifold.overlappedTriangles.Count; i++)
  144. {
  145. MeshBoundingBoxTreeData data = mobileMesh.Shape.TriangleMesh.Data;
  146. int triangleIndex = MeshManifold.overlappedTriangles.Elements[i];
  147. data.GetTriangle(triangleIndex, out triangle.vA, out triangle.vB, out triangle.vC);
  148. Matrix3x3.Transform(ref triangle.vA, ref orientation, out triangle.vA);
  149. Matrix3x3.Transform(ref triangle.vB, ref orientation, out triangle.vB);
  150. Matrix3x3.Transform(ref triangle.vC, ref orientation, out triangle.vC);
  151. Vector3.Add(ref triangle.vA, ref mobileMesh.worldTransform.Position, out triangle.vA);
  152. Vector3.Add(ref triangle.vB, ref mobileMesh.worldTransform.Position, out triangle.vB);
  153. Vector3.Add(ref triangle.vC, ref mobileMesh.worldTransform.Position, out triangle.vC);
  154. //Put the triangle into 'localish' space of the convex.
  155. Vector3.Subtract(ref triangle.vA, ref convex.worldTransform.Position, out triangle.vA);
  156. Vector3.Subtract(ref triangle.vB, ref convex.worldTransform.Position, out triangle.vB);
  157. Vector3.Subtract(ref triangle.vC, ref convex.worldTransform.Position, out triangle.vC);
  158. RayHit rayHit;
  159. if (GJKToolbox.CCDSphereCast(new Ray(Toolbox.ZeroVector, velocity), minimumRadius, triangle, ref Toolbox.RigidIdentity, timeOfImpact, out rayHit) &&
  160. rayHit.T > Toolbox.BigEpsilon)
  161. {
  162. if (sidedness != TriangleSidedness.DoubleSided)
  163. {
  164. Vector3 AB, AC;
  165. Vector3.Subtract(ref triangle.vB, ref triangle.vA, out AB);
  166. Vector3.Subtract(ref triangle.vC, ref triangle.vA, out AC);
  167. Vector3 normal;
  168. Vector3.Cross(ref AB, ref AC, out normal);
  169. float dot;
  170. Vector3.Dot(ref normal, ref rayHit.Normal, out dot);
  171. //Only perform sweep if the object is in danger of hitting the object.
  172. //Triangles can be one sided, so check the impact normal against the triangle normal.
  173. if (sidedness == TriangleSidedness.Counterclockwise && dot < 0 ||
  174. sidedness == TriangleSidedness.Clockwise && dot > 0)
  175. {
  176. timeOfImpact = rayHit.T;
  177. }
  178. }
  179. else
  180. {
  181. timeOfImpact = rayHit.T;
  182. }
  183. }
  184. }
  185. PhysicsResources.GiveBack(triangle);
  186. }
  187. }
  188. }
  189. protected internal override void GetContactInformation(int index, out ContactInformation info)
  190. {
  191. info.Contact = MeshManifold.contacts.Elements[index];
  192. //Find the contact's normal and friction forces.
  193. info.FrictionImpulse = 0;
  194. info.NormalImpulse = 0;
  195. for (int i = 0; i < contactConstraint.frictionConstraints.Count; i++)
  196. {
  197. if (contactConstraint.frictionConstraints.Elements[i].PenetrationConstraint.contact == info.Contact)
  198. {
  199. info.FrictionImpulse = contactConstraint.frictionConstraints.Elements[i].accumulatedImpulse;
  200. info.NormalImpulse = contactConstraint.frictionConstraints.Elements[i].PenetrationConstraint.accumulatedImpulse;
  201. break;
  202. }
  203. }
  204. //Compute relative velocity
  205. Vector3 velocity;
  206. if (convex.entity != null)
  207. {
  208. Vector3.Subtract(ref info.Contact.Position, ref convex.entity.position, out velocity);
  209. Vector3.Cross(ref convex.entity.angularVelocity, ref velocity, out velocity);
  210. Vector3.Add(ref velocity, ref convex.entity.linearVelocity, out info.RelativeVelocity);
  211. }
  212. else
  213. info.RelativeVelocity = new Vector3();
  214. if (mobileMesh.entity != null)
  215. {
  216. Vector3.Subtract(ref info.Contact.Position, ref mobileMesh.entity.position, out velocity);
  217. Vector3.Cross(ref mobileMesh.entity.angularVelocity, ref velocity, out velocity);
  218. Vector3.Add(ref velocity, ref mobileMesh.entity.linearVelocity, out velocity);
  219. Vector3.Subtract(ref info.RelativeVelocity, ref velocity, out info.RelativeVelocity);
  220. }
  221. info.Pair = this;
  222. }
  223. }
  224. }