Skip to content

Commit

Permalink
Updated the collision callbacks so the callback only occurs if the ma…
Browse files Browse the repository at this point in the history
…nifold has contact points.

Added the Bullet manual
Improved the readme documentation.
  • Loading branch information
Phong13 committed May 16, 2016
1 parent 05a85e0 commit 9ea1d69
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 120 deletions.
Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,34 +1,66 @@
GETTING STARTED WITH BULLET PHYSICS
===================================

BULLET UNITY CONTAINS TWO API'S

1) BulletSharp - Located in Plugins/BulletSharp is a low level set of C# wrappers for the native bullet libraries. These wrappers are not integrated with Unity in
any way. Simulations can be run that are not synchronized with Unity's game loop. The demos in BulletUnity/Examples/Scenes/BulletSharpDemos use this API.

2) BulletUnity - Located in BulletUnity/Scripts is a set of Unity Components similar to the PhysX components. These components use the lower level BulletSharp API.

======================
SOURCES OF INFORMATION

The Bullet Physics Manual. Download it from the Bullet Physics project on github. It is short (can be read in 1 hour) and will set you up well for working with
The BULLET PHYSICS MANUAL. Download it from the Bullet Physics project on github. It is short (can be read in 1 hour) and will set you up well for working with
Bullet Physics.

The Bullet Physics Wiki has a lot of good information http://bulletphysics.org/mediawiki-1.5.8/index.php/Main_Page.

The Bullet Physics Forums http://www.bulletphysics.org/Bullet/phpBB3/

