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

/BEPUphysics/NarrowPhaseSystems/Pairs/InstancedMeshPairHandler.cs

#
C# | 216 lines | 146 code | 37 blank | 33 comment | 27 complexity | b886d66e21b7a0f3dfde93aa49197b54 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 instanced mesh-convex collision pair.
  17. ///</summary>
  18. public abstract class InstancedMeshPairHandler : StandardPairHandler
  19. {
  20. InstancedMesh instancedMesh;
  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 instancedMesh; }
  30. }
  31. public override Entities.Entity EntityA
  32. {
  33. get { return convex.entity; }
  34. }
  35. public override Entities.Entity EntityB
  36. {
  37. get { return null; }
  38. }
  39. /// <summary>
  40. /// Gets the contact constraint used by the pair handler.
  41. /// </summary>
  42. public override ContactManifoldConstraint ContactConstraint
  43. {
  44. get { return contactConstraint; }
  45. }
  46. /// <summary>
  47. /// Gets the contact manifold used by the pair handler.
  48. /// </summary>
  49. public override ContactManifold ContactManifold
  50. {
  51. get { return MeshManifold; }
  52. }
  53. protected abstract InstancedMeshContactManifold 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. instancedMesh = entryA as InstancedMesh;
  62. convex = entryB as ConvexCollidable;
  63. if (instancedMesh == null || convex == null)
  64. {
  65. instancedMesh = entryB as InstancedMesh;
  66. convex = entryA as ConvexCollidable;
  67. if (instancedMesh == 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 = instancedMesh;
  73. UpdateMaterialProperties(convex.entity != null ? convex.entity.material : null, instancedMesh.material);
  74. base.Initialize(entryA, entryB);
  75. }
  76. ///<summary>
  77. /// Cleans up the pair handler.
  78. ///</summary>
  79. public override void CleanUp()
  80. {
  81. base.CleanUp();
  82. instancedMesh = null;
  83. convex = null;
  84. }
  85. ///<summary>
  86. /// Updates the time of impact for the pair.
  87. ///</summary>
  88. ///<param name="requester">Collidable requesting the update.</param>
  89. ///<param name="dt">Timestep duration.</param>
  90. public override void UpdateTimeOfImpact(Collidable requester, float dt)
  91. {
  92. //Notice that we don't test for convex entity null explicitly. The convex.IsActive property does that for us.
  93. if (convex.IsActive && convex.entity.PositionUpdateMode == PositionUpdateMode.Continuous)
  94. {
  95. //TODO: This system could be made more robust by using a similar region-based rejection of edges.
  96. //CCD events are awfully rare under normal circumstances, so this isn't usually an issue.
  97. //Only perform the test if the minimum radii are small enough relative to the size of the velocity.
  98. Vector3 velocity;
  99. Vector3.Multiply(ref convex.entity.linearVelocity, dt, out velocity);
  100. float velocitySquared = velocity.LengthSquared();
  101. var minimumRadius = convex.Shape.minimumRadius * MotionSettings.CoreShapeScaling;
  102. timeOfImpact = 1;
  103. if (minimumRadius * minimumRadius < velocitySquared)
  104. {
  105. var triangle = PhysicsResources.GetTriangle();
  106. triangle.collisionMargin = 0;
  107. //Spherecast against all triangles to find the earliest time.
  108. for (int i = 0; i < MeshManifold.overlappedTriangles.Count; i++)
  109. {
  110. MeshBoundingBoxTreeData data = instancedMesh.Shape.TriangleMesh.Data;
  111. int triangleIndex = MeshManifold.overlappedTriangles.Elements[i];
  112. data.GetTriangle(triangleIndex, out triangle.vA, out triangle.vB, out triangle.vC);
  113. AffineTransform.Transform(ref triangle.vA, ref instancedMesh.worldTransform, out triangle.vA);
  114. AffineTransform.Transform(ref triangle.vB, ref instancedMesh.worldTransform, out triangle.vB);
  115. AffineTransform.Transform(ref triangle.vC, ref instancedMesh.worldTransform, out triangle.vC);
  116. //Put the triangle into 'localish' space of the convex.
  117. Vector3.Subtract(ref triangle.vA, ref convex.worldTransform.Position, out triangle.vA);
  118. Vector3.Subtract(ref triangle.vB, ref convex.worldTransform.Position, out triangle.vB);
  119. Vector3.Subtract(ref triangle.vC, ref convex.worldTransform.Position, out triangle.vC);
  120. RayHit rayHit;
  121. if (GJKToolbox.CCDSphereCast(new Ray(Toolbox.ZeroVector, velocity), minimumRadius, triangle, ref Toolbox.RigidIdentity, timeOfImpact, out rayHit) &&
  122. rayHit.T > Toolbox.BigEpsilon)
  123. {
  124. if (instancedMesh.sidedness != TriangleSidedness.DoubleSided)
  125. {
  126. Vector3 AB, AC;
  127. Vector3.Subtract(ref triangle.vB, ref triangle.vA, out AB);
  128. Vector3.Subtract(ref triangle.vC, ref triangle.vA, out AC);
  129. Vector3 normal;
  130. Vector3.Cross(ref AB, ref AC, out normal);
  131. float dot;
  132. Vector3.Dot(ref normal, ref rayHit.Normal, out dot);
  133. //Only perform sweep if the object is in danger of hitting the object.
  134. //Triangles can be one sided, so check the impact normal against the triangle normal.
  135. if (instancedMesh.sidedness == TriangleSidedness.Counterclockwise && dot < 0 ||
  136. instancedMesh.sidedness == TriangleSidedness.Clockwise && dot > 0)
  137. {
  138. timeOfImpact = rayHit.T;
  139. }
  140. }
  141. else
  142. {
  143. timeOfImpact = rayHit.T;
  144. }
  145. }
  146. }
  147. PhysicsResources.GiveBack(triangle);
  148. }
  149. }
  150. }
  151. protected internal override void GetContactInformation(int index, out ContactInformation info)
  152. {
  153. info.Contact = MeshManifold.contacts.Elements[index];
  154. //Find the contact's normal and friction forces.
  155. info.FrictionImpulse = 0;
  156. info.NormalImpulse = 0;
  157. for (int i = 0; i < contactConstraint.frictionConstraints.Count; i++)
  158. {
  159. if (contactConstraint.frictionConstraints.Elements[i].PenetrationConstraint.contact == info.Contact)
  160. {
  161. info.FrictionImpulse = contactConstraint.frictionConstraints.Elements[i].accumulatedImpulse;
  162. info.NormalImpulse = contactConstraint.frictionConstraints.Elements[i].PenetrationConstraint.accumulatedImpulse;
  163. break;
  164. }
  165. }
  166. //Compute relative velocity
  167. if (convex.entity != null)
  168. {
  169. Vector3 velocity;
  170. Vector3.Subtract(ref info.Contact.Position, ref convex.entity.position, out velocity);
  171. Vector3.Cross(ref convex.entity.angularVelocity, ref velocity, out velocity);
  172. Vector3.Add(ref velocity, ref convex.entity.linearVelocity, out info.RelativeVelocity);
  173. }
  174. else
  175. info.RelativeVelocity = new Vector3();
  176. info.Pair = this;
  177. }
  178. }
  179. }