Using the ODE physics engine

The Open Dynamics Engine (ODE) in short, is a very powerful and feature-rich implementation of a rigid body physics system. It has been successfully integrated into various commercial simulation and game projects like World of Goo and Nail'd, for example. Panda3D comes with this proven piece of physics technology included out of the box. This leaves it to us to enable and use ODE in our code, so let's get started!

Getting ready

To get set for this recipe, please follow Setting up the game structure first. You can find this recipe in Chapter 1.

How to do it...

The ODE physics engine is used like the following in a Panda3D application:

  1. Open Application.py and add this code:
    from direct.showbase.ShowBase import ShowBase
    from panda3d.core import *
    from panda3d.ode import *
    import random
    class Application(ShowBase):
    def __init__(self):
    ShowBase.__init__(self)
    self.smiley = loader.loadModel("smiley")
    self.smileyCount = 0
    self.cam.setPos(0, -100, 10)
    self.setupODE()
    self.addGround()
    taskMgr.doMethodLater(0.01, self.addSmiley, "AddSmiley")
    taskMgr.add(self.updateODE, "UpdateODE")
    
  2. Append the following code to the file:
    def setupODE(self):
    self.odeWorld = OdeWorld()
    self.odeWorld.setGravity(0, 0, -9.81)
    self.odeWorld.initSurfaceTable(1)
    self.odeWorld.setSurfaceEntry(0, 0, 200, 0.7, 0.2, 0.9, 0.00001, 0.0, 0.002)
    self.space = OdeSimpleSpace()
    self.space.setAutoCollideWorld(self.odeWorld)
    self.contacts = OdeJointGroup()
    self.space.setAutoCollideJointGroup(self.contacts)
    def addGround(self):
    cm = CardMaker("ground")
    cm.setFrame(-500, 500, -500, 500)
    ground = render.attachNewNode(cm.generate())
    ground.setColor(0.2, 0.4, 0.8)
    ground.lookAt(0, 0, -1)
    groundGeom = OdePlaneGeom(self.space, Vec4(0, 0, 1, 0))
    
  3. Next, add these methods:
    def addSmiley(self, task):
    sm = render.attachNewNode("smiley-instance")
    sm.setPos(random.uniform(-20, 20), random.uniform(-30, 30), random.uniform(10, 30))
    self.smiley.instanceTo(sm)
    body = OdeBody(self.odeWorld)
    mass = OdeMass()
    mass.setSphereTotal(10, 1)
    body.setMass(mass)
    body.setPosition(sm.getPos())
    geom = OdeSphereGeom(self.space, 1)
    geom.setBody(body)
    sm.setPythonTag("body", body)
    self.smileyCount += 1
    if self.smileyCount == 1000:
    return task.done
    return task.again
    def updateODE(self, task):
    self.space.autoCollide()
    self.odeWorld.quickStep(globalClock.getDt())
    for smiley in render.findAllMatches("smiley-instance"):
    body = smiley.getPythonTag("body")
    smiley.setPosQuat(body.getPosition(), Quat(body.getQuaternion()))
    self.contacts.empty()
    return task.cont
    
  4. Press F6 to launch the program and see the smileys roll, tumble, and bounce:
How to do it...

How it works...

For ODE to work, we need to do the following things.

We create a new OdeWorld, set its gravity, and add a default surface description. The surface description defines the properties of two surfaces that collide. The first two parameters of setSurfaceEntry() are indices in the surface table, with index zero being the default surface. The next parameter is the friction coefficient, which sets how slippery or sticky the surfaces react to each other. The higher this value is set, the higher the friction will be. The fourth parameter describes the bounciness on a scale between 0 and 1, while the fifth parameter sets the minimum velocity that is required for an object to bounce at all. The next two parameters define the values for error reduction and constraint force mixing, which influence to which extent objects are allowed to penetrate each other and how much force will be applied to push objects out of each other. This is followed by the slip parameter that is used to set a force-dependent slip value, which is useful for simulating car tires, for example. The last parameter sets a damping coefficient, which helps to keep the simulation more stable.

Next, we create an OdeSimpleSpace, which represents a space within which ODE tests for collisions. We configure ODE to automatically detect and resolve collisions. This requires a joint group, because whenever two objects intersect in ODE, a temporary joint is created between them that pushes the objects off each other.

In the addGround() method, we create a static ground plane, both in our visible scene as well as in ODE's simulation world.

Whenever a new smiley is added, we create a new OdeBody, set its mass and position and assign it to a new OdeSphereGeom. We then assign the ODE physics body to a tag of the smiley NodePath. This part of the code also shows a very important principle of ODE—the OdeBody is used for physics calculations, whereas the geometry is used for collision detection.

The updateOde() method is run every frame as a task. It first runs collision detection, then steps the physics simulation, and updates the positions of the objects in the scene graph. Before the method returns, we must not forget to clear the list of contact groups to keep the automatic collision response working properly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset