Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
PhysicsEngine.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 
7 using SiliconStudio.Core.Mathematics;
8 using SiliconStudio.Paradox.Engine.Data;
9 using SiliconStudio.Paradox.Graphics;
10 
11 namespace SiliconStudio.Paradox.Physics
12 {
13  public class PhysicsEngine : IDisposable
14  {
15  BulletSharp.DiscreteDynamicsWorld discreteDynamicsWorld;
16  //BulletSharp.SoftBody.SoftRigidDynamicsWorld mSoftRigidDynamicsWorld;
17  BulletSharp.CollisionWorld collisionWorld;
18 
19  BulletSharp.CollisionDispatcher dispatcher;
20  BulletSharp.CollisionConfiguration collisionConfiguration;
21  BulletSharp.DbvtBroadphase broadphase;
22 
23  BulletSharp.ContactSolverInfo solverInfo;
24  BulletSharp.DispatcherInfo dispatchInfo;
25 
26  bool mCanCcd;
27 
28  public bool ContinuousCollisionDetection
29  {
30  get
31  {
32  if (!mCanCcd)
33  {
34  throw new Exception("ContinuousCollisionDetection must be enabled at physics engine initialization using the proper flag.");
35  }
36 
37  return dispatchInfo.UseContinuous;
38  }
39  set
40  {
41  if (!mCanCcd)
42  {
43  throw new Exception("ContinuousCollisionDetection must be enabled at physics engine initialization using the proper flag.");
44  }
45 
46  dispatchInfo.UseContinuous = value;
47  }
48  }
49 
50  /// <summary>
51  /// The debug effect, populate this field in the case of debug rendering
52  /// </summary>
53  public PhysicsDebugEffect DebugEffect = null;
54 
55  /// <summary>
56  /// Set to true if you want the engine to create the debug primitives
57  /// </summary>
58  public bool CreateDebugPrimitives = false;
59 
60  /// <summary>
61  /// Set to true if you want the engine to render the debug primitives
62  /// </summary>
63  public bool RenderDebugPrimitives = false;
64 
65  /// <summary>
66  /// Totally disable the simulation if set to true
67  /// </summary>
68  public bool DisableSimulation = false;
69 
70  internal GraphicsDevice DebugGraphicsDevice;
71 
72  internal static PhysicsEngine Singleton = null;
73 
74  readonly Game game;
75 
76  public PhysicsEngine(Game g)
77  {
78  game = g;
79  }
80 
81  static bool convertersDone;
82 
83  public static void InitializeConverters()
84  {
85  //init converters
86  // Register type PhysicsColliderShapeData
87  Core.Serialization.Converters.ConverterContext.RegisterConverter(new PhysicsColliderShapeDataConverter());
88  // Register type PhysicsComponentData
89  Core.Serialization.Converters.ConverterContext.RegisterConverter(new PhysicsComponentDataConverter());
90  // Register type PhysicsElementData
91  Core.Serialization.Converters.ConverterContext.RegisterConverter(new PhysicsElementDataConverter());
92 
93  convertersDone = true;
94  }
95 
96  /// <summary>
97  /// Initializes the Physics engine using the specified flags.
98  /// </summary>
99  /// <param name="flags">The flags.</param>
100  /// <exception cref="System.NotImplementedException">SoftBody processing is not yet available</exception>
102  {
103  // Preload proper libbulletc native library (depending on CPU type)
104  Core.NativeLibrary.PreloadLibrary("libbulletc.dll");
105 
106  if (!convertersDone)
107  {
108  InitializeConverters();
109  }
110 
111  //add into processors pipeline
112  game.Entities.Processors.Add(new PhysicsProcessor());
113 
114  collisionConfiguration = new BulletSharp.DefaultCollisionConfiguration();
115  dispatcher = new BulletSharp.CollisionDispatcher(collisionConfiguration);
116  broadphase = new BulletSharp.DbvtBroadphase();
117 
118  //this allows characters to have proper physics behavior
119  broadphase.OverlappingPairCache.SetInternalGhostPairCallback(new BulletSharp.GhostPairCallback());
120 
121  //2D pipeline
122  var simplex = new BulletSharp.VoronoiSimplexSolver();
123  var pdSolver = new BulletSharp.MinkowskiPenetrationDepthSolver();
124  var convexAlgo = new BulletSharp.Convex2DConvex2DAlgorithm.CreateFunc(simplex, pdSolver);
125 
126  dispatcher.RegisterCollisionCreateFunc(BulletSharp.BroadphaseNativeType.Convex2DShape, BulletSharp.BroadphaseNativeType.Convex2DShape, convexAlgo); //this is the ONLY one that we are actually using
127  dispatcher.RegisterCollisionCreateFunc(BulletSharp.BroadphaseNativeType.Box2DShape, BulletSharp.BroadphaseNativeType.Convex2DShape, convexAlgo);
128  dispatcher.RegisterCollisionCreateFunc(BulletSharp.BroadphaseNativeType.Convex2DShape, BulletSharp.BroadphaseNativeType.Box2DShape, convexAlgo);
129  dispatcher.RegisterCollisionCreateFunc(BulletSharp.BroadphaseNativeType.Box2DShape, BulletSharp.BroadphaseNativeType.Box2DShape, new BulletSharp.Box2DBox2DCollisionAlgorithm.CreateFunc());
130  //~2D pipeline
131 
132  //default solver
133  var solver = new BulletSharp.SequentialImpulseConstraintSolver();
134 
135  if (flags.HasFlag(PhysicsEngineFlags.CollisionsOnly))
136  {
137  collisionWorld = new BulletSharp.CollisionWorld(dispatcher, broadphase, collisionConfiguration);
138  }
139  else if (flags.HasFlag(PhysicsEngineFlags.SoftBodySupport))
140  {
141  //mSoftRigidDynamicsWorld = new BulletSharp.SoftBody.SoftRigidDynamicsWorld(mDispatcher, mBroadphase, solver, mCollisionConf);
142  //mDiscreteDynamicsWorld = mSoftRigidDynamicsWorld;
143  //mCollisionWorld = mSoftRigidDynamicsWorld;
144  throw new NotImplementedException("SoftBody processing is not yet available");
145  }
146  else
147  {
148  discreteDynamicsWorld = new BulletSharp.DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
149  collisionWorld = discreteDynamicsWorld;
150  }
151 
152  if (discreteDynamicsWorld != null)
153  {
154  solverInfo = discreteDynamicsWorld.SolverInfo; //we are required to keep this reference, or the GC will mess up
155  dispatchInfo = discreteDynamicsWorld.DispatchInfo;
156 
157  solverInfo.SolverMode |= BulletSharp.SolverModes.CacheFriendly; //todo test if helps with performance or not
158 
159  if (flags.HasFlag(PhysicsEngineFlags.ContinuosCollisionDetection))
160  {
161  mCanCcd = true;
162  solverInfo.SolverMode |= BulletSharp.SolverModes.Use2FrictionDirections | BulletSharp.SolverModes.RandomizeOrder;
163  dispatchInfo.UseContinuous = true;
164  }
165  }
166 
167  BulletSharp.PersistentManifold.ContactProcessed += PersistentManifoldContactProcessed;
168  BulletSharp.PersistentManifold.ContactDestroyed += PersistentManifoldContactDestroyed;
169 
170  Initialized = true;
171 
172  Singleton = this;
173  }
174 
175  static void PersistentManifoldContactDestroyed(object userPersistantData)
176  {
177  var contact = (Contact)userPersistantData;
178  var args = new CollisionArgs { Contact = contact };
179 
180  var colA = contact.ColliderA;
181  var colB = contact.ColliderB;
182 
183  colA.Contacts.Remove(contact);
184  colB.Contacts.Remove(contact);
185 
186  var colAEnded = false;
187  var previousColAState = colA.Contacts.Where(x => (x.ColliderA == colA && x.ColliderB == colB) || (x.ColliderA == colB && x.ColliderB == colA));
188  if (!previousColAState.Any()) colAEnded = true;
189 
190  var colBEnded = false;
191  var previousColBState = colB.Contacts.Where(x => (x.ColliderB == colB && x.ColliderA == colA) || (x.ColliderB == colA && x.ColliderA == colB));
192  if (!previousColBState.Any()) colBEnded = true;
193 
194  if(colAEnded) colA.PropagateOnLastContactEnd(args);
195  colA.PropagateOnContactEnd(args);
196 
197  if(colBEnded) colB.PropagateOnLastContactEnd(args);
198  colB.PropagateOnContactEnd(args);
199  }
200 
201  static void PersistentManifoldContactProcessed(BulletSharp.ManifoldPoint cp, BulletSharp.CollisionObject body0, BulletSharp.CollisionObject body1)
202  {
203  var colA = (Collider)body0.UserObject;
204  var colB = (Collider)body1.UserObject;
205 
206  if (!colA.NeedsCollisionCheck && !colB.NeedsCollisionCheck) return; //don't process at all if both the objects don't need any collision event
207 
208  if (cp.UserPersistentData == null) //New contact!
209  {
210  var contact = new Contact
211  {
212  ColliderA = colA,
213  ColliderB = colB,
214  Distance = cp.Distance,
215  PositionOnA = new Vector3(cp.PositionWorldOnA.X, cp.PositionWorldOnA.Y, cp.PositionWorldOnA.Z),
216  PositionOnB = new Vector3(cp.PositionWorldOnB.X, cp.PositionWorldOnB.Y, cp.PositionWorldOnB.Z),
217  Normal = new Vector3(cp.NormalWorldOnB.X, cp.NormalWorldOnB.Y, cp.NormalWorldOnB.Z)
218  };
219 
220  //must figure if we are a really brand new collision for correct event propagation
221  var colABegan = false;
222  var previousColAState = colA.Contacts.Where(x => (x.ColliderA == colA && x.ColliderB == colB) || (x.ColliderA == colB && x.ColliderB == colA));
223  if (!previousColAState.Any()) colABegan = true;
224 
225  var colBBegan = false;
226  var previousColBState = colB.Contacts.Where(x => (x.ColliderB == colB && x.ColliderA == colA) || (x.ColliderB == colA && x.ColliderA == colB));
227  if (!previousColBState.Any()) colBBegan = true;
228 
229  colA.Contacts.Add(contact);
230  colB.Contacts.Add(contact);
231 
232  var args = new CollisionArgs { Contact = contact };
233 
234  cp.UserPersistentData = contact;
235 
236  if(colABegan) colA.PropagateOnFirstContactBegin(args);
237  colA.PropagateOnContactBegin(args);
238 
239  if(colBBegan) colB.PropagateOnFirstContactBegin(args);
240  colB.PropagateOnContactBegin(args);
241  }
242  else
243  {
244  var contact = (Contact)cp.UserPersistentData;
245 
246  contact.Distance = cp.Distance;
247  contact.PositionOnA = new Vector3(cp.PositionWorldOnA.X, cp.PositionWorldOnA.Y, cp.PositionWorldOnA.Z);
248  contact.PositionOnB = new Vector3(cp.PositionWorldOnB.X, cp.PositionWorldOnB.Y, cp.PositionWorldOnB.Z);
249  contact.Normal = new Vector3(cp.NormalWorldOnB.X, cp.NormalWorldOnB.Y, cp.NormalWorldOnB.Z);
250 
251  var args = new CollisionArgs { Contact = contact };
252 
253  colA.PropagateOnContactChange(args);
254  colB.PropagateOnContactChange(args);
255  }
256  }
257 
258  /// <summary>
259  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
260  /// </summary>
261  public void Dispose()
262  {
263  //if (mSoftRigidDynamicsWorld != null) mSoftRigidDynamicsWorld.Dispose();
264  if (discreteDynamicsWorld != null) discreteDynamicsWorld.Dispose();
265  else if (collisionWorld != null) collisionWorld.Dispose();
266 
267  if (broadphase != null) broadphase.Dispose();
268  if (dispatcher != null) dispatcher.Dispose();
269  if (collisionConfiguration != null) collisionConfiguration.Dispose();
270  }
271 
272  /// <summary>
273  /// Creates the collider.
274  /// </summary>
275  /// <param name="shape">The shape.</param>
276  /// <returns></returns>
278  {
279  var collider = new Collider(shape)
280  {
281  InternalCollider = new BulletSharp.CollisionObject
282  {
283  CollisionShape = shape.InternalShape,
284  ContactProcessingThreshold = 1e18f
285  }
286  };
287 
288  collider.InternalCollider.CollisionFlags |= BulletSharp.CollisionFlags.NoContactResponse;
289 
290  if (shape.NeedsCustomCollisionCallback)
291  {
292  collider.InternalCollider.CollisionFlags |= BulletSharp.CollisionFlags.CustomMaterialCallback;
293  }
294 
295  collider.InternalCollider.UserObject = collider;
296  collider.Engine = this;
297 
298  return collider;
299  }
300 
301  /// <summary>
302  /// Creates the rigid body.
303  /// </summary>
304  /// <param name="collider">The collider.</param>
305  /// <returns></returns>
307  {
308  var rb = new RigidBody(collider);
309 
310  rb.InternalRigidBody = new BulletSharp.RigidBody(0.0f, rb.MotionState, collider.InternalShape, Vector3.Zero);
311  rb.InternalRigidBody.CollisionFlags |= BulletSharp.CollisionFlags.StaticObject; //already set if mass is 0 actually!
312 
313  rb.InternalCollider = rb.InternalRigidBody;
314 
315  rb.InternalCollider.ContactProcessingThreshold = 1e18f;
316 
317  if (collider.NeedsCustomCollisionCallback)
318  {
319  rb.InternalCollider.CollisionFlags |= BulletSharp.CollisionFlags.CustomMaterialCallback;
320  }
321 
322  if (collider.Is2D) //set different defaults for 2D shapes
323  {
324  rb.InternalRigidBody.LinearFactor = new Vector3(1.0f, 1.0f, 0.0f);
325  rb.InternalRigidBody.AngularFactor = new Vector3(0.0f, 0.0f, 1.0f);
326  }
327 
328  rb.InternalRigidBody.UserObject = rb;
329  rb.Engine = this;
330 
331  return rb;
332  }
333 
334  /// <summary>
335  /// Creates the character.
336  /// </summary>
337  /// <param name="collider">The collider.</param>
338  /// <param name="stepHeight">Height of the step.</param>
339  /// <returns></returns>
340  public Character CreateCharacter(ColliderShape collider, float stepHeight)
341  {
342  var ch = new Character(collider)
343  {
344  InternalCollider = new BulletSharp.PairCachingGhostObject
345  {
346  CollisionShape = collider.InternalShape
347  }
348  };
349 
350  ch.InternalCollider.CollisionFlags |= BulletSharp.CollisionFlags.CharacterObject;
351 
352  if (collider.NeedsCustomCollisionCallback)
353  {
354  ch.InternalCollider.CollisionFlags |= BulletSharp.CollisionFlags.CustomMaterialCallback;
355  }
356 
357  ch.InternalCollider.ContactProcessingThreshold = 1e18f;
358 
359  ch.KinematicCharacter = new BulletSharp.KinematicCharacterController((BulletSharp.PairCachingGhostObject)ch.InternalCollider, (BulletSharp.ConvexShape)collider.InternalShape, stepHeight);
360 
361  ch.InternalCollider.UserObject = ch;
362  ch.Engine = this;
363 
364  return ch;
365  }
366 
367  /// <summary>
368  /// Adds the collider to the engine processing pipeline.
369  /// </summary>
370  /// <param name="collider">The collider.</param>
371  public void AddCollider(Collider collider)
372  {
373  collisionWorld.AddCollisionObject(collider.InternalCollider);
374  }
375 
376  /// <summary>
377  /// Adds the collider to the engine processing pipeline.
378  /// </summary>
379  /// <param name="collider">The collider.</param>
380  /// <param name="group">The group.</param>
381  /// <param name="mask">The mask.</param>
383  {
384  collisionWorld.AddCollisionObject(collider.InternalCollider, (BulletSharp.CollisionFilterGroups)group, (BulletSharp.CollisionFilterGroups)mask);
385  }
386 
387  /// <summary>
388  /// Removes the collider from the engine processing pipeline.
389  /// </summary>
390  /// <param name="collider">The collider.</param>
391  public void RemoveCollider(Collider collider)
392  {
393  collisionWorld.RemoveCollisionObject(collider.InternalCollider);
394  }
395 
396  /// <summary>
397  /// Adds the rigid body to the engine processing pipeline.
398  /// </summary>
399  /// <param name="rigidBody">The rigid body.</param>
400  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
401  public void AddRigidBody(RigidBody rigidBody)
402  {
403  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
404 
405  discreteDynamicsWorld.AddRigidBody(rigidBody.InternalRigidBody);
406  }
407 
408  /// <summary>
409  /// Adds the rigid body to the engine processing pipeline.
410  /// </summary>
411  /// <param name="rigidBody">The rigid body.</param>
412  /// <param name="group">The group.</param>
413  /// <param name="mask">The mask.</param>
414  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
416  {
417  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
418 
419  discreteDynamicsWorld.AddRigidBody(rigidBody.InternalRigidBody, (short)group, (short)mask);
420  }
421 
422  /// <summary>
423  /// Removes the rigid body from the engine processing pipeline.
424  /// </summary>
425  /// <param name="rigidBody">The rigid body.</param>
426  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
427  public void RemoveRigidBody(RigidBody rigidBody)
428  {
429  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
430 
431  discreteDynamicsWorld.RemoveRigidBody(rigidBody.InternalRigidBody);
432  }
433 
434  /// <summary>
435  /// Adds the character to the engine processing pipeline.
436  /// </summary>
437  /// <param name="character">The character.</param>
438  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
439  public void AddCharacter(Character character)
440  {
441  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
442 
443  var collider = character.InternalCollider;
444  var action = character.KinematicCharacter;
445  discreteDynamicsWorld.AddCollisionObject(collider, BulletSharp.CollisionFilterGroups.CharacterFilter);
446  discreteDynamicsWorld.AddCharacter(action);
447  }
448 
449  /// <summary>
450  /// Adds the character to the engine processing pipeline.
451  /// </summary>
452  /// <param name="character">The character.</param>
453  /// <param name="group">The group.</param>
454  /// <param name="mask">The mask.</param>
455  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
457  {
458  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
459 
460  var collider = character.InternalCollider;
461  var action = character.KinematicCharacter;
462  discreteDynamicsWorld.AddCollisionObject(collider, (BulletSharp.CollisionFilterGroups)group, (BulletSharp.CollisionFilterGroups)mask);
463  discreteDynamicsWorld.AddCharacter(action);
464  }
465 
466  /// <summary>
467  /// Removes the character from the engine processing pipeline.
468  /// </summary>
469  /// <param name="character">The character.</param>
470  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
471  public void RemoveCharacter(Character character)
472  {
473  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
474 
475  var collider = character.InternalCollider;
476  var action = character.KinematicCharacter;
477  discreteDynamicsWorld.RemoveCollisionObject(collider);
478  discreteDynamicsWorld.RemoveCharacter(action);
479  }
480 
481  /// <summary>
482  /// Creates the constraint.
483  /// </summary>
484  /// <param name="type">The type.</param>
485  /// <param name="rigidBodyA">The rigid body a.</param>
486  /// <param name="frameA">The frame a.</param>
487  /// <param name="useReferenceFrameA">if set to <c>true</c> [use reference frame a].</param>
488  /// <returns></returns>
489  /// <exception cref="System.Exception">
490  /// Cannot perform this action when the physics engine is set to CollisionsOnly
491  /// or
492  /// Both RigidBodies must be valid
493  /// or
494  /// A Gear constraint always needs two rigidbodies to be created.
495  /// </exception>
496  public Constraint CreateConstraint(ConstraintTypes type, RigidBody rigidBodyA, Matrix frameA, bool useReferenceFrameA = false)
497  {
498  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
499  if (rigidBodyA == null) throw new Exception("Both RigidBodies must be valid");
500 
501  var rbA = rigidBodyA.InternalRigidBody;
502 
503  switch (type)
504  {
505  case ConstraintTypes.Point2Point:
506  {
507  var constraint = new Point2PointConstraint
508  {
509  InternalPoint2PointConstraint = new BulletSharp.Point2PointConstraint(rbA, frameA.TranslationVector),
510 
511  RigidBodyA = rigidBodyA,
512  };
513 
514  constraint.InternalConstraint = constraint.InternalPoint2PointConstraint;
515 
516  rigidBodyA.LinkedConstraints.Add(constraint);
517 
518  constraint.Engine = this;
519 
520  return constraint;
521  }
522  case ConstraintTypes.Hinge:
523  {
524  var constraint = new HingeConstraint
525  {
526  InternalHingeConstraint = new BulletSharp.HingeConstraint(rbA, frameA, useReferenceFrameA),
527 
528  RigidBodyA = rigidBodyA,
529  };
530 
531  constraint.InternalConstraint = constraint.InternalHingeConstraint;
532 
533  rigidBodyA.LinkedConstraints.Add(constraint);
534 
535  constraint.Engine = this;
536 
537  return constraint;
538  }
539  case ConstraintTypes.Slider:
540  {
541  var constraint = new SliderConstraint
542  {
543  InternalSliderConstraint = new BulletSharp.SliderConstraint(rbA, frameA, useReferenceFrameA),
544 
545  RigidBodyA = rigidBodyA,
546  };
547 
548  constraint.InternalConstraint = constraint.InternalSliderConstraint;
549 
550  rigidBodyA.LinkedConstraints.Add(constraint);
551 
552  constraint.Engine = this;
553 
554  return constraint;
555  }
556  case ConstraintTypes.ConeTwist:
557  {
558  var constraint = new ConeTwistConstraint
559  {
560  InternalConeTwistConstraint = new BulletSharp.ConeTwistConstraint(rbA, frameA),
561 
562  RigidBodyA = rigidBodyA
563  };
564 
565  constraint.InternalConstraint = constraint.InternalConeTwistConstraint;
566 
567  rigidBodyA.LinkedConstraints.Add(constraint);
568 
569  constraint.Engine = this;
570 
571  return constraint;
572  }
573  case ConstraintTypes.Generic6DoF:
574  {
575  var constraint = new Generic6DoFConstraint
576  {
577  InternalGeneric6DofConstraint = new BulletSharp.Generic6DofConstraint(rbA, frameA, useReferenceFrameA),
578 
579  RigidBodyA = rigidBodyA
580  };
581 
582  constraint.InternalConstraint = constraint.InternalGeneric6DofConstraint;
583 
584  rigidBodyA.LinkedConstraints.Add(constraint);
585 
586  constraint.Engine = this;
587 
588  return constraint;
589  }
590  case ConstraintTypes.Generic6DoFSpring:
591  {
592  var constraint = new Generic6DoFSpringConstraint
593  {
594  InternalGeneric6DofSpringConstraint = new BulletSharp.Generic6DofSpringConstraint(rbA, frameA, useReferenceFrameA),
595 
596  RigidBodyA = rigidBodyA
597  };
598 
599  constraint.InternalConstraint = constraint.InternalGeneric6DofConstraint = constraint.InternalGeneric6DofSpringConstraint;
600 
601  rigidBodyA.LinkedConstraints.Add(constraint);
602 
603  constraint.Engine = this;
604 
605  return constraint;
606  }
607  case ConstraintTypes.Gear:
608  {
609  throw new Exception("A Gear constraint always needs two rigidbodies to be created.");
610  }
611  }
612 
613  return null;
614  }
615 
616  /// <summary>
617  /// Creates the constraint.
618  /// </summary>
619  /// <param name="type">The type.</param>
620  /// <param name="rigidBodyA">The rigid body a.</param>
621  /// <param name="rigidBodyB">The rigid body b.</param>
622  /// <param name="frameA">The frame a.</param>
623  /// <param name="frameB">The frame b.</param>
624  /// <param name="useReferenceFrameA">if set to <c>true</c> [use reference frame a].</param>
625  /// <returns></returns>
626  /// <exception cref="System.Exception">
627  /// Cannot perform this action when the physics engine is set to CollisionsOnly
628  /// or
629  /// Both RigidBodies must be valid
630  /// </exception>
631  public Constraint CreateConstraint(ConstraintTypes type, RigidBody rigidBodyA, RigidBody rigidBodyB, Matrix frameA, Matrix frameB, bool useReferenceFrameA = false)
632  {
633  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
634  if (rigidBodyA == null || rigidBodyB == null) throw new Exception("Both RigidBodies must be valid");
635 
636  var rbA = rigidBodyA.InternalRigidBody;
637  var rbB = rigidBodyB.InternalRigidBody;
638 
639  switch (type)
640  {
641  case ConstraintTypes.Point2Point:
642  {
643  var constraint = new Point2PointConstraint
644  {
645  InternalPoint2PointConstraint = new BulletSharp.Point2PointConstraint(rbA, rbB, frameA.TranslationVector, frameB.TranslationVector),
646 
647  RigidBodyA = rigidBodyA,
648  RigidBodyB = rigidBodyB
649  };
650 
651  constraint.InternalConstraint = constraint.InternalPoint2PointConstraint;
652 
653  rigidBodyA.LinkedConstraints.Add(constraint);
654  rigidBodyB.LinkedConstraints.Add(constraint);
655 
656  constraint.Engine = this;
657 
658  return constraint;
659  }
660  case ConstraintTypes.Hinge:
661  {
662  var constraint = new HingeConstraint
663  {
664  InternalHingeConstraint = new BulletSharp.HingeConstraint(rbA, rbB, frameA, frameB, useReferenceFrameA),
665 
666  RigidBodyA = rigidBodyA,
667  RigidBodyB = rigidBodyB
668  };
669 
670  constraint.InternalConstraint = constraint.InternalHingeConstraint;
671 
672  rigidBodyA.LinkedConstraints.Add(constraint);
673  rigidBodyB.LinkedConstraints.Add(constraint);
674 
675  constraint.Engine = this;
676 
677  return constraint;
678  }
679  case ConstraintTypes.Slider:
680  {
681  var constraint = new SliderConstraint
682  {
683  InternalSliderConstraint = new BulletSharp.SliderConstraint(rbA, rbB, frameA, frameB, useReferenceFrameA),
684 
685  RigidBodyA = rigidBodyA,
686  RigidBodyB = rigidBodyB
687  };
688 
689  constraint.InternalConstraint = constraint.InternalSliderConstraint;
690 
691  rigidBodyA.LinkedConstraints.Add(constraint);
692  rigidBodyB.LinkedConstraints.Add(constraint);
693 
694  constraint.Engine = this;
695 
696  return constraint;
697  }
698  case ConstraintTypes.ConeTwist:
699  {
700  var constraint = new ConeTwistConstraint
701  {
702  InternalConeTwistConstraint = new BulletSharp.ConeTwistConstraint(rbA, rbB, frameA, frameB),
703 
704  RigidBodyA = rigidBodyA,
705  RigidBodyB = rigidBodyB
706  };
707 
708  constraint.InternalConstraint = constraint.InternalConeTwistConstraint;
709 
710  rigidBodyA.LinkedConstraints.Add(constraint);
711  rigidBodyB.LinkedConstraints.Add(constraint);
712 
713  constraint.Engine = this;
714 
715  return constraint;
716  }
717  case ConstraintTypes.Generic6DoF:
718  {
719  var constraint = new Generic6DoFConstraint
720  {
721  InternalGeneric6DofConstraint = new BulletSharp.Generic6DofConstraint(rbA, rbB, frameA, frameB, useReferenceFrameA),
722 
723  RigidBodyA = rigidBodyA,
724  RigidBodyB = rigidBodyB
725  };
726 
727  constraint.InternalConstraint = constraint.InternalGeneric6DofConstraint;
728 
729  rigidBodyA.LinkedConstraints.Add(constraint);
730  rigidBodyB.LinkedConstraints.Add(constraint);
731 
732  constraint.Engine = this;
733 
734  return constraint;
735  }
736  case ConstraintTypes.Generic6DoFSpring:
737  {
738  var constraint = new Generic6DoFSpringConstraint
739  {
740  InternalGeneric6DofSpringConstraint = new BulletSharp.Generic6DofSpringConstraint(rbA, rbB, frameA, frameB, useReferenceFrameA),
741 
742  RigidBodyA = rigidBodyA,
743  RigidBodyB = rigidBodyB
744  };
745 
746  constraint.InternalConstraint = constraint.InternalGeneric6DofConstraint = constraint.InternalGeneric6DofSpringConstraint;
747 
748  rigidBodyA.LinkedConstraints.Add(constraint);
749  rigidBodyB.LinkedConstraints.Add(constraint);
750 
751  constraint.Engine = this;
752 
753  return constraint;
754  }
755  case ConstraintTypes.Gear:
756  {
757  var constraint = new GearConstraint
758  {
759  InternalGearConstraint = new BulletSharp.GearConstraint(rbA, rbB, frameA.TranslationVector, frameB.TranslationVector),
760 
761  RigidBodyA = rigidBodyA,
762  RigidBodyB = rigidBodyB
763  };
764 
765  constraint.InternalConstraint = constraint.InternalGearConstraint;
766 
767  rigidBodyA.LinkedConstraints.Add(constraint);
768  rigidBodyB.LinkedConstraints.Add(constraint);
769 
770  constraint.Engine = this;
771 
772  return constraint;
773  }
774  }
775 
776  return null;
777  }
778 
779  /// <summary>
780  /// Adds the constraint to the engine processing pipeline.
781  /// </summary>
782  /// <param name="constraint">The constraint.</param>
783  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
784  public void AddConstraint(Constraint constraint)
785  {
786  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
787 
788  var c = constraint.InternalConstraint;
789 
790  discreteDynamicsWorld.AddConstraint(c);
791  }
792 
793  /// <summary>
794  /// Adds the constraint to the engine processing pipeline.
795  /// </summary>
796  /// <param name="constraint">The constraint.</param>
797  /// <param name="disableCollisionsBetweenLinkedBodies">if set to <c>true</c> [disable collisions between linked bodies].</param>
798  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
799  public void AddConstraint(Constraint constraint, bool disableCollisionsBetweenLinkedBodies)
800  {
801  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
802 
803  var c = constraint.InternalConstraint;
804 
805  discreteDynamicsWorld.AddConstraint(c, disableCollisionsBetweenLinkedBodies);
806  }
807 
808  /// <summary>
809  /// Removes the constraint from the engine processing pipeline.
810  /// </summary>
811  /// <param name="constraint">The constraint.</param>
812  /// <exception cref="System.Exception">Cannot perform this action when the physics engine is set to CollisionsOnly</exception>
813  public void RemoveConstraint(Constraint constraint)
814  {
815  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
816 
817  var c = constraint.InternalConstraint;
818 
819  discreteDynamicsWorld.RemoveConstraint(c);
820  }
821 
822  /// <summary>
823  /// Raycasts and stops at the first hit.
824  /// </summary>
825  /// <param name="from">From.</param>
826  /// <param name="to">To.</param>
827  /// <returns></returns>
828  public HitResult Raycast(Vector3 from, Vector3 to)
829  {
830  var result = new HitResult(); //result.Succeded is false by default
831 
832  using (var rcb = new BulletSharp.ClosestRayResultCallback(from, to))
833  {
834  collisionWorld.RayTest(ref from, ref to, rcb);
835 
836  if (rcb.CollisionObject == null) return result;
837  result.Succeeded = true;
838  result.Collider = (Collider)rcb.CollisionObject.UserObject;
839  result.Normal = rcb.HitNormalWorld;
840  result.Point = rcb.HitPointWorld;
841  }
842 
843  return result;
844  }
845 
846  /// <summary>
847  /// Raycasts penetrating any shape the ray encounters.
848  /// </summary>
849  /// <param name="from">From.</param>
850  /// <param name="to">To.</param>
851  /// <returns></returns>
852  public List<HitResult> RaycastPenetrating(Vector3 from, Vector3 to)
853  {
854  var result = new List<HitResult>();
855 
856  using (var rcb = new BulletSharp.AllHitsRayResultCallback(from, to))
857  {
858  collisionWorld.RayTest(ref from, ref to, rcb);
859 
860  var count = rcb.CollisionObjects.Count;
861 
862  for (var i = 0; i < count; i++)
863  {
864  var singleResult = new HitResult
865  {
866  Succeeded = true,
867  Collider = (Collider)rcb.CollisionObjects[i].UserObject,
868  Normal = rcb.HitNormalWorld[i],
869  Point = rcb.HitPointWorld[i]
870  };
871 
872  result.Add(singleResult);
873  }
874  }
875 
876  return result;
877  }
878 
879  /// <summary>
880  /// Pefrorms a sweep test using a collider shape and stops at the first hit
881  /// </summary>
882  /// <param name="shape">The shape.</param>
883  /// <param name="from">From.</param>
884  /// <param name="to">To.</param>
885  /// <returns></returns>
886  /// <exception cref="System.Exception">This kind of shape cannot be used for a ShapeSweep.</exception>
888  {
889  var sh = shape.InternalShape as BulletSharp.ConvexShape;
890  if(sh == null) throw new Exception("This kind of shape cannot be used for a ShapeSweep.");
891 
892  var result = new HitResult(); //result.Succeded is false by default
893 
894  using (var rcb = new BulletSharp.ClosestConvexResultCallback(from.TranslationVector, to.TranslationVector))
895  {
896  collisionWorld.ConvexSweepTest(sh, from, to, rcb);
897 
898  if (rcb.HitCollisionObject == null) return result;
899  result.Succeeded = true;
900  result.Collider = (Collider)rcb.HitCollisionObject.UserObject;
901  result.Normal = rcb.HitNormalWorld;
902  result.Point = rcb.HitPointWorld;
903  }
904 
905  return result;
906  }
907 
908  /// <summary>
909  /// Pefrorms a sweep test using a collider shape and never stops until "to"
910  /// </summary>
911  /// <param name="shape">The shape.</param>
912  /// <param name="from">From.</param>
913  /// <param name="to">To.</param>
914  /// <returns></returns>
915  /// <exception cref="System.Exception">This kind of shape cannot be used for a ShapeSweep.</exception>
916  public List<HitResult> ShapeSweepPenetrating(ColliderShape shape, Matrix from, Matrix to)
917  {
918  var sh = shape.InternalShape as BulletSharp.ConvexShape;
919  if (sh == null) throw new Exception("This kind of shape cannot be used for a ShapeSweep.");
920 
921  var result = new List<HitResult>();
922 
923  using (var rcb = new BulletSharp.AllHitsConvexResultCallback())
924  {
925  collisionWorld.ConvexSweepTest(sh, from, to, rcb);
926 
927  var count = rcb.CollisionObjects.Count;
928  for (var i = 0; i < count; i++)
929  {
930  var singleResult = new HitResult
931  {
932  Succeeded = true,
933  Collider = (Collider)rcb.CollisionObjects[i].UserObject,
934  Normal = rcb.HitNormalWorld[i],
935  Point = rcb.HitPointWorld[i]
936  };
937 
938  result.Add(singleResult);
939  }
940  }
941 
942  return result;
943  }
944 
945  /// <summary>
946  /// Gets a value indicating whether this <see cref="PhysicsEngine"/> is initialized.
947  /// </summary>
948  /// <value>
949  /// <c>true</c> if initialized; otherwise, <c>false</c>.
950  /// </value>
951  public bool Initialized { get; private set; }
952 
953  /// <summary>
954  /// Gets or sets the gravity.
955  /// </summary>
956  /// <value>
957  /// The gravity.
958  /// </value>
959  /// <exception cref="System.Exception">
960  /// Cannot perform this action when the physics engine is set to CollisionsOnly
961  /// or
962  /// Cannot perform this action when the physics engine is set to CollisionsOnly
963  /// </exception>
964  public Vector3 Gravity
965  {
966  get
967  {
968  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
969  return discreteDynamicsWorld.Gravity;
970  }
971  set
972  {
973  if (discreteDynamicsWorld == null) throw new Exception("Cannot perform this action when the physics engine is set to CollisionsOnly");
974  discreteDynamicsWorld.Gravity = value;
975  }
976  }
977 
978  internal void Update(float delta)
979  {
980  if (DisableSimulation) return;
981 
982  if (collisionWorld == null) return;
983 
984  if (discreteDynamicsWorld != null) discreteDynamicsWorld.StepSimulation(delta);
985  else collisionWorld.PerformDiscreteCollisionDetection();
986  }
987  }
988 }
void RemoveRigidBody(RigidBody rigidBody)
Removes the rigid body from the engine processing pipeline.
Character CreateCharacter(ColliderShape collider, float stepHeight)
Creates the character.
void RemoveCollider(Collider collider)
Removes the collider from the engine processing pipeline.
Constraint CreateConstraint(ConstraintTypes type, RigidBody rigidBodyA, Matrix frameA, bool useReferenceFrameA=false)
Creates the constraint.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Definition: DirectXTexP.h:170
bool Is2D
Gets a value indicating whether the collider shape is 2D.
void Dispose()
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resourc...
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
Collider CreateCollider(ColliderShape shape)
Creates the collider.
void AddRigidBody(RigidBody rigidBody)
Adds the rigid body to the engine processing pipeline.
Main Game class system.
Definition: Game.cs:32
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
_In_ size_t count
Definition: DirectXTexP.h:174
void Initialize(PhysicsEngineFlags flags=PhysicsEngineFlags.None)
Initializes the Physics engine using the specified flags.
RigidBody CreateRigidBody(ColliderShape collider)
Creates the rigid body.
List< HitResult > RaycastPenetrating(Vector3 from, Vector3 to)
Raycasts penetrating any shape the ray encounters.
Structure using the same layout than System.Drawing.Point.
Definition: Point.cs:35
void AddConstraint(Constraint constraint)
Adds the constraint to the engine processing pipeline.
static void Distance(ref Vector3 value1, ref Vector3 value2, out float result)
Calculates the distance between two vectors.
Definition: Vector3.cs:507
void AddConstraint(Constraint constraint, bool disableCollisionsBetweenLinkedBodies)
Adds the constraint to the engine processing pipeline.
Constraint CreateConstraint(ConstraintTypes type, RigidBody rigidBodyA, RigidBody rigidBodyB, Matrix frameA, Matrix frameB, bool useReferenceFrameA=false)
Creates the constraint.
void AddCollider(Collider collider)
Adds the collider to the engine processing pipeline.
List< HitResult > ShapeSweepPenetrating(ColliderShape shape, Matrix from, Matrix to)
Pefrorms a sweep test using a collider shape and never stops until "to"
void RemoveCharacter(Character character)
Removes the character from the engine processing pipeline.
void AddCharacter(Character character, CollisionFilterGroups group, CollisionFilterGroups mask)
Adds the character to the engine processing pipeline.
void RemoveConstraint(Constraint constraint)
Removes the constraint from the engine processing pipeline.
Generic contact between colliders, Always using Vector3 as the engine allows mixed 2D/3D contacts...
Definition: Contact.cs:11
using SiliconStudio.Paradox. Physics
SiliconStudio.Core.Mathematics.Vector3 Vector3
void AddCharacter(Character character)
Adds the character to the engine processing pipeline.
HitResult Raycast(Vector3 from, Vector3 to)
Raycasts and stops at the first hit.
HitResult ShapeSweep(ColliderShape shape, Matrix from, Matrix to)
Pefrorms a sweep test using a collider shape and stops at the first hit
void AddRigidBody(RigidBody rigidBody, CollisionFilterGroups group, CollisionFilterGroups mask)
Adds the rigid body to the engine processing pipeline.
void AddCollider(Collider collider, CollisionFilterGroups group, CollisionFilterGroups mask)
Adds the collider to the engine processing pipeline.
Represents a 4x4 mathematical matrix.
Definition: Matrix.cs:47