Physics - Bullet Tutorial2 example

From Wikiid
Jump to: navigation, search

CcdConstructionInfo defines various properties of the construction of an object as it pertains to collision detection and physics calculations. We can use the same construction information to produce many of the same type of object. Take bricks for example. Each brick is constructed the same, so you can use the same construction information for each. */

 CcdConstructionInfo object_cons_a;
 CcdConstructionInfo object_cons_b;

Create a new box collision shape. This will be the "static" box.

 box_a = new BoxShape(SimdVector3(30.0f, 4.0f, 30.0f));
 box_a->SetMargin(1.0f);
 a_motion_state.setWorldPosition(0.0f, -10.0f, 0.0f);

The object is static and doesn't need most of this stuff. You can include it for consistency, but otherwise it doesn't matter.

 object_cons_a.m_friction = 0.5f;

Think of this as the amount of "bounce" of the object. Higher values make it more bouncy.

 object_cons_a.m_restitution = 0.00f;

Think of this as the amount of "bounce" of the object. Higher values make it more bouncy.

 object_cons_a.m_linearDamping = 0.2f;
 object_cons_a.m_angularDamping = 0.1f;
 object_cons_a.m_gravity = SimdVector3(0.0f, 0.0f, 0.0f);
 object_cons_a.m_mass = 0.0f;
 box_a->CalculateLocalInertia(0.0f, localInertia);
 object_cons_a.m_localInertiaTensor = localInertia;
 object_cons_a.m_collisionFlags = CollisionObject::isStatic;  // A static object. It won't move with physics.
 object_cons_a.m_collisionShape = box_a;  // Set the shape to do collision tests and physics against.
 object_cons_a.m_MotionState = &a_motion_state;
 box_a_controller = new CcdPhysicsController(object_cons_a);  // Create a new controller for the object.

Ok, near as I can tell, motion threshold is about efficiency. If the object didn't move much, then don't treat it as a continuously moving object, just test against it's current position. For example, if an airplane moves 1cm, you can fairly safely perform physics calculations of a person hitting it without doing exact calculations of movement over the time period for that 1cm. You can do the calculations based just upon the plane's new position and rotation.

 box_a_controller->GetRigidBody()->m_ccdSquareMotionTreshold = 1.0f;  // The object is static anyway in this case.
 physics_environment->addCcdPhysicsController(box_a_controller);  // Add the object to the environment.

Now do box b. Box b will be a dynamic motion object. Create a new box collision shape. This will be the "dynamic" box.

 box_b = new BoxShape(SimdVector3(1.0f, 1.0f, 1.0f));
 box_b->SetMargin(0.05f);  // Feel free to play around with this value.

Set up orientation and location of the object.

 SimdQuaternion quat;
 SimdVector3 axis(0,0,1);
 SimdScalar angle=0.0f;
 quat.setRotation(axis,angle);
 b_motion_state.setWorldOrientation(quat.getX(),quat.getY(),quat.getZ(),quat[3]);
 b_motion_state.setWorldPosition(0.0f, 11.0f, 0.0f);

Object 'b' has its motion affected in a dynamic manner, and so set various physical properties.

 object_cons_b.m_friction = 0.5f;
 object_cons_b.m_restitution = 0.01f;
 object_cons_b.m_linearDamping = 0.2f;  // Think of this as resistance to translational motion.
 object_cons_b.m_angularDamping = 0.1f;  // Think of this as resistance to rotation.
 object_cons_b.m_gravity = SimdVector3(0.0f, 0.0f, 0.0f);
 object_cons_b.m_mass = 10.0f;
 box_b->CalculateLocalInertia(10.0f, localInertia);
 object_cons_b.m_localInertiaTensor = localInertia;
 object_cons_b.m_collisionFlags = 0;  // Nothing special - treat it as a normal dynamic object.
 object_cons_b.m_collisionShape = box_b;  // Set the shape to do collision tests against.
 object_cons_b.m_MotionState = &b_motion_state;
 box_b_controller = new CcdPhysicsController(object_cons_b);  // Create a new controller for the object.
 box_b_controller->GetRigidBody()->m_ccdSquareMotionTreshold = 1.0f;  // As before.
 box_b_controller->SetLinearVelocity(40.0f, 0.0f, 0.0f, false);  // This will apply some rotation force to the object.

