class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) dlight = DirectionalLight('dlight') dlight.setColor(VBase4(0.8, 0.8, 0.5, 1)) dlnp = self.render.attachNewNode(dlight) dlnp.setHpr(0, -60, 0) self.render.setLight(dlnp) self.balls = [Ball(self) for x in range(NUMBALLS)] # Setup our physics world and the body self.world = OdeWorld() self.world.setGravity(0, 0, -9.81) if 0: self.body = OdeBody(self.world) M = OdeMass() M.setSphere(7874, 1.0) self.body.setMass(M) self.body.setPosition(self.sphere.getPos(self.render)) self.body.setQuaternion(self.sphere.getQuat(self.render)) ## Set the camera position self.disableMouse() self.angle = 0.0 self.camera.setPos(1000, 1000, 1000) self.camera.lookAt(0, 0, 0) #self.enableMouse() # Create an accumulator to track the time since the sim # has been running self.deltaTimeAccumulator = 0.0 # This stepSize makes the simulation run at 60 frames per second self.stepSize = 1.0 / 60.0 taskMgr.doMethodLater(1.0, self.simulationTask, "Physics Simulation") def simulationTask(self, task): if 0: # Add the deltaTime for the task to the accumulator self.deltaTimeAccumulator += globalClock.getDt() while self.deltaTimeAccumulator > self.stepSize: # Remove a stepSize from the accumulator until # the accumulated time is less than the stepsize self.deltaTimeAccumulator -= self.stepSize # Step the simulation self.world.quickStep(self.stepSize) for ball in self.balls: ball.evolve() deltas = [ball.getdelta(self.balls) for ball in self.balls] for i, ball in enumerate(self.balls): dx, dy, dz = deltas[i] ball.move(dx, dy, dz) ball.update() #print "moved" self.camera.setPos(CX + 2500 * math.sin(self.angle), CY + 2500 * math.cos(self.angle), CZ) self.camera.lookAt(CX, CY, CZ) self.angle += 0.01 return task.cont
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) dlight = DirectionalLight("dlight") dlight.setColor(VBase4(0.8, 0.8, 0.5, 1)) dlnp = self.render.attachNewNode(dlight) dlnp.setHpr(0, -60, 0) self.render.setLight(dlnp) self.balls = [Ball(self) for x in range(NUMBALLS)] # Setup our physics world and the body self.world = OdeWorld() self.world.setGravity(0, 0, -9.81) if 0: self.body = OdeBody(self.world) M = OdeMass() M.setSphere(7874, 1.0) self.body.setMass(M) self.body.setPosition(self.sphere.getPos(self.render)) self.body.setQuaternion(self.sphere.getQuat(self.render)) ## Set the camera position self.disableMouse() self.angle = 0.0 self.camera.setPos(1000, 1000, 1000) self.camera.lookAt(0, 0, 0) # self.enableMouse() # Create an accumulator to track the time since the sim # has been running self.deltaTimeAccumulator = 0.0 # This stepSize makes the simulation run at 60 frames per second self.stepSize = 1.0 / 60.0 taskMgr.doMethodLater(1.0, self.simulationTask, "Physics Simulation") def simulationTask(self, task): if 0: # Add the deltaTime for the task to the accumulator self.deltaTimeAccumulator += globalClock.getDt() while self.deltaTimeAccumulator > self.stepSize: # Remove a stepSize from the accumulator until # the accumulated time is less than the stepsize self.deltaTimeAccumulator -= self.stepSize # Step the simulation self.world.quickStep(self.stepSize) for ball in self.balls: ball.evolve() deltas = [ball.getdelta(self.balls) for ball in self.balls] for i, ball in enumerate(self.balls): dx, dy, dz = deltas[i] ball.move(dx, dy, dz) ball.update() # print "moved" self.camera.setPos(CX + 2500 * math.sin(self.angle), CY + 2500 * math.cos(self.angle), CZ) self.camera.lookAt(CX, CY, CZ) self.angle += 0.01 return task.cont
class MinigamePhysicsWorldBase: notify = DirectNotifyGlobal.directNotify.newCategory( 'MinigamePhysicsWorldBase') def __init__(self, canRender=0): self.canRender = canRender self.world = OdeWorld() self.space = OdeSimpleSpace() self.contactgroup = OdeJointGroup() self.bodyList = [] self.geomList = [] self.massList = [] self.rayList = [] self.showContacts = 0 self.jointMarkers = [] self.jointMarkerCount = 64 self.meshDataList = [] self.geomDataList = [] self.commonObjectInfoDict = {} self.maxColCount = 0 if self.canRender: self.odePandaRelationList = self.bodyList self.root = render.attachNewNode('physics root node') else: self.root = NodePath('physics root node') self.placerNode = self.root.attachNewNode('Placer') self.subPlacerNode = self.placerNode.attachNewNode('Placer Sub Node') self.commonObjectDict = {} self.commonId = 0 self.worldAttach = self.root.attachNewNode('physics geom attach point') self.timingCycleLength = 10.0 self.timingCycleOffset = 0.0 self.timingSimTime = 0.0 self.FPS = 60.0 self.DTAStep = 1.0 / self.FPS self.DTA = 0 self.useQuickStep = False self.deterministic = True self.numStepsInSimulateTask = 0 self.collisionEventName = 'ode-collision-%s' % id(self) self.space.setCollisionEvent(self.collisionEventName) self.accept(self.collisionEventName, self.__handleCollision) def delete(self): self.notify.debug('Max Collision Count was %s' % self.maxColCount) self.stopSim() self.commonObjectDict = None if self.canRender: for pair in self.odePandaRelationList: pair[0].removeNode() pair[1].destroy() self.odePandaRelationList = None else: for body in self.bodyList: body[1].destroy() self.bodyList = None for mass in self.massList: mass = None for geom in self.geomList: geom.destroy() geom = None for ray in self.rayList: ray.destroy() ray = None self.placerNode.removeNode() self.root.removeNode() for marker in self.jointMarkers: marker.removeNode() self.jointMarkers = None for data in self.geomDataList: data.destroy() for data in self.meshDataList: data.destroy() self.contactgroup.empty() self.world.destroy() self.space.destroy() self.world = None self.space = None self.ignore(self.collisionEventName) return def setupSimulation(self): if self.canRender: for count in xrange(self.jointMarkerCount): testMarker = render.attachNewNode('Joint Marker') ballmodel = loader.loadModel('phase_3/models/misc/sphere') ballmodel.reparentTo(testMarker) ballmodel.setScale(0.1) testMarker.setPos(0.0, 0.0, -100.0) self.jointMarkers.append(testMarker) def startSim(self): taskMgr.add(self.__simulationTask, 'simulation task') def stopSim(self): taskMgr.remove('simulation task') def __simulationTask(self, task): self.DTA += globalClock.getDt() numSteps = int(self.DTA / self.DTAStep) if numSteps > 10: self.notify.warning('phyics steps = %d' % numSteps) startTime = globalClock.getRealTime() while self.DTA >= self.DTAStep: if self.deterministic: OdeUtil.randSetSeed(0) self.DTA -= self.DTAStep self.preStep() self.simulate() self.postStep() if self.canRender: self.placeBodies() return task.cont def preStep(self): pass def postStep(self): if self.showContacts and self.canRender: for count in xrange(self.jointMarkerCount): pandaNodePathGeom = self.jointMarkers[count] if count < self.colCount: pandaNodePathGeom.setPos( self.space.getContactData(count * 3 + 0), self.space.getContactData(count * 3 + 1), self.space.getContactData(count * 3 + 2)) else: pandaNodePathGeom.setPos(0.0, 0.0, -100.0) def __handleCollision(self, entry): self.colEntries.append(entry) def simulate(self): self.colEntries = [] self.space.autoCollide() eventMgr.doEvents() self.colCount = len(self.colEntries) if self.maxColCount < self.colCount: self.maxColCount = self.colCount self.notify.debug('New Max Collision Count %s' % self.maxColCount) if self.useQuickStep: self.world.quickStep(self.DTAStep) else: self.world.step(self.DTAStep) for bodyPair in self.bodyList: self.world.applyDampening(self.DTAStep, bodyPair[1]) self.contactgroup.empty() self.timingSimTime = self.timingSimTime + self.DTAStep def placeBodies(self): for pair in self.odePandaRelationList: pandaNodePathGeom = pair[0] odeBody = pair[1] if pandaNodePathGeom: pandaNodePathGeom.setPos(odeBody.getPosition()) pandaNodePathGeom.setQuat( Quat(odeBody.getQuaternion()[0], odeBody.getQuaternion()[1], odeBody.getQuaternion()[2], odeBody.getQuaternion()[3])) def getOrderedContacts(self, entry): c0 = self.space.getCollideId(entry.getGeom1()) c1 = self.space.getCollideId(entry.getGeom2()) if c0 > c1: return c1, c0 else: return c0, c1
class PhysicsSimulator(ShowBase): def __init__(self): ShowBase.__init__(self) self.smiley = loader.loadModel("smiley") self.smiley.set_scale(1) self.cam.set_pos(0, -50, 25) self.setup_ODE() self.add_ground() self.add_static_box(1, 1, 1) self.s1 = self.add_smiley(0, 0, 50) self.s2 = self.add_smiley(0, 0, 40) self.accept("escape", sys.exit) self.accept('a', self.velocity) taskMgr.add(self.update_ODE, "update_ODE") self.accept('on_collision', self.on_collision) def velocity(self): self.s2.set_linear_vel(0, 0, 10) def setup_ODE(self): # Setup our physics world self.world = OdeWorld() self.world.setGravity(0, 0, -9.81) self.world.initSurfaceTable(1) self.world.setSurfaceEntry(0, 0, 200, 0.7, 0.2, 0.9, 0.00001, 0.0, 0.002) self.space = OdeSimpleSpace() self.space.setAutoCollideWorld(self.world) self.contacts = OdeJointGroup() self.space.setAutoCollideJointGroup(self.contacts) self.space.setCollisionEvent("on_collision") def on_collision(self, entry): geom1 = entry.getGeom1() geom2 = entry.getGeom2() body1 = entry.getBody1() body2 = entry.getBody2() def add_ground(self): cm = CardMaker("ground") cm.setFrame(-1, 1, -1, 1) ground = render.attachNewNode(cm.generate()) ground.setColor(0.5, 0.7, 0.8) ground.lookAt(0, 0, -1) groundGeom = OdePlaneGeom(self.space, Vec4(0, 0, 1, 0)) def add_smiley(self, x, y, z): sm = render.attachNewNode("smiley-instance") sm.setPos(x, y, z) self.smiley.instanceTo(sm) body = OdeBody(self.world) 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) return body def add_static_box(self, x, y, z): self.box = OdeBoxGeom(self.space, Vec3(x, y, z)) self.box.set_position(0, 0, 25) def draw_box(self, box): line_collection = LineNodePath(parent=render, thickness=1.0, colorVec=Vec4(1, 0, 0, 1)) pos = box.get_position() lengths = box.get_lengths() x = pos[0] y = pos[1] z = pos[2] half_width = lengths[0] / 2 half_length = lengths[1] / 2 half_height = lengths[2] / 2 lines = [ # Bottom Face ((x - half_width, y - half_length, z - half_height), (x + half_width, y - half_length, z - half_height)), ((x + half_width, y - half_length, z - half_height), (x + half_width, y + half_length, z - half_height)), ((x + half_width, y + half_length, z - half_height), (x - half_width, y + half_length, z - half_height)), ((x - half_width, y + half_length, z - half_height), (x - half_width, y - half_length, z - half_height)), # Top Face ((x - half_width, y - half_length, z + half_height), (x + half_width, y - half_length, z + half_height)), ((x + half_width, y - half_length, z + half_height), (x + half_width, y + half_length, z + half_height)), ((x + half_width, y + half_length, z + half_height), (x - half_width, y + half_length, z + half_height)), ((x - half_width, y + half_length, z + half_height), (x - half_width, y - half_length, z + half_height)), # Vertical Lines ((x - half_width, y - half_length, z - half_height), (x - half_width, y - half_length, z + half_height)), ((x + half_width, y - half_length, z - half_height), (x + half_width, y - half_length, z + half_height)), ((x + half_width, y + half_length, z - half_height), (x + half_width, y + half_length, z + half_height)), ((x - half_width, y + half_length, z - half_height), (x - half_width, y + half_length, z + half_height)), ] line_collection.drawLines(lines) line_collection.create() def update_ODE(self, task): self.space.autoCollide() self.world.quickStep(globalClock.getDt()) self.draw_box(self.box) for smiley in render.findAllMatches("smiley-instance"): body = smiley.getPythonTag("body") smiley.setPosQuat(body.getPosition(), Quat(body.getQuaternion())) self.contacts.empty() return task.cont
class BaseApp(ShowBase): odeBoxes = [] def createOdeEnv(self, model): geomNodeCollection = model.findAllMatches('**/+GeomNode') for nodePath in geomNodeCollection: geomNode = nodePath.node() #print "\n\nGeomNode: ", geomNode.getName() for i in range(geomNode.getNumGeoms()): geom = geomNode.getGeom(i) #state = geomNode.getGeomState(i) T = geomNode.getTransform() #print " - ", T pos = T.getPos() if T.hasComponents(): Q = T.getQuat() S = T.getScale() vdata = geom.getVertexData() vertex = GeomVertexReader(vdata, 'vertex') #mins and maxes for MBB minX = 1e10 maxX = -1e10 minY = 1e10 maxY = -1e10 minZ = 1e10 maxZ = -1e10 while not vertex.isAtEnd(): v = vertex.getData3f() minX = min(minX,v[0]) minY = min(minY,v[1]) minZ = min(minZ,v[2]) maxX = max(maxX,v[0]) maxY = max(maxY,v[1]) maxZ = max(maxZ,v[2]) #print "v = %s" % (repr(v)) #print "X:(%f->%f) Y(%f->%f) Z(%f->%f)" % (minX, maxX, minY, maxY, minZ, maxZ) minX *= S[0] maxX *= S[0] minY *= S[1] maxY *= S[1] minZ *= S[2] maxZ *= S[2] #print "X:(%f->%f) Y(%f->%f) Z(%f->%f)" % (minX, maxX, minY, maxY, minZ, maxZ) box = OdeBoxGeom(self.space, maxX-minX, maxY-minY, maxZ-minZ) box.setPosition(pos) box.setQuaternion(Q) self.odeBoxes.append(box) else: print "Error Transform does not have components - skipping" def load_environment(self, modelfile): self.room = loader.loadModel(modelfile) self.room.reparentTo(render) self.room.setPos(0,0,0) self.createOdeEnv(self.room) def __init__(self): ShowBase.__init__(self) ambLight = AmbientLight("ambient") ambLight.setColor(Vec4(0.1,0.11,0.12,1.0)) ambNode = render.attachNewNode(ambLight) render.setLight(ambNode) dirLight = DirectionalLight("directional") dirLight.setColor(Vec4(0.7,0.7,0.68,1.0)) dirNode = render.attachNewNode(dirLight) dirNode.setHpr(60,-40,90) render.setLight(dirNode) sptLight = Spotlight("spot") sptLens = PerspectiveLens() sptLight.setLens(sptLens) sptLight.setColor(Vec4(0.6,0.6,0.6,1.0)) sptLight.setShadowCaster(True) sptNode = render.attachNewNode(sptLight) sptNode.setPos(0,0,20) sptNode.lookAt(0,0,0) render.setLight(sptNode) render.setShaderAuto() base.camLens.setFov(70) base.camLens.setNear(0.1) base.camLens.setFar(50) self.cam.setPos(-1,-4,4) self.cam.lookAt(0,-1,1) def create_ode_world(self): self.world = OdeWorld() self.world.setGravity(0,0,-9.81) self.world.initSurfaceTable(1) #self.world.setSurfaceEntry(0,0,0.5,0.35,0.1,0.9,0.00001,0.4,0.002) self.world.setSurfaceEntry(0,0,0.8,0.7,0.1,0.9,0.00001,0.4,0.002) self.space = OdeSimpleSpace() self.space.setAutoCollideWorld(self.world) self.contacts = OdeJointGroup() self.space.setAutoCollideJointGroup(self.contacts) self.groundGeom = OdePlaneGeom(self.space, Vec4(0,0,1,0)) def updateODE(self, n_millis): for n in range(0,n_millis): self.space.autoCollide() self.world.quickStep(0.001) self.contacts.empty() return True
class World(object): def __init__(self, game): super(World, self).__init__() self.game = game self.things = [] #initialize the rendering self.renderer = self.game.render self.initFog() #FIXME do better lighting alight = AmbientLight('alight') alight.setColor(VBase4(0.2, 0.2, 0.2, 1)) alnp = self.renderer.attachNewNode(alight) self.renderer.setLight(alnp) #initialize a hud self.hud = HUD() self.add(self.hud) #physics self.world = OdeWorld() self.world.setGravity(0, -20, 0) #FIXME (0,-9.81) would be realistic physics self.world.initSurfaceTable(1) self.world.setSurfaceEntry(0, 0, 0.6, 0.0, 9.1, 0.9, 0.00001, 1.0, 0.02) #FIXME I have no idea what this means self.space = OdeSimpleSpace() self.space.setAutoCollideWorld(self.world) self.contactGroup = OdeJointGroup() self.space.setAutoCollideJointGroup(self.contactGroup) #constrain to 2d self.plane = OdePlane2dJoint(self.world) self.timeAccumulator = 0 self.dt = 1.0 / 60.0 #give it a player self.player = Player(self, Point3(0,10,0)) self.add(self.player) self.game.taskMgr.add(self.player.move, "movePlayer") def initFog(self): f = Fog("World Fog") f.setColor(0.5,0.5,0.5) f.setLinearOnsetPoint(0,0,0) f.setLinearOpaquePoint(0,0,-Thing.REVERTS_VISIBLE * 3)#THING_REVERT_DISTANCE) self.renderer.attachNewNode(f) self.renderer.setFog(f) def add(self, obj): obj.model.reparentTo(self.renderer) if isinstance(obj, Physical): self.things += [obj] self.plane.attach(obj.body, None) def step(self, task): self.timeAccumulator += globalClock.getDt() while(self.timeAccumulator > self.dt): self.timeAccumulator -= self.dt self.space.autoCollide() self.world.quickStep(self.dt) self.contactGroup.empty() for x in self.things: x.constrainQuat() x.model.setPosQuat(self.renderer, x.body.getPosition(), Quat(x.body.getQuaternion())) return task.cont
class Physics(): def __init__(self): #init the world self.world = OdeWorld() self.world.setGravity(0, 0, -9.81) #init the friction self.world.initSurfaceTable(1) surfaceId1 = 0 surfaceId2 = 0 mu = 500 bounce = 0. # 2 bounce_vel = 0.1 soft_erp = 0.9 soft_cfm = 0.00001 slip = 0.0 dampen = 0.002 self.world.setSurfaceEntry( surfaceId1, surfaceId2, mu, bounce, bounce_vel, soft_erp, soft_cfm, slip, dampen) #init the collision space self.space = OdeSimpleSpace() self.space.setAutoCollideWorld(self.world) self.contactgroup = OdeJointGroup() self.space.setAutoCollideJointGroup(self.contactgroup) self.servogroup = OdeJointGroup() #cm = CardMaker("ground") #cm.setFrame(-20, 20, -20, 20) #ground = render.attachNewNode(cm.generate()) #ground.setPos(0, 0, 0); ground.lookAt(0, 0, -1) # Ground definition self.groundGeom = OdePlaneGeom(self.space, Vec4(0, 0, 1, 0)) self.groundGeom.setCollideBits(BitMask32(0x00000001)) self.groundGeom.setCategoryBits(BitMask32(0x00000002)) self.deltaTimeAccumulator = 0.0 self.stepSize = 0.01 # The task for our simulation def simulationTask(self, creatures, dt=0): # Add the deltaTime for the task to the accumulator self.stepSize = dt for c in creatures: c.update_angles(dt) c.draw() #model.setPosQuat(render, body.getPosition(), Quat(body.getQuaternion())) if dt == 0: self.deltaTimeAccumulator += globalClock.getDt() else: self.deltaTimeAccumulator = dt #while self.deltaTimeAccumulator > self.stepSize: # Remove a stepSize from the accumulator until # the accumulated time is less than the stepsize # self.deltaTimeAccumulator -= self.stepSize # Step the simulation self.space.autoCollide() # Setup the contact joints self.world.quickStep(self.stepSize) # set the new positions self.contactgroup.empty() # Clear the contact joints def run_physics(self, t, creatures): """ run physics for t steps """ for i in range(t): self.simulationTask(creatures, 0.01)