The Bullet Physics Examples (ported to C#, then ported to Unity) located in the BulletUnity/BulletSharpExamples folder. At the time of writing not all of these
have been ported. More are available in the https://github.com/Phong13/BulletSharpPInvoke project.
The Bullet Physics Examples (ported to C#, then ported to Unity) located in the BulletUnity/Examples/Scenes/BulletSharpDemos folder. More are available in the https://github.com/Phong13/BulletSharpPInvoke project.

DON'T BE AFRAID TO LOOK AT THE BULLET PHYSICS SOURCE CODE. I know it sounds intimidating, but it is much easier than you think. If you are not sure what an API
call or class does or what a member variable is for, then search for it in the bullet sourcecode. Even if you are not a C++ programmer you can probably deduce
what it does. I recently spent a few hours on google trying to find good information explaining the difference between btGhostObject and btPairCachingGhostObject.
Eventually I opened the btGhostObject.cpp source file and had a look. The entire sourcecode for both classes is only 170 lines. In about 10 minutes I had a complete
understanding how both classes worked. Much better than an online tutorial.

It is possible to debug from Unity into the Bullet Physics library with Visual Studio (probably possible with other IDEs but I havn't tried). To do this you need
to clone the https://github.com/Phong13/BulletSharpPInvoke project. Build a debug, x64 version of libbulletc for windows. Copy the .dll and .pdb file to Unity project.
It is possible to debug from Unity into the Bullet Physics library native code with Visual Studio (probably possible with other IDEs but I havn't tried). To do this you need
to clone the https://github.com/Phong13/BulletSharpPInvoke project. Build a debug, x64 version of libbulletc for windows. Copy the .dll and .pdb file to Unity project (Plugins/Native/x64.
Then launch Unity from the Visual Studio as described here https://msdn.microsoft.com/en-us/library/605a12zt.aspx.

IMPORTANT DIFFERENCES WITH UNITY'S PHYSICS
================================================
IMPORTANT DIFFERENCES WITH UNITY'S PHYSX PHYSICS

Don't try to move the rigid bodies by writing to myRigidBody.transform.position or .rotation. Bullet Physics is not as tightly integrated with Unity as PhysX.
Consider the transform to be completely under the control of Bullet Physics and translate/rotate your rigidBodies using the Bullet Physics API calls.
Consider the transform to be completely under the control of Bullet Physics (for non-kinematic RigidBodies) and translate/rotate your rigidBodies using the Bullet Physics API calls.

Be careful of localScale. It is almost completely ignored by Bullet Physics. There are only a few CollisionShapes that can be scaled in the Bullet API (at the time
of writing these have not been implemented in Unity). Modify the shape of the CollisionShape and leave localScale at 1,1,1.
of writing these have not been implemented in Unity). Modify the shape of the CollisionShape and leave localScale at 1,1,1. You can add your MeshRender as a child of
the CollisionShape and scale that.

Don't try to nest Rigid Bodies. Bullet Unity has no control over the order that bullet updates the transforms of objects each simulation step. If the child RigidBodies get
updated before the parent RigidBodies then the child will jitter terribly.

WRONG
RigidBodyGameObjectA
-RigidBodyGameObjectB
-RigidBodyGameObjectC

CORRECT
RigidBodyGameObjectA
RigidBodyGameObjectB
RigidBodyGameObjectC

======================================
FEEL FREE TO CONTRIBUTE TO THE PROJECT

Bullet Unity is an open source project in GitHub. Please feel free to clone the github repository and contribute:

https://github.com/Phong13/BulletUnity
https://github.com/Phong13/BulletSharpPInvoke




Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void FixedUpdate()
transform.rotation = BSExtensionMethods2.ExtractRotationFromMatrix(ref trans);
transform.localScale = BSExtensionMethods2.ExtractScaleFromMatrix(ref trans);
}

/*
public void OldUpdate()
{
float FrameDelta = Time.fixedDeltaTime; // todo put a variable in the physics world for this.
Expand Down Expand Up @@ -177,5 +177,6 @@ public void OldUpdate()
transform.position = trans.Origin.ToUnity();
}
*/
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class PersistentManifoldList
List<PersistentManifoldList> newContacts = new List<PersistentManifoldList>();
List<CollisionObject> objectsToRemove = new List<CollisionObject>();

public void Start()
public virtual void Start()
{

BCollisionObject co = GetComponent<BCollisionObject>();
Expand All @@ -32,6 +32,10 @@ public void Start()

public override void OnVisitPersistentManifold(PersistentManifold pm)
{
if (pm.NumContacts == 0)
{
return;
}
CollisionObject other;
if (pm.Body0 == myCollisionObject)
{
Expand Down
14 changes: 14 additions & 0 deletions UnityProject/Assets/BulletUnity/Scripts/BCollisionObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public virtual CollisionObject GetCollisionObject()
return m_collisionObject;
}

//Don't try to call functions on other objects such as the Physics world since they may not exit.
protected virtual void Awake()
{
m_collisionShape = GetComponent<BCollisionShape>();
Expand All @@ -141,12 +142,22 @@ protected virtual void RemoveObjectFromBulletWorld()
BPhysicsWorld.Get().RemoveCollisionObject(m_collisionObject);
}


//Add this object to the world on Start. We are doing this so that scripts which add this componnet to
//game objects have a chance to configure them before the object is added to the bullet world.
//Be aware that Start is not affected by script execution order so objects such as constraints should
//make sure that objects they depend on have been added to the world before they add themselves.
internal virtual void Start()
{
m_startHasBeenCalled = true;
AddObjectToBulletWorld();
}

//OnEnable and OnDisable are called when a game object is Activated and Deactivated.
//Unfortunately the first call comes before Awake and Start. We suppress this call so that the component
//has a chance to initialize itself. Objects that depend on other objects such as constraints should make
//sure those objects have been added to the world first.
//don't try to call functions on world before Start is called. It may not exist.
protected virtual void OnEnable()
{
if (!isInWorld && m_startHasBeenCalled)
Expand All @@ -155,6 +166,9 @@ protected virtual void OnEnable()
}
}

// when scene is closed objects, including the physics world, are destroyed in random order.
// There is no way to distinquish between scene close destruction and normal gameplay destruction.
// Objects cannot depend on world existing when they Dispose of themselves. World may have been destroyed first.
protected virtual void OnDisable()
{
if (isInWorld)
Expand Down
2 changes: 1 addition & 1 deletion UnityProject/Assets/BulletUnity/Scripts/BGhostObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ internal override bool _BuildCollisionObject()
HashSet<CollisionObject> objsCurrentlyInContactWith = new HashSet<CollisionObject>();
void FixedUpdate()
{
//TODO what if objects are destroyed. How will TriggerExit be called for that object? Should be tracking InstanceIDs
//TODO should do two passes like with collisions
objsCurrentlyInContactWith.Clear();
for (int i = 0; i < m_ghostObject.NumOverlappingObjects; i++)
{
Expand Down
108 changes: 0 additions & 108 deletions UnityProject/Assets/BulletUnity/Scripts/BPhysicsWorld.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
using BulletUnity.Debugging;


// TODO order of destruction is an issue
// TODO all constraints need to be removed from a rigid body before the rigid body is destroyed / removed

namespace BulletUnity {
public class BPhysicsWorld : MonoBehaviour, IDisposable {

Expand Down Expand Up @@ -667,109 +664,4 @@ public void OnPhysicsStep(CollisionWorld world)
}
}
}

/*
public class BDefaultCollisionHandler{
public struct CollisionPair
{
public int obj0ID;
public int obj1ID;
public CollisionPair(CollisionObject a, CollisionObject b)
{
int idA = a.BroadphaseHandle.UniqueId;
int idB = b.BroadphaseHandle.UniqueId;
if (idA < idB) {
obj0ID = idA;
obj1ID = idB;
} else
{
obj0ID = idB;
obj1ID = idB;
}
}
public override int GetHashCode()
{
return obj0ID ^ obj1ID;
}
public override bool Equals(object obj)
{
if (obj is CollisionPair) return false;
else
{
if (((CollisionPair) obj).obj0ID == obj0ID &&
((CollisionPair) obj).obj1ID == obj1ID)
{
return true;
}
return false;
}
}
}
public class ManifoldPoints
{
public int frameLastVisited = 0;
public List<PersistentManifold> manifolds = List<PersistentManifold>();
}
CollisionWorld m_world;
Dictionary<CollisionPair, ManifoldPoints> pair2ManifoldMap = new Dictionary<CollisionPair, List<ManifoldPoints>>();
public void OnPhysicsStep()
{
int numManifolds = m_world.Dispatcher.NumManifolds;
// collect manifolds
pair2ManifoldMap.Clear();
for (int i = 0; i < numManifolds; i++)
{
PersistentManifold contactManifold = m_world.Dispatcher.GetManifoldByIndexInternal(i);
CollisionObject a = contactManifold.Body0;
CollisionObject b = contactManifold.Body1;
bool hasCallback = false;
if (a is CollisionObject && a.UserObject is BCollisionObject && ((BCollisionObject)a.UserObject).onCollisionCallback != null){
hasCallback = true;
}
if (b is CollisionObject && b.UserObject is BCollisionObject && ((BCollisionObject)b.UserObject).onCollisionCallback != null)
{
hasCallback = true;
}
if (hasCallback)
{
CollisionPair pair = new CollisionPair(contactManifold.Body0, contactManifold.Body1);
ManifoldPoints pms;
if (!pair2ManifoldMap.TryGetValue(pair, out pms))
{
//TODO implement pool
pms = new ManifoldPoints();
pair2ManifoldMap.Add(pair, pms);
}
pms.Add(contactManifold);
}
}
//second call the callbacks
foreach (CollisionPair p in pair2ManifoldMap.Keys)
{
List<PersistentManifold> pms = pair2ManifoldMap[p];
for (int i = 0; i < pms.Count; i++)
{
CollisionObject a = pms[i].Body0;
CollisionObject b = pms[i].Body1;
if (a is CollisionObject && a.UserObject is BCollisionObject && ((BCollisionObject)a.UserObject).onCollisionCallback != null)
{
((BCollisionObject)a.UserObject).onCollisionCallback(pms[i]);
}
if (b is CollisionObject && b.UserObject is BCollisionObject && ((BCollisionObject)b.UserObject).onCollisionCallback != null)
{
((BCollisionObject)b.UserObject).onCollisionCallback(pms[i]);
}
}
}
}
}
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace BulletUnity {
[System.Serializable]
public class B6DOFConstraint : BTypedConstraint {
//Todo not sure if this is working
//Todo breaking strength
//todo should be properties so can capture changes and propagate to scene
public static string HelpMessage = "\n" +
"\nTIP: To see constraint limits:\n" +
Expand Down Expand Up @@ -95,6 +94,8 @@ internal override bool _BuildConstraint() {
sl.AngularUpperLimit = m_angularLimitUpperRadians.ToBullet();
sl.TranslationalLimitMotor.TargetVelocity = m_motorLinearTargetVelocity.ToBullet();
sl.TranslationalLimitMotor.MaxMotorForce = m_motorLinearMaxMotorForce.ToBullet();
sl.BreakingImpulseThreshold = m_breakingImpulseThreshold;
sl.DebugDrawSize = m_debugDrawSize;
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ internal override bool _BuildConstraint() {
m_constraintPtr = new Point2PointConstraint(rba, m_localConstraintPoint.ToBullet());
}
m_constraintPtr.Userobject = this;
m_constraintPtr.BreakingImpulseThreshold = m_breakingImpulseThreshold;
m_constraintPtr.DebugDrawSize = m_debugDrawSize;
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ internal override bool _BuildConstraint() {
sl.SetLimit(m_swingSpan1Radians, m_swingSpan2Radians, m_twistSpanRadians, m_softness, m_biasFactor, m_relaxationFactor);
m_constraintPtr.Userobject = this;
m_constraintPtr.DebugDrawSize = m_debugDrawSize;
m_constraintPtr.BreakingImpulseThreshold = m_breakingImpulseThreshold;
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ internal override bool _BuildConstraint() {
return false;
}
m_constraintPtr.Userobject = this;
m_constraintPtr.DebugDrawSize = m_debugDrawSize;
m_constraintPtr.BreakingImpulseThreshold = m_breakingImpulseThreshold;

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ internal override bool _BuildConstraint() {
((HingeConstraint)m_constraintPtr).SetLimit(m_lowLimitAngleRadians, m_highLimitAngleRadians, m_limitSoftness, m_limitBiasFactor);
}
m_constraintPtr.Userobject = this;
m_constraintPtr.DebugDrawSize = m_debugDrawSize;
m_constraintPtr.BreakingImpulseThreshold = m_breakingImpulseThreshold;
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ internal override bool _BuildConstraint() {
sl.LowerAngularLimit = m_lowerAngularLimitRadians;
sl.UpperAngularLimit = m_upperAngularLimitRadians;
m_constraintPtr.Userobject = this;
m_constraintPtr.DebugDrawSize = m_debugDrawSize;
m_constraintPtr.BreakingImpulseThreshold = m_breakingImpulseThreshold;
return true;
}
}
Expand Down

0 comments on commit 9ea1d69

Please sign in to comment.