Add the physics object to our environment. This will allow the environmnent to affect it.

 physics_environment->addCcdPhysicsController(box_b_controller);

This adds a point-to-point constraint. Basically, the object is free to move anywhere that is a set distance from the point. Normally two controllers are used, with the first 3 values being a linear offset from a controller - that is, one object (second?) will be constrained to the location of the other (first?), plust some offset. You can specify the rotation axes as well. Play around with it some, add constraints to other things - I've simply shown how to create a basic sort of pendulum here. Note that the second object is not used, so box_b is constrained to the world center plus some offset.

Constraint types can be any one of: PHY_POINT2POINT_CONSTRAINT, PHY_LINEHINGE_CONSTRAINT, PHY_ANGULAR_CONSTRAINT, PHY_VEHICLE_CONSTRAINT, PHY_GENERIC_6DOF_CONSTRAINT.

Each should be fairly self-explanatory as to the type of constraint it provides.

 int constraintID = physics_environment->createConstraint(box_b_controller, 0, PHY_POINT2POINT_CONSTRAINT, 0.0f, 10.0f, 0.0f, 0.0f, 0.0f, 1.0f);

Now do box c. Box c is exactly the same as box b, except it has a different starting location. Note that we can use the basic construction of box b to make box c.

 box_c = new BoxShape(SimdVector3(1.0f, 1.0f, 1.0f));
 box_c->SetMargin(0.05f);
 c_motion_state.setWorldPosition(0.0f, 9.5f, 0.0f);
 object_cons_b.m_MotionState = &c_motion_state;
 box_c_controller = new CcdPhysicsController(object_cons_b);
 box_c_controller->GetRigidBody()->m_ccdSquareMotionTreshold = 1.0f;
 box_c_controller->SetLinearVelocity(0.0f, -5.0f, 0.0f, false);
 physics_environment->addCcdPhysicsController(box_c_controller);
 // Now do box d.
 box_d = new BoxShape(SimdVector3(1.0f, 2.0f, 1.0f));  // Make box d a little larger.
 box_d->SetMargin(0.05f);
 d_motion_state.setWorldPosition(0.0f, 5.0f, 0.0f);  // Set its world position as appropriate.
 object_cons_b.m_MotionState = &d_motion_state;  // Use object b construction again.
 // object_cons_b.m_collisionFlags = CollisionObject::noContactResponse;  // Try this. Things just don't react to it. Collision is detected, but no physics reaction takes place.

A quick note on friction and restitution. The total amount of bounce between two object depends on both objects. It's importantant to realise that friction and restitution are not values of any particular surface, but rather a value of the interaction of two surfaces. So why is it defined for each object? In order to determine the overall friction and restitution between any two surfaces in a collision.

 object_cons_b.m_friction = 0.8f;  // Set a different friction value.
 object_cons_b.m_mass = 20.0f;  // Make box d a different mass.
 object_cons_b.m_restitution = 0.01f;  // Think of this as the amount of "bounce" of the object. Higher values make it more bouncy.

I've set damping values again here so that you can play around with them and see the difference it makes for objects. Play around with it a little.

 object_cons_b.m_linearDamping = 0.2f;
 object_cons_b.m_angularDamping = 0.1f;
 object_cons_b.m_collisionShape = box_d;  // The box size has been changed, so change the collision shape too.
 box_d->CalculateLocalInertia(object_cons_b.m_mass, localInertia);  // Inertia is, in common usage, resistance to change in velocity.
 object_cons_b.m_localInertiaTensor = localInertia;  // Not entirely sure how a local inertia tensor is used, but I think it
 box_d_controller = new CcdPhysicsController(object_cons_b);
 box_d_controller->GetRigidBody()->m_ccdSquareMotionTreshold = 1.0f;
 box_d_controller->SetLinearVelocity(0.0f, -6.0f, 0.0f, false);
 physics_environment->addCcdPhysicsController(box_d_controller);
 unsigned int current_time, prev_time = 0;
 while(bProgramRunning)
 {
   current_time = SDL_GetTicks();

You may notice that the delta timing has been changed here since tutorial 1. I find these values work better - play around with it and see. Either way, this should run the physics at the same speed regardless of frame rates. */

   if(current_time - prev_time >= 15)
   {
     updateInput();
     physics_environment->proceedDeltaTime(0.0f, 0.002f * (float)(current_time - prev_time));
     prev_time = current_time;
   }
   drawGL();  // Draw the boxes on-screen.
   glFinish();  // Wait for OpenGL calls to finish processing.
   SDL_GL_SwapBuffers();  // Update the screen.
 }


