PhysX is a proprietary physics programming library made by the graphics card specialist nVidia that simulates the behavior of rigid bodies. One of the library's major features is its ability to leverage the computing abilities of a graphics card to accelerate the calculation of the internal physics formulas used for the simulation. If a suitable graphics adapter cannot be found, the physics engine falls back to the system's CPU so that nobody's left behind.
This recipe will give you some insight into the wrapper that the Panda3D developers have created around this physics API.
This recipe builds upon the framework created in Setting up the game structure found in Chapter 1.
Additionally, you need to have the PhysX SDK installed on your system. For more information on licensing and how to download, see this website: http://developer.nvidia.com/object/physx_downloads.html.
These are the tasks required to create a program that uses PhysX:
NxCharacter.dll
from C:Program Files (x86)NVIDIA CorporationNVIDIA PhysX SDKv2.8.4_winBinwin32
to C:Panda3D-1.7.0in
. Application.py
and add the required imports and the constructor:from direct.showbase.ShowBase import ShowBase from panda3d.core import * from panda3d.physx import * import random class Application(ShowBase): def __init__(self): ShowBase.__init__(self) self.box = loader.loadModel("misc/rgbCube") self.boxCount = 0 self.cam.setPos(0, -100, 10) self.setupPhysX() self.addGround() taskMgr.doMethodLater(0.01, self.addBox, "AddBox") taskMgr.add(self.updatePhysX, "UpdatePhysX")
def setupPhysX(self): scene = PhysxSceneDesc() scene.setGravity(Vec3(0, 0, -9.81)) self.physxScene = PhysxManager.getGlobalPtr().createScene(scene) mat = self.physxScene.getMaterial(0) mat.setRestitution(0.7) mat.setStaticFriction(0.5) mat.setDynamicFriction(0.8) def addGround(self): cm = CardMaker("ground") cm.setFrame(-500, 500, -500, 500) ground = render.attachNewNode(cm.generate()) ground.setColor(0.2, 0.2, 0.2) ground.lookAt(0, 0, -1) shape = PhysxPlaneShapeDesc() shape.setPlane(Vec3(0, 0, 1), 0) actor = PhysxActorDesc() actor.addShape(shape) self.physxScene.createActor(actor)
def addBox(self, task): bx = render.attachNewNode("box-instance") self.box.instanceTo(bx) shape = PhysxBoxShapeDesc() shape.setDimensions(Vec3(0.5, 0.5, 0.5)) body = PhysxBodyDesc() body.setMass(10) actor = PhysxActorDesc() actor.setBody(body) actor.addShape(shape) actor.setGlobalPos(Point3(random.uniform(-20, 20), random.uniform(-30, 30), random.uniform(10, 30))) physxActor = self.physxScene.createActor(actor) physxActor.attachNodePath(bx) self.boxCount += 1 PhysXusingif self.boxCount == 1000: return task.done return task.again def updatePhysX(self, task): self.physxScene.simulate(globalClock.getDt()) self.physxScene.fetchResults() return task.cont
First, we make sure to place NxCharacter.dll
in the right location, or else we won't be able to use the API. The exact path of the source directory might vary slightly, depending on which version of the PhysX SDK is installed.
After adding the boilerplate code for loading modules and setting up the Application
class, we can proceed to the setupPhysX()
method, where we create a new PhysX scene with earth-like gravitation. We also modify the material stored at index zero—the default material—to be a bit more bouncy and also have more friction.
We then add a ground plane by creating a shape description, adding it to an actor description, and creating the new physics actor using the createActor()
method.
In the addSmiley()
method, we connect a shape, used for collision detection, and body, which is used for physics calculations, to form a new actor. We also attach the created smiley NodePath
to the newly created actor, so its transformation is automatically updated as PhysX advances the simulation.
Finally, we add the code for the task that keeps on updating the simulation. This method first performs a simulation step and afterwards instructs the PhysX API to collect and apply the results of the calculations it performed.