ODE is already included in the Panda3D 1.7.0 distribution. The ODE classes are all under pandac.PandaModules, so since you've already imported everything from there into your program (using the '*'), you don't have to do anything to start using them.
world
) and another for collision handling (called space
). So the first thing you do (you can do all of this in the constructor of your World class) is to instantiate and set up these two environments: # Set up the physical world self.world = OdeWorld() self.world.setGravity((0,0,-9.81)) # Surface properties self.world.initSurfaceTable(1) # We define 1 surface material self.world.setSurfaceEntry(0, 0, 150, 0.0, 9.1, 0.9, 0.00001, 0.0, 0.002) # Default surface material # Simulation space with collision self.space = OdeSimpleSpace() self.space.setAutoCollideWorld(self.world) self.contactgroup = OdeJointGroup() self.space.setAutoCollideJointGroup(self.contactgroup) self.space.setCollisionEvent("collision")
For each object you want to be part of the physics simulation, you have to create a physical body. Here is how the physical body of the box is created (note that you still need your original Panda model of the box, that's the visible version of the box):
# Physical body for the box self.boxbody = OdeBody(self.world) self.boxbody.setPosition((1,0,2)) self.boxbody.addForce((0,0,1000)) self.boxmass = OdeMass() self.boxmass.setBox(500, 0.3, 0.3, 0.3) self.boxbody.setMass(self.boxmass)
Now that you have a physical representation of the box, you still need to make an ODE collision solid for it and put into the collision environment. This is how:
# Collision body for the box self.boxsolid = OdeBoxGeom(self.space, 0.3, 0.3, 0.3) self.boxsolid.setCollideBits(BitMask32(0x00000001)) # Filters what objects this Box can collide into (required category) self.boxsolid.setCategoryBits(BitMask32(0x00000001)) # The Box itself is of that same category self.boxsolid.setBody(self.boxbody)
To see the effect of gravity on the box, you will now have to start a task that copies the position of the physical box to the position of the visual box at every frame, and advances the physics simulation world by one step:
taskMgr.add(self.simulate, 'ODE Simulation') def simulate(self, task): self.space.autoCollide() # Resolve collisions # Set the position and rotation of the graphical box from the physical box self.box.setPosQuat (render, self.boxbody.getPosition(), Quat(self.boxbody.getQuaternion())) self.world.quickStep(globalClock.getDt()) # Advance the simulation self.contactgroup.empty() # Clear collected collisions return Task.cont
Test this and make sure gravity is working as expected. Make sure to comment out the LerpPosInterval for the box since you no longer need it! You should also change the left mouse button handler so that it sets the position of both the visual box and the physical box back to the original position (to maintain similar functionality as before). You will also want to set the linear velocity of the box to 0 like this self.boxbody.setLinearVel( (0,0,0) )
, otherwise the box will keep going faster and faster
simulate
task should now look like this: def simulate(self, task): self.space.autoCollide() self.box.setPosQuat (render, self.boxbody.getPosition(), Quat(self.boxbody.getQuaternion())) self.door.setPosQuat(render, self.doorbody.getPosition(), Quat(self.doorbody.getQuaternion())) self.world.quickStep(globalClock.getDt()) self.contactgroup.empty() return Task.cont
You may notice that the door naturally falls down along with the box since there is nothing holding it up! We'll fix that next.
# Sliding motor for the door self.doorslider = OdeSliderJoint(self.world) # Instantiating a new slider joint self.doorslider.attach(self.doorbody, None) # Using the joint to attach door body to environment (None) self.doorslider.setAxis((-1,0,0)) # Slides down the x-axis self.doorslider.setParamLoStop(0) # Minimum position on the slider self.doorslider.setParamHiStop(2) # Maximum position on the slider self.doorslider.setParamFMax(50) # Sets the force of a motor attached to this joint
The last line here actually attaches a little motor to the joint, which we can give a certain velocity whenever we want to move the joint autonomously. Try replacing the LerpPosInterval calls for opening and closing the door, with calls like this: self.doorslider.setParamVel(0.5)
, where 0.5 is the velocity (can also be negative to go in the other direction).