User input, and how it will affect the scene.

         case SDLK_SPACE:
           box_d_controller->GetLinearVelocity(x, y, z);
           box_d_controller->SetLinearVelocity(x, y + 5.0f, z, false);
           break;
         case SDLK_a:
           box_d_controller->GetLinearVelocity(x, y, z);
           box_d_controller->SetLinearVelocity(x - 5.0f, y, z, false);
           break;
         case SDLK_c:
           box_d_controller->GetLinearVelocity(x, y, z);
           box_d_controller->SetLinearVelocity(x, y - 5.0f, z, false);
           break;
         case SDLK_d:
           box_d_controller->GetLinearVelocity(x, y, z);
           box_d_controller->SetLinearVelocity(x + 5.0f, y, z, false);
           break;
         case SDLK_s:
           box_d_controller->GetLinearVelocity(x, y, z);
           box_d_controller->SetLinearVelocity(x, y, z + 5.0f, false);
           break;
         case SDLK_w:
           box_d_controller->GetLinearVelocity(x, y, z);
           box_d_controller->SetLinearVelocity(x, y, z - 5.0f, false);
           break;

A manifold represents and maintains a collision between two objects. It gives up to four points of contact. You can obtain a collision manifold from the collision dispatcher, and run through each object. Note that RigidBody is a type of CollisionObject, which can have a pointer of user data attached. I'll leave you to figure out just how useful that is.

 for(int i = 0; i < collision_dispatcher->GetNumManifolds(); i++)
 {
   PersistentManifold *collision_manifold = collision_dispatcher->GetManifoldByIndexInternal(i);
   CollisionObject *obja = static_cast<CollisionObject*>(collision_manifold->GetBody0());
   CollisionObject* objb = static_cast<CollisionObject*>(collision_manifold->GetBody1());

Occasionally I find that one contact point is mis-placed, and set to the world center. This seems to fix the problem. I should also note that the awry contact point only presents itself when the object stops and is deactivated. Don't do this every frame - it will occasionally cause the refresh to remove all contact points, especially if one object is moving parallel to the the surface of the other object.

   if(!obja->IsActive() || !objb->IsActive())
     collision_manifold->RefreshContactPoints(obja->m_worldTransform,objb->m_worldTransform);

Go through each collision point (there doesn't have to be four, there can be less).

   for(int j = 0; j < collision_manifold->GetNumContacts(); j++)
   {

A manifold point is a point of contact for the collision. Get the point of contact of the collision.

     ManifoldPoint &pt = collision_manifold->GetContactPoint(j);

Note here that two points are used. One (A) is actually a little redundant. Two points are actually specified because of object penetration - the calculations are not perfect, and one object can penetrate into another. As such, there are different graphical points of contact for what should be the one collision point. The value m_distance1 of the manifold point shows the penetration depth.

     SimdVector3 ptA = pt.GetPositionWorldOnA();
     SimdVector3 ptB = pt.GetPositionWorldOnB();
     glColor3f(1.0f, 0.0f, 0.0f);
     glDisable(GL_DEPTH_TEST);
     glPointSize(5.0f);

Though usually not much difference is usually seen, draw both points anyway.

     glBegin(GL_POINTS);
     glVertex3f(ptA.x(), ptA.y(), ptA.z());
     glVertex3f(ptB.x(), ptB.y(), ptB.z());
     glEnd();
     glEnable(GL_DEPTH_TEST);
   }
 }



Wikiid Pages relating to the Bullet physics engine (edit)
Main articles: Physics - Bullet
On the Bullet website: Forum, Doxygen docs, FAQ, A Module diagram, Draft user manual, CCD & Physics Paper
Annotated example programs: HelloWorld, Tutorial2
Other: Collected advice snippets
See also : Intersection tests, GameTools Sabot