PageRenderTime 47ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/PhysicsEngines/Bullet/BulletPhysics.cs

#
C# | 388 lines | 245 code | 48 blank | 95 comment | 19 complexity | 04db6314d56431ee323b71ec6e728e4a MD5 | raw file
Possible License(s): Apache-2.0
  1. using BulletXNA;
  2. using BulletXNA.BulletCollision;
  3. using BulletXNA.BulletDynamics;
  4. using Delta.PhysicsEngines.Enums;
  5. using Delta.Utilities;
  6. using Delta.Utilities.Datatypes;
  7. using BulletVector3 = Microsoft.Xna.Framework.Vector3;
  8. using BulletMatrix = Microsoft.Xna.Framework.Matrix;
  9. namespace Delta.PhysicsEngines.Bullet
  10. {
  11. /// <summary>
  12. /// Bullet physics engine implementation into DeltaEngine.
  13. /// <remarks>
  14. /// Reference <see cref="http://code.google.com/p/bullet-xna/"/> for more info.
  15. /// </remarks>
  16. /// </summary>
  17. public class BulletPhysics : Physics
  18. {
  19. #region Constants
  20. private const int MaxProxies = 100000;
  21. private const float PlaneHeight = 1.0f;
  22. #endregion
  23. #region Internal
  24. #region bulletWorld (Internal)
  25. internal DynamicsWorld bulletWorld;
  26. #endregion
  27. #region bulletCollisionConf (Internal)
  28. internal ICollisionConfiguration bulletCollisionConf;
  29. #endregion
  30. #region bulletDispatcher (Internal)
  31. internal CollisionDispatcher bulletDispatcher;
  32. #endregion
  33. #region bulletBroadphase (Internal)
  34. internal IBroadphaseInterface bulletBroadphase;
  35. #endregion
  36. #region bulletSolver (Internal)
  37. internal IConstraintSolver bulletSolver;
  38. #endregion
  39. #endregion
  40. #region Constructors
  41. /// <summary>
  42. /// Initializes a new instance of the <see cref="BulletPhysics"/> class.
  43. /// </summary>
  44. public BulletPhysics()
  45. : base(false, "Bullet")
  46. {
  47. // Collision configuration contains default setup for memory.
  48. bulletCollisionConf = new DefaultCollisionConfiguration();
  49. bulletDispatcher = new CollisionDispatcher(bulletCollisionConf);
  50. // Now create broad phase.
  51. IOverlappingPairCache pairCache = null;
  52. bulletBroadphase = new SimpleBroadphase(MaxProxies, pairCache);
  53. // Now create solver
  54. bulletSolver = new SequentialImpulseConstraintSolver();
  55. // Add possibility for different world in future.
  56. bulletWorld = new DiscreteDynamicsWorld(bulletDispatcher,
  57. bulletBroadphase,
  58. bulletSolver,
  59. bulletCollisionConf);
  60. var bulletVector = BulletDatatypesMapping.Convert(DefaultGravity);
  61. bulletWorld.SetGravity(ref bulletVector);
  62. CreateGroundBody();
  63. }
  64. #endregion
  65. #region IsShapeSupported (Public)
  66. /// <summary>
  67. /// Implementation for getting which shapes are supported by Bullet.
  68. /// </summary>
  69. /// <param name="shapeType">The type of shape to check if supported.</param>
  70. /// <returns>True if supported, false otherwise.</returns>
  71. public override bool IsShapeSupported(ShapeType shapeType)
  72. {
  73. switch (shapeType)
  74. {
  75. case ShapeType.Box:
  76. case ShapeType.Sphere:
  77. case ShapeType.Capsule:
  78. case ShapeType.Triangle:
  79. //case Enums.ShapeType.Terrain:
  80. // Bullet supports this too.
  81. case ShapeType.Cone:
  82. case ShapeType.Cylinder:
  83. return true;
  84. }
  85. return false;
  86. }
  87. #endregion
  88. #region IsJointSupported (Public)
  89. /// <summary>
  90. /// Implementation for getting which shapes are supported by Bullet.
  91. /// </summary>
  92. /// <param name="jointType">The type of joint to check if supported.</param>
  93. /// <returns>True if supported, false otherwise.</returns>
  94. public override bool IsJointSupported(JointType jointType)
  95. {
  96. switch (jointType)
  97. {
  98. //case Enums.JointType.FixedAngle:
  99. //case Enums.JointType.SingleBodyPointOnLine:
  100. //case Enums.JointType.PointOnLine:
  101. case JointType.PointOnPoint:
  102. //case Enums.JointType.PointPointDistance:
  103. case JointType.Hinge:
  104. //case Enums.JointType.Prismatic:
  105. return true;
  106. }
  107. return false;
  108. }
  109. #endregion
  110. #region IsFeatureSupported (Public)
  111. /// <summary>
  112. /// Implementation for getting which features are supported by Bullet.
  113. /// </summary>
  114. /// <param name="support">The type of feature to check if supported.</param>
  115. /// <returns>True if supported, false otherwise.</returns>
  116. public override bool IsFeatureSupported(FeatureSupport support)
  117. {
  118. switch (support)
  119. {
  120. case FeatureSupport.Joint:
  121. return true;
  122. }
  123. return false;
  124. }
  125. #endregion
  126. #region SetGroundPlane (Public)
  127. /// <summary>
  128. /// Implementation of SetGroundPlane
  129. /// </summary>
  130. /// <param name="enable">True to enable the ground plane, false otherwise.</param>
  131. /// <param name="height">The height of the plane.</param>
  132. public override void SetGroundPlane(bool enable, float height)
  133. {
  134. RigidBody groundRigidBody = ((BulletBody)groundBody).bulletBody;
  135. BulletVector3 translate = new BulletVector3(height - (PlaneHeight * 0.5f));
  136. groundRigidBody.Translate(ref translate);
  137. // Check if we need to add it
  138. if (enable)
  139. {
  140. if (groundRigidBody.IsInWorld() == false)
  141. {
  142. bulletWorld.AddRigidBody(groundRigidBody);
  143. }
  144. }
  145. else
  146. {
  147. if (groundRigidBody.IsInWorld())
  148. {
  149. bulletWorld.RemoveRigidBody(groundRigidBody);
  150. }
  151. }
  152. }
  153. #endregion
  154. #region Methods (Private)
  155. #region CreateBody
  156. /// <summary>
  157. /// Creates a BulletBody from base implementation.
  158. /// </summary>
  159. /// <param name="is2DBody">True if the body is 2D, false means that is 3D.</param>
  160. /// <param name="shape">The shape to attach to the new create body.</param>
  161. /// <param name="initialPosition">Initial position of the body.</param>
  162. /// <returns>New PhysicsBody instance or null if not supported.</returns>
  163. protected override PhysicsBody CreateBody(bool is2DBody,
  164. PhysicsShape shape, Vector initialPosition)
  165. {
  166. if (is2DBody)
  167. {
  168. Log.Warning("Bullet does not support 2D bodies.");
  169. return null;
  170. }
  171. PhysicsBody body = new BulletBody(this, shape, initialPosition);
  172. bodies.Add(body);
  173. return body;
  174. }
  175. #endregion
  176. #region CreateJoint
  177. /// <summary>
  178. /// Creates a BulletJoint from base implementation.
  179. /// </summary>
  180. /// <param name="jointType">The type of joint to create.</param>
  181. /// <param name="bodyA">The first required body.</param>
  182. /// <param name="bodyB">The second [optional] body.</param>
  183. /// <param name="args">Array of args to pass to Joint implementation.</param>
  184. /// <returns></returns>
  185. public override PhysicsJoint CreateJoint(
  186. JointType jointType,
  187. PhysicsBody bodyA, PhysicsBody bodyB, object[] args)
  188. {
  189. if (IsJointSupported(jointType) == false)
  190. {
  191. Log.Warning("Current module does not support " +
  192. "the type of joint " + jointType);
  193. return null;
  194. }
  195. PhysicsJoint joint =
  196. new BulletJoint(this, jointType, bodyA, bodyB, args);
  197. if (joint != null)
  198. {
  199. joints.Add(joint);
  200. }
  201. return joint;
  202. }
  203. #endregion
  204. #region CreateGroundBody
  205. /// <summary>
  206. /// Create the body that will be used as ground.
  207. /// </summary>
  208. private void CreateGroundBody()
  209. {
  210. BulletVector3 vectorSize =
  211. new BulletVector3(20000.0f, 20000.0f, PlaneHeight / 2.0f);
  212. CollisionShape groundShape = new BoxShape(ref vectorSize);
  213. DefaultMotionState groundMotionState =
  214. new DefaultMotionState(BulletMatrix.Identity, BulletMatrix.Identity);
  215. RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(
  216. 0.0f, groundMotionState, groundShape, BulletVector3.Zero);
  217. rbInfo.m_restitution = 1.0f;
  218. rbInfo.m_mass = 0.0f;
  219. rbInfo.m_friction = 0.5f;
  220. rbInfo.m_angularDamping = 0.3f;
  221. rbInfo.m_linearDamping = 0.3f;
  222. RigidBody groundRigidBody = new RigidBody(rbInfo);
  223. groundBody = new BulletBody(this, groundRigidBody, groundShape);
  224. groundBody.Name = "PlaneBody";
  225. }
  226. #endregion
  227. #region RemoveBodyImpl
  228. /// <summary>
  229. /// Implementation of RemoveBody.
  230. /// </summary>
  231. /// <param name="body">The body to remove.</param>
  232. protected override void RemoveBodyImpl(PhysicsBody body)
  233. {
  234. // Remove from bullet world
  235. bulletWorld.RemoveRigidBody((body as BulletBody).bulletBody);
  236. }
  237. #endregion
  238. #region RemoveJointImpl
  239. /// <summary>
  240. /// Implementation of RemoveJoint.
  241. /// </summary>
  242. /// <param name="body">The joint to remove.</param>
  243. protected override void RemoveJointImpl(PhysicsJoint joint)
  244. {
  245. BulletJoint bulletJoint = joint as BulletJoint;
  246. bulletWorld.RemoveConstraint(bulletJoint.Constraint);
  247. }
  248. #endregion
  249. #region RayCastImpl
  250. /// <summary>
  251. /// Performs ray cast in Bullet world.
  252. /// </summary>
  253. /// <param name="ray"></param>
  254. /// <param name="checkGround"></param>
  255. /// <param name="foundBody"></param>
  256. /// <param name="surfaceNormal"></param>
  257. /// <param name="fraction"></param>
  258. /// <param name="userData"></param>
  259. /// <returns></returns>
  260. protected override bool RayCastImpl(Ray ray, bool checkGround,
  261. out PhysicsBody foundBody, out Vector surfaceNormal, out float fraction,
  262. out object userData)
  263. {
  264. foundBody = null;
  265. surfaceNormal = Vector.Zero;
  266. fraction = 0.0f;
  267. userData = null;
  268. var rayPos = BulletDatatypesMapping.Convert(ray.Position);
  269. var rayDir = BulletDatatypesMapping.Convert(ray.Direction);
  270. ClosestRayResultCallback resultCallback
  271. = new ClosestRayResultCallback(ref rayPos, ref rayDir);
  272. bulletWorld.RayTest(ref rayPos, ref rayDir, resultCallback);
  273. if (resultCallback.HasHit() == false)
  274. {
  275. return false;
  276. }
  277. RigidBody rigBody = RigidBody.Upcast(resultCallback.m_collisionObject);
  278. BulletBody body = rigBody.GetUserPointer() as BulletBody;
  279. if (body != null)
  280. {
  281. foundBody = body;
  282. surfaceNormal = BulletDatatypesMapping.Convert(
  283. resultCallback.m_hitNormalWorld);
  284. fraction = resultCallback.m_closestHitFraction;
  285. return true;
  286. }
  287. return false;
  288. }
  289. #endregion
  290. #region UpdateSimulation
  291. /// <summary>
  292. /// Update simulation implementation of Physics.
  293. /// </summary>
  294. protected override void UpdateSimulation(float timeStep)
  295. {
  296. // http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_the_World
  297. if (IsPaused == false)
  298. {
  299. bulletWorld.StepSimulation(timeStep, 10);
  300. }
  301. }
  302. #endregion
  303. #region SetGravity
  304. /// <summary>
  305. /// Sets gravity implementation.
  306. /// </summary>
  307. /// <param name="gravity">The 3D gravity vector.</param>
  308. protected override void SetGravity(Vector gravity)
  309. {
  310. var bulletVector = BulletDatatypesMapping.Convert(gravity);
  311. bulletWorld.SetGravity(ref bulletVector);
  312. }
  313. #endregion
  314. #region SetMultithreading
  315. /// <summary>
  316. /// Sets multithreading on Bullet implementation.
  317. /// </summary>
  318. /// <param name="enable">True to enable, false otherwise.</param>
  319. protected override void SetMultithreading(bool enable)
  320. {
  321. // Not supported
  322. if (enable)
  323. {
  324. Log.Warning("BulleXNA does not support multi-threading yet!");
  325. }
  326. }
  327. #endregion
  328. #region GetTotalPhysicsTime
  329. /// <summary>
  330. /// Gets total time step of physics simulation.
  331. /// </summary>
  332. /// <returns></returns>
  333. protected override double GetTotalPhysicsTime()
  334. {
  335. return bulletWorld.GetDispatchInfo().GetTimeStep();
  336. }
  337. #endregion
  338. #endregion
  339. }
  340. }