コード例 #1
0
def test_sphere_into_heightfield():
    root = NodePath("root")
    world = BulletWorld()
    # Create PNMImage to construct Heightfield with
    img = PNMImage(10, 10, 1)
    img.fill_val(255)
    # Make our nodes
    heightfield = make_node("Heightfield", BulletHeightfieldShape, img, 1, ZUp)
    sphere = make_node("Sphere", BulletSphereShape, 1)
    # Attach to world
    np1 = root.attach_new_node(sphere)
    np1.set_pos(0, 0, 1)
    world.attach(sphere)

    np2 = root.attach_new_node(heightfield)
    np2.set_pos(0, 0, 0)
    world.attach(heightfield)

    assert world.get_num_rigid_bodies() == 2
    test = world.contact_test_pair(sphere, heightfield)
    assert test.get_num_contacts() > 0
    assert test.get_contact(0).get_node0() == sphere
    assert test.get_contact(0).get_node1() == heightfield

    # Increment sphere's Z coordinate, no longer colliding
    np1.set_pos(0, 0, 2)
    test = world.contact_test_pair(sphere, heightfield)
    assert test.get_num_contacts() == 0
コード例 #2
0
def bulletRayHit(pfrom, pto, geom):
    """
    NOTE: this function is quite slow
    find the nearest collision point between vec(pto-pfrom) and the mesh of nodepath

    :param pfrom: starting point of the ray, Point3
    :param pto: ending point of the ray, Point3
    :param geom: meshmodel, a panda3d datatype
    :return: None or Point3

    author: weiwei
    date: 20161201
    """

    bulletworld = BulletWorld()
    facetmesh = BulletTriangleMesh()
    facetmesh.addGeom(geom)
    facetmeshnode = BulletRigidBodyNode('facet')
    bullettmshape = BulletTriangleMeshShape(facetmesh, dynamic=True)
    bullettmshape.setMargin(1e-6)
    facetmeshnode.addShape(bullettmshape)
    bulletworld.attach(facetmeshnode)
    result = bulletworld.rayTestClosest(pfrom, pto)

    if result.hasHit():
        return result.getHitPos()
    else:
        return None
コード例 #3
0
ファイル: element.py プロジェクト: Edwardhk/pgdrive
 def attach_to_physics_world(self, bullet_world: BulletWorld):
     """
     Attach the nodes in this list to bullet world
     :param bullet_world: BulletWorld()
     :return: None
     """
     if self.attached:
         return
     for node in self:
         bullet_world.attach(node)
     self.attached = True
コード例 #4
0
def test_get_steering():
    world = BulletWorld()
    # Chassis
    shape = BulletBoxShape(Vec3(0.6, 1.4, 0.5))
    body = BulletRigidBodyNode('Vehicle')
    body.addShape(shape)
    world.attach(body)
    # Vehicle
    vehicle = BulletVehicle(world, body)
    world.attachVehicle(vehicle)
    # Wheel
    wheel = vehicle.createWheel()
    wheel.setSteering(30.0)
    # Returns the steering angle in degrees.
    assert wheel.getSteering() == approx(30.0)
コード例 #5
0
class TestApplication(ShowBase):

  def __init__(self):

    ShowBase.__init__(self)
    
    # game objects   
    self.controlled_obj_index_ = 0
    self.level_sectors_ = []
    self.controlled_objects_ = []
    
    # active objects
    self.active_sector_ = None

    self.setupRendering()
    self.setupControls()
    self.setupPhysics()
    self.clock_ = ClockObject()
    self.kinematic_mode_ = False
    
    # Task
    logging.info("TestSectors demo started")
    taskMgr.add(self.update, 'updateWorld')


  def setupRendering(self):

    self.setBackgroundColor(0.1, 0.1, 0.8, 1)
    self.setFrameRateMeter(True)

    # Light
    alight = AmbientLight('ambientLight')
    alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
    alightNP = self.render.attachNewNode(alight)

    dlight = DirectionalLight('directionalLight')
    dlight.setDirection(Vec3(1, 1, -1))
    dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
    dlightNP = self.render.attachNewNode(dlight)

    self.render.clearLight()
    self.render.setLight(alightNP)
    self.render.setLight(dlightNP)
    
    self.setupBackgroundImage()
    
  def setupBackgroundImage(self):
    
    
    image_file = Filename(rospack.RosPack().get_path(BACKGROUND_IMAGE_PACKAGE) + '/resources/backgrounds/' + BACKGROUND_IMAGE_PATH)
    
    # check if image can be loaded
    img_head = PNMImageHeader()
    if not img_head.readHeader(image_file ):
        raise IOError, "PNMImageHeader could not read file %s. Try using absolute filepaths"%(image_file.c_str())
        sys.exit()
        
    # Load the image with a PNMImage
    w = img_head.getXSize()
    h = img_head.getYSize()
    img = PNMImage(w,h)
    #img.alphaFill(0)
    img.read(image_file) 
    
    texture = Texture()        
    texture.setXSize(w)
    texture.setYSize(h)
    texture.setZSize(1)    
    texture.load(img)
    texture.setWrapU(Texture.WM_border_color) # gets rid of odd black edges around image
    texture.setWrapV(Texture.WM_border_color)
    texture.setBorderColor(LColor(0,0,0,0))
    
    # creating CardMaker to hold the texture
    cm = CardMaker('background')
    cm.setFrame(-0.5*w,0.5*w,-0.5*h,0.5*h)  # This configuration places the image's topleft corner at the origin (left, right, bottom, top)
    background_np = NodePath(cm.generate())            
    background_np.setTexture(texture)
    
    background_np.reparentTo(self.render)
    background_np.setPos(BACKGROUND_POSITION)
    background_np.setScale(BACKGROUND_IMAGE_SCALE)
  

  def setupControls(self):

    # Input (Events)
    self.accept('escape', self.doExit)
    self.accept('r', self.doReset)
    self.accept('f1', self.toggleWireframe)
    self.accept('f2', self.toggleTexture)
    self.accept('f3', self.toggleDebug)
    self.accept('f5', self.doScreenshot)
    self.accept('n', self.selectNextControlledObject)
    self.accept('k', self.toggleKinematicMode)

    # Inputs (Polling)
    self.input_state_ = InputState()
    self.input_state_.watchWithModifiers("right","arrow_right")
    self.input_state_.watchWithModifiers('left', 'arrow_left')
    self.input_state_.watchWithModifiers('jump', 'arrow_up')
    self.input_state_.watchWithModifiers('stop', 'arrow_down')
    self.input_state_.watchWithModifiers('roll_right', 'c')
    self.input_state_.watchWithModifiers('roll_left', 'z')
    self.input_state_.watchWithModifiers('roll_stop', 'x')


    self.title = addTitle("Panda3D: Kinematic Objects")
    self.inst1 = addInstructions(0.06, "ESC: Quit")
    self.inst2 = addInstructions(0.12, "Up/Down: Jump/Stop")
    self.inst3 = addInstructions(0.18, "Left/Right: Move Left / Move Rigth")
    self.inst4 = addInstructions(0.24, "z/x/c : Rotate Left/ Rotate Stop / Rotate Right")
    self.inst5 = addInstructions(0.30, "n: Select Next Character")
    self.inst6 = addInstructions(0.36, "k: Toggle Kinematic Mode")
    self.inst7 = addInstructions(0.42, "f1: Toggle Wireframe")
    self.inst8 = addInstructions(0.48, "f2: Toggle Texture")
    self.inst9 = addInstructions(0.54, "f3: Toggle BulletDebug")
    self.inst10 = addInstructions(0.60, "f5: Capture Screenshot")
    
  def processCollisions(self):
    
    contact_manifolds = self.physics_world_.getManifolds()
    for cm in contact_manifolds:      
      node0 = cm.getNode0()
      node1 = cm.getNode1()
      col_mask1 = node0.getIntoCollideMask()
      col_mask2 = node1.getIntoCollideMask()
      
      
      if (col_mask1 == col_mask2) and \
        (col_mask1 == SECTOR_ENTERED_BITMASK) and \
        self.active_sector_.getSectorPlaneNode().getName() != node0.getName():
        
        logging.info('Collision between %s and %s'%(node0.getName(),node1.getName()))
        sector = [s for s in self.level_sectors_ if s.getSectorPlaneNode().getName() == node0.getName()]
        sector = [s for s in self.level_sectors_ if s.getSectorPlaneNode().getName() == node1.getName()] + sector
        
        self.switchToSector(sector[0])
        logging.info("Sector %s entered"%(self.active_sector_.getName()))
        
  def switchToSector(self,sector):       
    
    obj_index = self.controlled_obj_index_
    character_obj = self.controlled_objects_[obj_index]
    
    if self.active_sector_ is not None:
      self.active_sector_.releaseCharacter()
    
    character_obj.setY(sector,0)
    character_obj.setH(sector,0)
    self.active_sector_ = sector
    
    self.active_sector_.constrainCharacter(character_obj)
    
    self.active_sector_.enableDetection(False)
    sectors = [s for s in self.level_sectors_ if s != self.active_sector_]
    for s in sectors:
      s.enableDetection(True)

  def setupPhysics(self):

    # setting up physics world and parent node path 
    self.physics_world_ = BulletWorld()
    self.world_node_ = self.render.attachNewNode('world')
    self.cam.reparentTo(self.world_node_)
    self.physics_world_.setGravity(Vec3(0, 0, -9.81))

    self.debug_node_ = self.world_node_.attachNewNode(BulletDebugNode('Debug'))
    self.debug_node_.node().showWireframe(True)
    self.debug_node_.node().showConstraints(True)
    self.debug_node_.node().showBoundingBoxes(True)
    self.debug_node_.node().showNormals(True)
    self.physics_world_.setDebugNode(self.debug_node_.node())
    self.debug_node_.hide()
    
    # setting up collision groups
    self.physics_world_.setGroupCollisionFlag(GAME_OBJECT_BITMASK.getLowestOnBit(),GAME_OBJECT_BITMASK.getLowestOnBit(),True)
    self.physics_world_.setGroupCollisionFlag(SECTOR_ENTERED_BITMASK.getLowestOnBit(),SECTOR_ENTERED_BITMASK.getLowestOnBit(),True)
    self.physics_world_.setGroupCollisionFlag(GAME_OBJECT_BITMASK.getLowestOnBit(),SECTOR_ENTERED_BITMASK.getLowestOnBit(),False)
    

    # setting up ground
    self.ground_ = self.world_node_.attachNewNode(BulletRigidBodyNode('Ground'))
    self.ground_.node().addShape(BulletPlaneShape(Vec3(0, 0, 1), 0))
    self.ground_.setPos(0,0,0)
    self.ground_.setCollideMask(GAME_OBJECT_BITMASK)
    self.physics_world_.attachRigidBody(self.ground_.node())
    
    # creating level objects    
    self.setupLevelSectors()

    # creating controlled objects
    diameter = 0.4
    sphere_visual = loader.loadModel('models/ball.egg')

    bounds = sphere_visual.getTightBounds() # start of model scaling
    extents = Vec3(bounds[1] - bounds[0])
    scale_factor = diameter/max([extents.getX(),extents.getY(),extents.getZ()])
    sphere_visual.clearModelNodes()
    sphere_visual.setScale(scale_factor,scale_factor,scale_factor) # end of model scaling

    sphere_visual.setTexture(loader.loadTexture('models/bowl.jpg'),1)
    sphere = NodePath(BulletRigidBodyNode('Sphere'))
    sphere.node().addShape(BulletSphereShape(0.5*diameter))
    sphere.node().setMass(1.0)
    #sphere.node().setLinearFactor((1,0,1))
    #sphere.node().setAngularFactor((0,1,0))
    sphere.setCollideMask(GAME_OBJECT_BITMASK)
    sphere_visual.instanceTo(sphere)
    
    self.physics_world_.attachRigidBody(sphere.node())
    self.controlled_objects_.append(sphere) 
    sphere.reparentTo(self.world_node_)
    sphere.setPos(self.level_sectors_[0],Vec3(0,0,diameter+10))
    sphere.setHpr(self.level_sectors_[0],Vec3(0,0,0))
    
    # creating bullet ghost for detecting entry into other sectors
    player_ghost = sphere.attachNewNode(BulletGhostNode('player-ghost-node'))
    ghost_box_shape = BulletSphereShape(PLAYER_GHOST_DIAMETER/2)
    ghost_box_shape.setMargin(SECTOR_COLLISION_MARGIN)
    ghost_sphere_shape = BulletSphereShape(PLAYER_GHOST_DIAMETER*0.5)
    ghost_sphere_shape.setMargin(SECTOR_COLLISION_MARGIN)
    player_ghost.node().addShape(ghost_box_shape)
    player_ghost.setPos(sphere,Vec3(0,0,0))
    player_ghost.node().setIntoCollideMask(SECTOR_ENTERED_BITMASK)
    self.physics_world_.attach(player_ghost.node())

    # creating mobile box
    size = Vec3(0.2,0.2,0.4)
    mbox_visual = loader.loadModel('models/box.egg')
    bounds = mbox_visual.getTightBounds()
    extents = Vec3(bounds[1] - bounds[0])
    scale_factor = 1/max([extents.getX(),extents.getY(),extents.getZ()])
    mbox_visual.setScale(size.getX()*scale_factor,size.getY()*scale_factor,size.getZ()*scale_factor)

    mbox = NodePath(BulletRigidBodyNode('MobileBox'))
    mbox.node().addShape(BulletBoxShape(size/2))
    mbox.node().setMass(1.0)
    #mbox.node().setLinearFactor((1,0,1))
    #mbox.node().setAngularFactor((0,1,0))
    mbox.setCollideMask(GAME_OBJECT_BITMASK)
    mbox_visual.instanceTo(mbox)    
    self.physics_world_.attachRigidBody(mbox.node())
    self.controlled_objects_.append(mbox)
    mbox.reparentTo(self.level_sectors_[0])    
    mbox.setPos(Vec3(1,0,size.getZ()+1))
    
    # switching to sector 1
    self.switchToSector(self.level_sectors_[0])


  def setupLevelSectors(self):
    
    start_pos = Vec3(0,-20,0)
    
    for i in range(0,4):
      
      sector = Sector('sector' + str(i),self.physics_world_)
      sector.reparentTo(self.world_node_)
      
      #sector.setHpr(Vec3(60*(i+1),0,0))
      sector.setHpr(Vec3(90*i,0,0))
      sector.setPos(sector,Vec3(0,-20,i*4))
      self.level_sectors_.append(sector)
      sector.setup()      

  def update(self, task):

    self.clock_.tick()
    dt = self.clock_.getDt()
    self.processInput(dt)    
    self.physics_world_.doPhysics(dt, 5, 1.0/180.0)
    self.processCollisions()
    self.updateCamera()

    return task.cont 

  def processInput(self,dt):
  
    activate = False
    obj = self.controlled_objects_[self.controlled_obj_index_]

    if self.kinematic_mode_:
      obj.node().setKinematic(True)
      return
    else:
      obj.node().setKinematic(False)

    vel = self.active_sector_.getRelativeVector(self.world_node_,obj.node().getLinearVelocity())
    w = self.active_sector_.getRelativeVector(self.world_node_, obj.node().getAngularVelocity())
    vel.setY(0)
    #w.setX(0)
    #w.setZ(0)

  
    if self.input_state_.isSet('right'): 
      vel.setX(2)
      activate = True

    if self.input_state_.isSet('left'): 
      vel.setX(-2)
      activate = True

    if self.input_state_.isSet('jump'): 
      vel.setZ(4)
      activate = True

    if self.input_state_.isSet('stop'): 
      vel.setX(0)

    if self.input_state_.isSet('roll_right'):
      w.setY(ROTATIONAl_SPEED)
      activate = True

    if self.input_state_.isSet('roll_left'):
      w.setY(-ROTATIONAl_SPEED)
      activate = True

    if self.input_state_.isSet('roll_stop'):
      w.setY(0)

    if activate : obj.node().setActive(True,True)
    vel = self.world_node_.getRelativeVector(self.active_sector_,vel)
    w = self.world_node_.getRelativeVector(self.active_sector_,w)
    obj.node().setLinearVelocity(vel)
    obj.node().setAngularVelocity(w)
    
    #logging.info("Linear Velocity: %s"%(str(vel)))

  def updateCamera(self):
 
    if len(self.controlled_objects_) > 0:
      obj = self.controlled_objects_[self.controlled_obj_index_]
      self.cam.setPos(self.active_sector_,obj.getPos(self.active_sector_))
      self.cam.setY(self.active_sector_,-CAM_DISTANCE/1)
      self.cam.lookAt(obj.getParent(),obj.getPos())

  def cleanup(self):
    
    for i in range(0,len(self.controlled_objects_)):
      rb = self.controlled_objects_[i]
      self.physics_world_.removeRigidBody(rb.node())
      rb.removeNode()

    self.object_nodes_ = []
    self.controlled_objects_ = []
    self.physics_world_.removeRigidBody(self.ground_.node())
    self.ground_ = None
    self.physics_world_ = None
    self.debug_node_ = None
    self.cam.reparentTo(self.render)
    self.world_node_.removeNode()
    self.world_node_ = None

  # _____HANDLER_____

  def toggleKinematicMode(self):
    self.kinematic_mode_ = not self.kinematic_mode_

    print "Kinematic Mode %s"%('ON' if self.kinematic_mode_ else 'OFF')

  def selectNextControlledObject(self):
    self.controlled_obj_index_+=1
    if self.controlled_obj_index_ >= len(self.controlled_objects_):
      self.controlled_obj_index_ = 0 #  reset


  def doExit(self):
    self.cleanup()
    sys.exit(1)

  def doReset(self):
    self.cleanup()
    self.setupPhysics()

  def toggleDebug(self):

    if self.debug_node_.isHidden():
      self.debug_node_.show()
    else:
      self.debug_node_.hide()

  def doScreenshot(self):
    self.screenshot('Bullet')
コード例 #6
0
class BCMchecker(object):
    """
    BBCMchecker bullet box collision model checker
    """
    def __init__(self, toggledebug=False):
        self.world = BulletWorld()
        self._toggledebug = toggledebug
        if self._toggledebug:
            bulletcolliderrender = base.render.attachNewNode(
                "bulletboxcollider")
            debugNode = BulletDebugNode('Debug')
            debugNode.showWireframe(True)
            debugNode.showConstraints(True)
            debugNode.showBoundingBoxes(False)
            debugNode.showNormals(False)
            self._debugNP = bulletcolliderrender.attachNewNode(debugNode)
            self.world.setDebugNode(self._debugNP.node())

        self.worldrigidbodylist = []
        self._isupdateworldadded = False

    def _updateworld(self, world, task):
        world.doPhysics(globalClock.getDt())
        return task.cont

    def isBoxBoxCollided(self, objcm0, objcm1):
        """
        check if two objects objcm0 as objcm1 are in collision with each other
        the two objects are in the form of collision model
        the AABB boxlist will be used
        type "box" is required

        :param objcm0: the first object
        :param objcm1: the second object
        :return: boolean value showing if the two objects are in collision

        author: weiwei
        date: 20190313
        """

        objcm0boxbullnode = genBulletCDBox(objcm0)
        objcm1boxbullnode = genBulletCDBox(objcm1)
        result = self.world.contactTestPair(objcm0boxbullnode,
                                            objcm1boxbullnode)
        if not result.getNumContacts():
            return False
        else:
            return True

    def isBoxBoxListCollided(self, objcm0, objcmlist=[]):
        """
        check if objcm0 is in collision with a list of collisionmodels in objcmlist
        each obj is in the form of a collision model

        :param objcm0:
        :param obcmjlist: a list of collision models
        :return: boolean value showing if the object and the list are in collision

        author: weiwei
        date: 20190313
        """

        objcm0boxbullnode = genBulletCDBox(objcm0)
        objcm1boxbullnode = genBulletCDBoxList(objcmlist)
        result = self.world.contactTestPair(objcm0boxbullnode,
                                            objcm1boxbullnode)
        if not result.getNumContacts():
            return False
        else:
            return True

    def isBoxListBoxListCollided(self, objcm0list=[], objcm1list=[]):
        """
        check if a list of collisionmodels in objcm0list is in collision with a list of collisionmodels in objcm1list
        each obj is in the form of a collision model

        :param objcm0list: a list of collision models
        :param obcmj1list: a list of collision models
        :return: boolean value showing if the object and the list are in collision

        author: weiwei
        date: 20190313
        """

        objcm0boxbullnode = genBulletCDBoxList(objcm0list)
        objcm1boxbullnode = genBulletCDBoxList(objcm1list)
        result = self.world.contactTestPair(objcm0boxbullnode,
                                            objcm1boxbullnode)
        if not result.getNumContacts():
            return False
        else:
            return True

    def showBox(self, objcm):
        """
        show the AABB collision meshes of the given objects

        :param objcm

        author: weiwei
        date: 20190313
        :return:
        """

        if not self._toggledebug:
            print(
                "Toggle debug on during defining the XCMchecker object to use showfunctions!"
            )
            return

        if not self._isupdateworldadded:
            base.taskMgr.add(self._updateworld,
                             "updateworld",
                             extraArgs=[self.world],
                             appendTask=True)

        objcmboxbullnode = genBulletCDBox(objcm)
        self.world.attach(objcmboxbullnode)
        self.worldrigidbodylist.append(objcmboxbullnode)
        self._debugNP.show()

    def showBoxList(self, objcmlist):
        """
        show the AABB collision meshes of the given objects

        :param objcm0, objcm1

        author: weiwei
        date: 20190313
        :return:
        """

        if not self._toggledebug:
            print(
                "Toggle debug on during defining the XCMchecker object to use showfunctions!"
            )
            return

        if not self._isupdateworldadded:
            base.taskMgr.add(self._updateworld,
                             "updateworld",
                             extraArgs=[self.world],
                             appendTask=True)

        objcmboxbullnode = genBulletCDBoxList(objcmlist)
        self.world.attach(objcmboxbullnode)
        self.worldrigidbodylist.append(objcmboxbullnode)
        self._debugNP.show()

    def unshow(self):
        """
        unshow everything

        author: weiwei
        date: 20180621
        :return:
        """

        base.taskMgr.remove("updateworld")
        print(self.worldrigidbodylist)
        for cdnode in self.worldrigidbodylist:
            self.world.remove(cdnode)
        self.worldrigidbodylist = []
        self._debugNP.hide()
コード例 #7
0
class Game(ShowBase):
    def __init__(self):
        """
        Load some configuration variables, it's important for this to happen
        before the ShowBase is initialized
        """
        load_prc_file_data(
            "", """
            sync-video #t
            ### add entries below if you are not running from an installation.
            #model-path /path/to/panda3d
            """)
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        self.accept('space', self.do_jump)
        self.accept('c', self.do_crouch)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    def do_jump(self):
        self.character.set_max_jump_height(5.0)
        self.character.set_jump_speed(8.0)
        self.character.do_jump()
        self.actorNP.play("jump")

    def do_crouch(self):
        self.crouching = not self.crouching
        sz = self.crouching and 0.6 or 1.0
        self.characterNP.set_scale(LVector3(1, 1, sz))
        #self.character.get_shape().set_local_scale(LVector3(1, 1, sz))
        #self.characterNP.set_scale(LVector3(1, 1, sz) * 0.3048)
        #self.characterNP.set_pos(0, 0, -1 * sz)

    # ____TASK___

    def process_input(self, dt):
        speed = LVector3(0, 0, 0)
        omega = 0.0

        if inputState.isSet('forward'): speed.y = 2.0
        if inputState.isSet('reverse'): speed.y = -2.0
        if inputState.isSet('left'): speed.x = -2.0
        if inputState.isSet('right'): speed.x = 2.0
        if inputState.isSet('turnLeft'): omega = 120.0
        if inputState.isSet('turnRight'): omega = -120.0

        self.character.set_angular_movement(omega)
        self.character.set_linear_movement(speed, True)

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt, 4, 1. / 240.)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        shape = BulletPlaneShape(LVector3(0, 0, 1), 0)

        #img = PNMImage(Filename('models/elevation.png'))
        #shape = BulletHeightfieldShape(img, 1.0, ZUp)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -1)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Box
        shape = BulletBoxShape(LVector3(1.0, 3.0, 0.3))

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box'))
        np.node().set_mass(10.0)
        np.node().add_shape(shape)
        np.set_pos(3, 0, 4)
        np.setH(20.0)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Character
        self.crouching = False

        h = 1.75
        w = 0.4
        shape = BulletCapsuleShape(w, h - 2 * w, ZUp)
        self.character = BulletCharacterControllerNode(shape, 0.4, 'Player')
        self.characterNP = self.worldNP.attach_new_node(self.character)
        self.characterNP.set_pos(-2, 0, 14)
        self.characterNP.set_h(45)
        self.characterNP.set_collide_mask(BitMask32.all_on())
        self.world.attach(self.character)

        self.actorNP = Actor(
            'samples/roaming-ralph/models/ralph.egg.pz', {
                'run': 'samples/roaming-ralph/models/ralph-run.egg.pz',
                'walk': 'samples/roaming-ralph/models/ralph-walk.egg.pz'
            })
        self.actorNP.reparent_to(self.characterNP)
        self.actorNP.set_scale(0.3048)  # 1ft = 0.3048m
        self.actorNP.setH(180)
        self.actorNP.set_pos(0, 0, -1)
コード例 #8
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

        # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

        # ____TASK___

    def process_input(self, dt):
        force = LVector3(0, 0, 0)
        torque = LVector3(0, 0, 0)

        if inputState.isSet('forward'): force.y = 1.0
        if inputState.isSet('reverse'): force.y = -1.0
        if inputState.isSet('left'): force.x = -1.0
        if inputState.isSet('right'): force.x = 1.0
        if inputState.isSet('turnLeft'): torque.z = 1.0
        if inputState.isSet('turnRight'): torque.z = -1.0

        force *= 30.0
        torque *= 10.0

        self.boxNP.node().set_active(True)
        self.boxNP.node().apply_central_force(force)
        self.boxNP.node().apply_torque(torque)

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        shape = BulletPlaneShape(LVector3(0, 0, 1), -1)

        mask = BitMask32(0x0f)
        print('ground: ', mask)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -1)
        np.set_collide_mask(mask)

        self.world.attach(np.node())

        ## Box 1
        #shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        #mask = BitMask32.allOff()
        #print('box-1:  ', mask)

        #np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box-1'))
        #np.node().set_mass(1.0)
        #np.node().add_shape(shape)
        #np.set_pos(-6, 0, 4)
        #np.set_collide_mask(mask)

        #self.world.attach(np.node())

        ## Box 2
        #shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        #mask = BitMask32.bit(0)
        #print('box-2:  ', mask)

        #np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box-2'))
        #np.node().set_mass(1.0)
        #np.node().add_shape(shape)
        #np.set_pos(-2, 0, 4)
        #np.set_collide_mask(mask)

        #self.world.attach(np.node())

        ## Box 3
        #shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        #mask = BitMask32.bit(2)
        #print('box-3:  ', mask)

        #np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box-3'))
        #np.node().set_mass(1.0)
        #np.node().add_shape(shape)
        #np.set_pos(2, 0, 4)
        #np.set_collide_mask(mask)

        #self.world.attach(np.node())

        # Box 4
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        mask = BitMask32(0x3)
        print('box-4:  ', mask)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box-4'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.set_pos(6, 0, 4)
        np.set_collide_mask(mask)

        self.world.attach(np.node())

        self.boxNP = np

        visualNP = loader.load_model('models/box.egg')
        visualNP.reparent_to(self.boxNP)
コード例 #9
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        self.accept('1', self.do_select, [
            0,
        ])
        self.accept('2', self.do_select, [
            1,
        ])
        self.accept('3', self.do_select, [
            2,
        ])
        self.accept('4', self.do_select, [
            3,
        ])
        self.accept('5', self.do_select, [
            4,
        ])
        self.accept('6', self.do_select, [
            5,
        ])

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    def do_select(self, i):
        self.boxNP = self.boxes[i]

        # ____TASK___

    def process_input(self, dt):
        force = LVector3(0, 0, 0)
        torque = LVector3(0, 0, 0)

        if inputState.isSet('forward'): force.y = 1.0
        if inputState.isSet('reverse'): force.y = -1.0
        if inputState.isSet('left'): force.x = -1.0
        if inputState.isSet('right'): force.x = 1.0
        if inputState.isSet('turnLeft'): torque.z = 1.0
        if inputState.isSet('turnRight'): torque.z = -1.0

        force *= 30.0
        torque *= 10.0

        self.boxNP.node().set_active(True)
        self.boxNP.node().apply_central_force(force)
        self.boxNP.node().apply_torque(torque)

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        shape = BulletPlaneShape(LVector3(0, 0, 1), -1)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -1)
        np.set_collide_mask(BitMask32.bit(0))

        self.world.attach(np.node())

        # Boxes
        self.boxes = [
            None,
        ] * 6

        for i in range(6):
            shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

            np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box-1'))
            np.node().set_mass(1.0)
            np.node().add_shape(shape)

            self.world.attach(np.node())

            self.boxes[i] = np

            visualNP = loader.load_model('models/box.egg')
            visualNP.reparent_to(np)

        self.boxes[0].set_pos(-3, -3, 0)
        self.boxes[1].set_pos(0, -3, 0)
        self.boxes[2].set_pos(3, -3, 0)
        self.boxes[3].set_pos(-3, 3, 0)
        self.boxes[4].set_pos(0, 3, 0)
        self.boxes[5].set_pos(3, 3, 0)

        self.boxes[0].set_collide_mask(BitMask32.bit(1))
        self.boxes[1].set_collide_mask(BitMask32.bit(2))
        self.boxes[2].set_collide_mask(BitMask32.bit(3))
        self.boxes[3].set_collide_mask(BitMask32.bit(1))
        self.boxes[4].set_collide_mask(BitMask32.bit(2))
        self.boxes[5].set_collide_mask(BitMask32.bit(3))

        self.boxNP = self.boxes[0]

        self.world.set_group_collision_flag(0, 1, True)
        self.world.set_group_collision_flag(0, 2, True)
        self.world.set_group_collision_flag(0, 3, True)

        self.world.set_group_collision_flag(1, 1, False)
        self.world.set_group_collision_flag(1, 2, True)
コード例 #10
0
class BulletBase(object):
    """ Manages Panda3d Bullet physics resources and convenience methods."""

    # Bitmasks for each object type. By setting ghost and static
    # objects to different masks, we can filter ghost-to-static
    # collisions.
    ghost_bit = BitMask32.bit(1)
    static_bit = BitMask32.bit(2)
    dynamic_bit = ghost_bit | static_bit
    bw_types = (BulletBaseCharacterControllerNode, BulletBodyNode,
                BulletConstraint, BulletVehicle)

    def __init__(self):
        self.world = None
        # Parameters for simulation.
        self.sim_par = {"size": 1. / 100, "n_subs": 10, "size_sub": 1. / 1000}
        # Initialize axis constraint so that there aren't constraints.
        self.axis_constraint_fac = Vec3(1, 1, 1)
        self.axis_constraint_disp = Vec3(nan, nan, nan)
        # Attribute names of destructable objects.
        self._destructables = ()

    def init(self):
        """ Initialize world and resources. """
        # Initialize world.
        self.world = BulletWorld()

    def destroy(self):
        """ Destroy all resources."""
        for key in self._destructables:
            getattr(self, key).destroy()

    def setup_debug(self):
        debug_node = BulletDebugNode('Debug')
        debug_node.showWireframe(True)
        debug_node.showConstraints(True)
        debug_node.showBoundingBoxes(True)
        debug_node.showNormals(True)
        self.world.setDebugNode(debug_node)
        return debug_node

    @property
    def bodies(self):
        """ Return all bodies (rigid, soft, and ghost) in self.world."""
        bodies = (self.world.getRigidBodies() + self.world.getSoftBodies() +
                  self.world.getGhosts())
        return bodies

    def _constrain_axis(self, body):
        """ Apply existing axis constraints to a body."""
        # Set displacements.
        for axis, (f, d) in enumerate(zip(self.axis_constraint_fac,
                                          self.axis_constraint_disp)):
            if not f and not isnan(d):
                nodep = NodePath(body)
                pos = nodep.getPos()
                pos[axis] = d
                nodep.setPos(pos)
        try:
            # Linear and angular factors of 0 mean forces in the
            # corresponding axis are scaled to 0.
            body.setLinearFactor(self.axis_constraint_fac)
            # Angular factors restrict rotation about an axis, so the
            # following logic selects the appropriate axes to
            # constrain.
            s = sum(self.axis_constraint_fac)
            if s == 3.:
                v = self.axis_constraint_fac
            elif s == 2.:
                v = -self.axis_constraint_fac + 1
            else:
                v = Vec3.zero()
            body.setAngularFactor(v)
        except AttributeError:
            # The body was not a rigid body (it didn't have
            # setLinearFactor method).
            pass

    def set_axis_constraint(self, axis, on, disp=None):
        """ Sets an axis constraint, so that bodies can/cannot
        move in that direction."""
        # Create the constraint vector.
        self.axis_constraint_fac[axis] = int(not on)
        self.axis_constraint_disp[axis] = disp if disp is not None else nan
        # Iterate over bodies, applying the constraint.
        for body in self.bodies:
            self._constrain_axis(body)

    def attach(self, objs, suppress_deact_warn=False):
        """ Attach Bullet objects to the world."""
        if not self.world:
            raise BulletBaseError("No BulletWorld initialized.")
        # Make sure they're iterable.
        if not isinstance(objs, Iterable):
            objs = [objs]
        elif isinstance(objs, dict):
            objs = objs.itervalues()
        bw_objs = []
        for obj in objs:
            if isinstance(obj, NodePath):
                obj = obj.node()
            if isinstance(obj, self.bw_types):
                bw_objs.append(obj)
        # Don't attach ones that are already attached.
        bw_objs = set(bw_objs) - set(self.bodies)
        # Attach them.
        for obj in bw_objs:
            # Warn about deactivation being enabled.
            if (not suppress_deact_warn and
                getattr(obj, "isDeactivationEnabled", lambda: True)()):
                msg = "Deactivation is enabled on object: %s" % obj
                warn(msg, DeactivationEnabledWarning)
            # Apply existing axis constraints to the objects.
            self._constrain_axis(obj)
            # Attach the objects to the world.
            try:
                self.world.attach(obj)
            except AttributeError:
                DeprecationWarning("Upgrade to Panda3d 1.9.")
                for attr in ("attachRigidBody", "attachConstraint",
                             "attachGhost"):
                    attach = getattr(self.world, attr)
                    try:
                        attach(obj)
                    except TypeError:
                        pass
                    else:
                        break

    def remove(self, objs):
        """ Remove Bullet objects to the world."""
        if not self.world:
            raise BulletBaseError("No BulletWorld initialized.")
        # Make sure they're iterable.
        if not isinstance(objs, Iterable):
            objs = [objs]
        elif isinstance(objs, dict):
            objs = objs.itervalues()
        bw_objs = []
        for obj in objs:
            if isinstance(obj, NodePath):
                obj = obj.node()
            if isinstance(obj, self.bw_types):
                bw_objs.append(obj)
        # Remove them.
        for obj in bw_objs:
            # Remove the objects from the world.
            try:
                self.world.remove(obj)
            except AttributeError:
                DeprecationWarning("Upgrade to Panda3d 1.9.")
                for attr in ("removeRigidBody", "removeConstraint",
                             "removeGhost"):
                    remove = getattr(self.world, attr)
                    try:
                        remove(obj)
                    except TypeError:
                        pass
                    else:
                        break

    def remove_all(self):
        """ Remove all objects from world."""
        objs = (self.world.getCharacters() + self.world.getConstraints() +
                self.world.getGhosts() + self.world.getRigidBodies() +
                self.world.getSoftBodies() + self.world.getVehicles())
        self.remove(objs)

    @property
    def gravity(self):
        """ Get gravity on self.world. """
        return self.world.getGravity()

    @gravity.setter
    def gravity(self, gravity):
        """ Set gravity on self.world. """
        self.world.setGravity(Vec3(*gravity))

    def step(self, *args, **kwargs):
        """ Wrapper for BulletWorld.doPhysics."""
        # Defaults.
        dt = args[0] if len(args) > 0 else self.sim_par["size"]
        n_subs = args[1] if len(args) > 1 else self.sim_par["n_subs"]
        size_sub = args[2] if len(args) > 2 else self.sim_par["size_sub"]
        force = kwargs.get("force", None)
        if force:
            bodies, vecpos, dur = force
            dt0 = np.clip(dur, 0., dt)
            n_subs0 = int(np.ceil(n_subs * dt0 / dt))
            dt1 = dt - dt0
            n_subs1 = n_subs - n_subs0 + 1
            for body in bodies:
                body.applyForce(Vec3(*vecpos[0]), Point3(*vecpos[1]))
            # With force.
            self.world.doPhysics(dt0, n_subs0, size_sub)
            for body in bodies:
                body.clearForces()
        else:
            dt1 = dt
            n_subs1 = n_subs
        # With no force.
        self.world.doPhysics(dt1, n_subs1, size_sub)

    @staticmethod
    def attenuate_velocities(bodies, linvelfac=0., angvelfac=0.):
        """ Zeros out the bodies' linear and angular velocities."""
        # Iterate through bodies, re-scaling their velocity vectors
        for body in bodies:
            linvel0 = body.getLinearVelocity()
            angvel0 = body.getAngularVelocity()
            # .normalize() returns True if the length is > 0
            if linvel0.normalize():
                linvel = linvel0 * linvelfac
                body.setLinearVelocity(linvel)
            if angvel0.normalize():
                angvel = angvel0 * angvelfac
                body.setAngularVelocity(angvel)

    def repel(self, n_steps=1000, thresh=10, step_size=0.01):
        """ Performs n_steps physical "repel" steps. """

        @contextmanager
        def repel_context(world):
            """ Sets up a repel context. Gets the bodies, turns off
            gravity, rescales the masses, sets up the collision
            notification callback. """

            def change_contact_thresh(bodies, thresh=0.001):
                """ Adjust the contact processing threshold. This is
                used to make the objects not trigger collisions when
                just barely touching."""
                if isinstance(thresh, Iterable):
                    it = izip(bodies, thresh)
                else:
                    it = ((body, thresh) for body in bodies)
                thresh0 = []
                for body, th in it:
                    thresh0.append(body.getContactProcessingThreshold())
                    body.setContactProcessingThreshold(th)
                return thresh0

            def rescale_masses(bodies):
                """ Rescale the masses so they are proportional to the
                volume."""
                masses, inertias = zip(*[(body.getMass(), body.getInertia())
                                         for body in bodies])
                volumefac = 1.
                for body, mass, inertia in zip(bodies, masses, inertias):
                    # Compute the mass-normalized diagonal elements of the
                    # inertia tensor.
                    if mass > 0.:
                        it = inertia / mass * 12
                        # Calculate volume from the mass-normalized
                        # inertia tensor (from wikipedia).
                        h = sqrt((it[0] - it[1] + it[2]) / 2)
                        w = sqrt(it[2] - h ** 2)
                        d = sqrt(it[1] - w ** 2)
                        volume = h * w * d
                        # Change the mass.
                        body.setMass(volume * volumefac)
                return masses

            # Get the bodies.
            bodies = world.getRigidBodies()
            # Turn gravity off.
            gravity = world.getGravity()
            world.setGravity(Vec3.zero())
            # Tighten the contact processing threshold slightly.
            delta = -0.001
            cp_thresh = change_contact_thresh(bodies, thresh=delta)
            # Adjust masses.
            masses = rescale_masses(bodies)
            # Adjust sleep thresholds.
            deactivations = [b.isDeactivationEnabled() for b in bodies]
            for body in bodies:
                body.setDeactivationEnabled(False)
            # Zero out velocities.
            self.attenuate_velocities(bodies)
            # Collisions monitor.
            collisions = CollisionMonitor(world)
            collisions.push_notifiers(bodies)
            ## Finish __enter__.
            yield bodies, collisions
            ## Start __exit__.
            collisions.pop_notifiers()
            # Zero out velocities.
            self.attenuate_velocities(bodies)
            # Restore the contact processing threshold.
            change_contact_thresh(bodies, thresh=cp_thresh)
            # Set masses back.
            for body, mass in zip(bodies, masses):
                body.setMass(mass)
                # Turn gravity back on.
                world.setGravity(gravity)
            for body, d in zip(bodies, deactivations):
                body.setDeactivationEnabled(d)

        # Operate in a context that changes the masses, turns off
        # gravity, adds collision monitoring callback, etc.
        with repel_context(self.world) as (bodies, collisions):
            # Loop through the repel simulation.
            done_count = 0
            for istep in xrange(n_steps):
                # Take one step.
                self.world.doPhysics(step_size, 1, step_size)
                # HACK: The following can be removed once Panda3d 1.9
                # is installed (and the method can be removed from
                # CollisionMonitor).
                collisions.detect18()
                # Increment done_count, only if there are no contacts.
                if collisions:
                    done_count = 0
                else:
                    done_count += 1
                if any(body.getMass() > 0. and not body.isActive()
                       for body in bodies):
                    BP()
                # Stop criterion.
                if done_count >= thresh:
                    break
                # Zero-out/re-scale velocities.
                linvelfac = bool(collisions) * 0.001
                angvelfac = bool(collisions) * 0.001
                self.attenuate_velocities(bodies, linvelfac, angvelfac)
                # Reset collisions.
                collisions.reset()
        return istep

    @classmethod
    def add_collide_mask(cls, func0):
        """ Decorator. Initializes ghost, static, and dynamic nodes
        with the appropriate collide masks."""
        def func(*args, **kwargs):
            # Create node using func0.
            node = func0(*args, **kwargs)
            # Determine collide mask.
            if isinstance(node, BulletGhostNode):
                bit = cls.ghost_bit
            elif node.getMass() == 0.:
                bit = cls.static_bit
            else:
                bit = cls.dynamic_bit
            # Set collide mask.
            node.setCollideMask(bit)
            return node
        return update_wrapper(func0, func)

    @staticmethod
    def add_ghostnode(node):
        """ Adds a child ghostnode to a node as a workaround for the
        ghost-static node collision detection problem."""
        name = "%s-ghost" % node.getName()
        ghost = NodePath(BulletGhostNode(name))
        ghost.reparentTo(node)
        return ghost
コード例 #11
0
ファイル: physics.py プロジェクト: vmichals/home-platform
class Panda3dBulletPhysics(World):

    # NOTE: the model ids of objects that correspond to opened doors. They will be ignored for collisions.
    openedDoorModelIds = [
        '122',
        '133',
        '214',
        '246',
        '247',
        '361',
        '73',
        '756',
        '757',
        '758',
        '759',
        '760',
        '761',
        '762',
        '763',
        '764',
        '765',
        '768',
        '769',
        '770',
        '771',
        '778',
        '779',
        '780',
        's__1762',
        's__1763',
        's__1764',
        's__1765',
        's__1766',
        's__1767',
        's__1768',
        's__1769',
        's__1770',
        's__1771',
        's__1772',
        's__1773',
    ]

    # FIXME: is not a complete list of movable objects
    movableObjectCategories = [
        'table', 'dressing_table', 'sofa', 'trash_can', 'chair', 'ottoman',
        'bed'
    ]

    # For more material, see table: http://www.ambrsoft.com/CalcPhysics/Density/Table_2.htm
    defaultDensity = 1000.0  # kg/m^3

    # For more coefficients, see table: https://www.thoughtspike.com/friction-coefficients-for-bullet-physics/
    defaultMaterialFriction = 0.7

    defaultMaterialRestitution = 0.5

    def __init__(self,
                 scene,
                 suncgDatasetRoot=None,
                 debug=False,
                 objectMode='box',
                 agentRadius=0.1,
                 agentHeight=1.6,
                 agentMass=60.0,
                 agentMode='capsule'):

        super(Panda3dBulletPhysics, self).__init__()

        self.__dict__.update(scene=scene,
                             suncgDatasetRoot=suncgDatasetRoot,
                             debug=debug,
                             objectMode=objectMode,
                             agentRadius=agentRadius,
                             agentHeight=agentHeight,
                             agentMass=agentMass,
                             agentMode=agentMode)

        if suncgDatasetRoot is not None:
            self.modelCatMapping = ModelCategoryMapping(
                os.path.join(suncgDatasetRoot, "metadata",
                             "ModelCategoryMapping.csv"))
        else:
            self.modelCatMapping = None

        self.bulletWorld = BulletWorld()
        self.bulletWorld.setGravity(Vec3(0, 0, -9.81))

        if debug:
            debugNode = BulletDebugNode('physic-debug')
            debugNode.showWireframe(True)
            debugNode.showConstraints(False)
            debugNode.showBoundingBoxes(True)
            debugNode.showNormals(False)
            self.debugNodePath = self.scene.scene.attachNewNode(debugNode)
            self.debugNodePath.show()
            self.bulletWorld.setDebugNode(debugNode)
        else:
            self.debugNodePath = None

        self._initLayoutModels()
        self._initAgents()
        self._initObjects()

        self.scene.worlds['physics'] = self

    def destroy(self):
        # Nothing to do
        pass

    def _initLayoutModels(self):

        # Load layout objects as meshes
        for model in self.scene.scene.findAllMatches(
                '**/layouts/object*/model*'):

            shape, transform = getCollisionShapeFromModel(
                model, mode='mesh', defaultCentered=False)

            node = BulletRigidBodyNode('physics')
            node.setMass(0.0)
            node.setFriction(self.defaultMaterialFriction)
            node.setRestitution(self.defaultMaterialRestitution)
            node.setStatic(True)
            node.addShape(shape)
            node.setDeactivationEnabled(True)
            node.setIntoCollideMask(BitMask32.allOn())
            self.bulletWorld.attach(node)

            # Attach the physic-related node to the scene graph
            physicsNp = model.getParent().attachNewNode(node)
            physicsNp.setTransform(transform)

            if node.isStatic():
                model.getParent().setTag('physics-mode', 'static')
            else:
                model.getParent().setTag('physics-mode', 'dynamic')

            # Reparent render and acoustics nodes (if any) below the new physic node
            #XXX: should be less error prone to just reparent all children (except the hidden model)
            renderNp = model.getParent().find('**/render')
            if not renderNp.isEmpty():
                renderNp.reparentTo(physicsNp)
            acousticsNp = model.getParent().find('**/acoustics')
            if not acousticsNp.isEmpty():
                acousticsNp.reparentTo(physicsNp)

            # NOTE: we need this to update the transform state of the internal bullet node
            physicsNp.node().setTransformDirty()

            # Validation
            assert np.allclose(
                mat4ToNumpyArray(physicsNp.getNetTransform().getMat()),
                mat4ToNumpyArray(model.getNetTransform().getMat()),
                atol=1e-6)

    def _initAgents(self):

        # Load agents
        for agent in self.scene.scene.findAllMatches('**/agents/agent*'):

            transform = TransformState.makeIdentity()
            if self.agentMode == 'capsule':
                shape = BulletCapsuleShape(
                    self.agentRadius, self.agentHeight - 2 * self.agentRadius)
            elif self.agentMode == 'sphere':
                shape = BulletCapsuleShape(self.agentRadius,
                                           2 * self.agentRadius)

            # XXX: use BulletCharacterControllerNode class, which already handles local transform?
            node = BulletRigidBodyNode('physics')
            node.setMass(self.agentMass)
            node.setStatic(False)
            node.setFriction(self.defaultMaterialFriction)
            node.setRestitution(self.defaultMaterialRestitution)
            node.addShape(shape)
            self.bulletWorld.attach(node)

            # Constrain the agent to have fixed position on the Z-axis
            node.setLinearFactor(Vec3(1.0, 1.0, 0.0))

            # Constrain the agent not to be affected by rotations
            node.setAngularFactor(Vec3(0.0, 0.0, 0.0))

            node.setIntoCollideMask(BitMask32.allOn())
            node.setDeactivationEnabled(True)

            # Enable continuous collision detection (CCD)
            node.setCcdMotionThreshold(1e-7)
            node.setCcdSweptSphereRadius(0.50)

            if node.isStatic():
                agent.setTag('physics-mode', 'static')
            else:
                agent.setTag('physics-mode', 'dynamic')

            # Attach the physic-related node to the scene graph
            physicsNp = NodePath(node)
            physicsNp.setTransform(transform)

            # Reparent all child nodes below the new physic node
            for child in agent.getChildren():
                child.reparentTo(physicsNp)
            physicsNp.reparentTo(agent)

            # NOTE: we need this to update the transform state of the internal bullet node
            physicsNp.node().setTransformDirty()

            # Validation
            assert np.allclose(
                mat4ToNumpyArray(physicsNp.getNetTransform().getMat()),
                mat4ToNumpyArray(agent.getNetTransform().getMat()),
                atol=1e-6)

    def _initObjects(self):

        # Load objects
        for model in self.scene.scene.findAllMatches(
                '**/objects/object*/model*'):
            modelId = model.getParent().getTag('model-id')

            # XXX: we could create BulletGhostNode instance for non-collidable objects, but we would need to filter out the collisions later on
            if not modelId in self.openedDoorModelIds:

                shape, transform = getCollisionShapeFromModel(
                    model, self.objectMode, defaultCentered=True)

                node = BulletRigidBodyNode('physics')
                node.addShape(shape)
                node.setFriction(self.defaultMaterialFriction)
                node.setRestitution(self.defaultMaterialRestitution)
                node.setIntoCollideMask(BitMask32.allOn())
                node.setDeactivationEnabled(True)

                if self.suncgDatasetRoot is not None:

                    # Check if it is a movable object
                    category = self.modelCatMapping.getCoarseGrainedCategoryForModelId(
                        modelId)
                    if category in self.movableObjectCategories:
                        # Estimate mass of object based on volumetric data and default material density
                        objVoxFilename = os.path.join(self.suncgDatasetRoot,
                                                      'object_vox',
                                                      'object_vox_data',
                                                      modelId,
                                                      modelId + '.binvox')
                        voxelData = ObjectVoxelData.fromFile(objVoxFilename)
                        mass = Panda3dBulletPhysics.defaultDensity * voxelData.getFilledVolume(
                        )
                        node.setMass(mass)
                    else:
                        node.setMass(0.0)
                        node.setStatic(True)
                else:
                    node.setMass(0.0)
                    node.setStatic(True)

                if node.isStatic():
                    model.getParent().setTag('physics-mode', 'static')
                else:
                    model.getParent().setTag('physics-mode', 'dynamic')

                # Attach the physic-related node to the scene graph
                physicsNp = model.getParent().attachNewNode(node)
                physicsNp.setTransform(transform)

                # Reparent render and acoustics nodes (if any) below the new physic node
                #XXX: should be less error prone to just reparent all children (except the hidden model)
                renderNp = model.getParent().find('**/render')
                if not renderNp.isEmpty():
                    renderNp.reparentTo(physicsNp)
                acousticsNp = model.getParent().find('**/acoustics')
                if not acousticsNp.isEmpty():
                    acousticsNp.reparentTo(physicsNp)

                # NOTE: we need this to update the transform state of the internal bullet node
                node.setTransformDirty()

                # NOTE: we need to add the node to the bullet engine only after setting all attributes
                self.bulletWorld.attach(node)

                # Validation
                assert np.allclose(
                    mat4ToNumpyArray(physicsNp.getNetTransform().getMat()),
                    mat4ToNumpyArray(
                        model.getParent().getNetTransform().getMat()),
                    atol=1e-6)

            else:
                logger.debug('Object %s ignored from physics' % (modelId))

    def step(self, dt):
        self.bulletWorld.doPhysics(dt)

    def isCollision(self, root):
        isCollisionDetected = False
        if isinstance(root.node(), BulletRigidBodyNode):
            result = self.bulletWorld.contactTest(root.node())
            if result.getNumContacts() > 0:
                isCollisionDetected = True
        else:
            for nodePath in root.findAllMatches('**/+BulletBodyNode'):
                isCollisionDetected |= self.isCollision(nodePath)
        return isCollisionDetected

    def getCollisionInfo(self, root, dt):

        result = self.bulletWorld.contactTest(root.node())

        force = 0.0
        relativePosition = LVecBase3f(0.0, 0.0, 0.0)
        isCollisionDetected = False
        for _ in result.getContacts():

            # Iterate over all manifolds of the world
            # NOTE: it seems like the contact manifold doesn't hold the information
            #       to calculate contact force. We need the persistent manifolds for that.
            for manifold in self.bulletWorld.getManifolds():

                # Check if the root node is part of that manifold, by checking positions
                # TODO: there is surely a better way to compare the two nodes here
                #if (manifold.getNode0().getTransform().getPos() == root.getNetTransform().getPos()):
                if manifold.getNode0().getTag('model-id') == root.getTag(
                        'model-id'):

                    # Calculate the to
                    totalImpulse = 0.0
                    maxImpulse = 0.0
                    for pt in manifold.getManifoldPoints():
                        impulse = pt.getAppliedImpulse()
                        totalImpulse += impulse

                        if impulse > maxImpulse:
                            maxImpulse = impulse
                            relativePosition = pt.getLocalPointA()

                    force = totalImpulse / dt
                    isCollisionDetected = True

        return force, relativePosition, isCollisionDetected

    def calculate2dNavigationMap(self, agent, z=0.1, precision=0.1, yup=True):

        agentRbNp = agent.find('**/+BulletRigidBodyNode')

        # Calculate the bounding box of the scene
        bounds = []
        for nodePath in self.scene.scene.findAllMatches(
                '**/object*/+BulletRigidBodyNode'):
            node = nodePath.node()

            #NOTE: the bounding sphere doesn't seem to take into account the transform, so apply it manually (translation only)
            bsphere = node.getShapeBounds()
            center = nodePath.getNetTransform().getPos()
            bounds.extend(
                [center + bsphere.getMin(), center + bsphere.getMax()])

        minBounds, maxBounds = np.min(bounds, axis=0), np.max(bounds, axis=0)

        # Using the X and Y dimensions of the bounding box, discretize the 2D plan into a uniform grid with given precision
        X = np.arange(minBounds[0], maxBounds[0], step=precision)
        Y = np.arange(minBounds[1], maxBounds[1], step=precision)
        nbTotalCells = len(X) * len(Y)
        threshold10Perc = int(nbTotalCells / 10)

        # XXX: the simulation needs to be run a little before moving the agent, not sure why
        self.bulletWorld.doPhysics(0.1)

        # Sweep the position of the agent across the grid, checking if collision/contacts occurs with objects or walls in the scene.
        occupancyMap = np.zeros((len(X), len(Y)))
        occupancyMapCoord = np.zeros((len(X), len(Y), 2))
        n = 0
        for i, x in enumerate(X):
            for j, y in enumerate(Y):
                agentRbNp.setPos(LVecBase3f(x, y, z))

                if self.isCollision(agentRbNp):
                    occupancyMap[i, j] = 1.0

                occupancyMapCoord[i, j, 0] = x
                occupancyMapCoord[i, j, 1] = y

                n += 1
                if n % threshold10Perc == 0:
                    logger.debug('Collision test no.%d (out of %d total)' %
                                 (n, nbTotalCells))

        if yup:
            # Convert to image format (y,x)
            occupancyMap = np.flipud(occupancyMap.T)
            occupancyMapCoord = np.flipud(
                np.transpose(occupancyMapCoord, axes=(1, 0, 2)))

        return occupancyMap, occupancyMapCoord
コード例 #12
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -10, 5)
        base.cam.look_at(0, 0, 0.2)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        inputState.watchWithModifiers('up', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('down', 's')
        inputState.watchWithModifiers('right', 'd')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def process_input(self, dt):
        force = LVector3(0, 0, 0)

        if inputState.isSet('up'): force.y = 1.0
        if inputState.isSet('down'): force.y = -1.0
        if inputState.isSet('left'): force.x = -1.0
        if inputState.isSet('right'): force.x = 1.0

        force *= 300.0

        self.bowlNP.node().set_active(True)
        self.bowlNP.node().apply_central_force(force)

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()
        self.debugNP.node().show_wireframe(True)
        self.debugNP.node().show_constraints(True)
        self.debugNP.node().show_bounding_boxes(False)
        self.debugNP.node().show_normals(False)

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        shape = BulletPlaneShape(LVector3(0, 0, 1), 0)

        body = BulletRigidBodyNode('Ground')
        bodyNP = self.worldNP.attach_new_node(body)
        bodyNP.node().add_shape(shape)
        bodyNP.set_pos(0, 0, 0)
        bodyNP.set_collide_mask(BitMask32.all_on())
        self.world.attach(bodyNP.node())

        # Bowl
        visNP = loader.load_model('models/bowl.egg')

        geom = (visNP.findAllMatches('**/+GeomNode').get_path(
            0).node().get_geom(0))
        mesh = BulletTriangleMesh()
        mesh.addGeom(geom)
        shape = BulletTriangleMeshShape(mesh, dynamic=True)

        body = BulletRigidBodyNode('Bowl')
        bodyNP = self.worldNP.attach_new_node(body)
        bodyNP.node().add_shape(shape)
        bodyNP.node().set_mass(10.0)
        bodyNP.set_pos(0, 0, 0)
        bodyNP.set_collide_mask(BitMask32.all_on())
        self.world.attach(bodyNP.node())

        visNP.reparent_to(bodyNP)

        self.bowlNP = bodyNP
        self.bowlNP.set_scale(2)

        # Eggs
        self.eggNPs = []
        for i in range(5):
            x = random.gauss(0, 0.1)
            y = random.gauss(0, 0.1)
            z = random.gauss(0, 0.1) + 1
            h = random.random() * 360
            p = random.random() * 360
            r = random.random() * 360

            visNP = loader.load_model('models/egg.egg')

            geom = (visNP.find_all_matches('**/+GeomNode').get_path(
                0).node().get_geom(0))
            shape = BulletConvexHullShape()
            shape.addGeom(geom)

            body = BulletRigidBodyNode('Egg-%i' % i)
            bodyNP = self.worldNP.attach_new_node(body)
            bodyNP.node().set_mass(1.0)
            bodyNP.node().add_shape(shape)
            bodyNP.node().set_deactivation_enabled(False)
            bodyNP.set_collide_mask(BitMask32.all_on())
            bodyNP.set_pos_hpr(x, y, z, h, p, r)
            #bodyNP.set_scale(1.5)
            self.world.attach(bodyNP.node())

            visNP.reparent_to(bodyNP)

            self.eggNPs.append(bodyNP)
コード例 #13
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -80, 40)
        base.cam.look_at(0, 0, 10)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(0, 0, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def update(self, task):
        dt = globalClock.get_dt()
        self.world.do_physics(dt, 10, 0.008)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    @staticmethod
    def LVector3_rand():
        x = 2 * random.random() - 1
        y = 2 * random.random() - 1
        z = 2 * random.random() - 1
        return LVector3(x, y, z)

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        p0 = LPoint3(-20, -20, 0)
        p1 = LPoint3(-20, 20, 0)
        p2 = LPoint3(20, -20, 0)
        p3 = LPoint3(20, 20, 0)
        mesh = BulletTriangleMesh()
        mesh.add_triangle(p0, p1, p2)
        mesh.add_triangle(p1, p2, p3)
        shape = BulletTriangleMeshShape(mesh, dynamic=False)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Mesh'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -2)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Soft body world information
        info = self.world.get_world_info()
        info.set_air_density(1.2)
        info.set_water_density(0)
        info.set_water_offset(0)
        info.set_water_normal(LVector3(0, 0, 0))

        # Softbody
        for i in range(50):
            p00 = LPoint3(-2, -2, 0)
            p10 = LPoint3(2, -2, 0)
            p01 = LPoint3(-2, 2, 0)
            p11 = LPoint3(2, 2, 0)
            node = BulletSoftBodyNode.make_patch(info, p00, p10, p01, p11, 6,
                                                 6, 0, True)
            node.generate_bending_constraints(2)
            node.get_cfg().set_lift_coefficient(0.004)
            node.get_cfg().set_dynamic_friction_coefficient(0.0003)
            node.get_cfg().set_aero_model(
                BulletSoftBodyConfig.AM_vertex_two_sided)
            node.set_total_mass(0.1)
            node.add_force(LVector3(0, 2, 0), 0)

            np = self.worldNP.attach_new_node(node)
            np.set_pos(self.LVector3_rand() * 10 + LVector3(0, 0, 20))
            np.set_hpr(self.LVector3_rand() * 16)
            self.world.attach(node)

            fmt = GeomVertexFormat.get_v3n3t2()
            geom = BulletHelper.make_geom_from_faces(node, fmt, True)
            node.link_geom(geom)
            nodeV = GeomNode('')
            nodeV.add_geom(geom)
            npV = np.attach_new_node(nodeV)

            tex = loader.load_texture('models/panda.jpg')
            npV.set_texture(tex)
            BulletHelper.make_texcoords_for_patch(geom, 6, 6)
コード例 #14
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 5)
        base.cam.look_at(0, 0, 5)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        self.accept('enter', self.do_shoot)

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    def do_shoot(self):
        # Get from/to points from mouse click
        pMouse = base.mouseWatcherNode.get_mouse()
        pFrom = LPoint3()
        pTo = LPoint3()
        base.camLens.extrude(pMouse, pFrom, pTo)

        pFrom = render.get_relative_point(base.cam, pFrom)
        pTo = render.get_relative_point(base.cam, pTo)

        # Calculate initial velocity
        v = pTo - pFrom
        v.normalize()
        v *= 100.0

        # Create bullet
        shape = BulletSphereShape(0.3)
        body = BulletRigidBodyNode('Bullet')
        bodyNP = self.worldNP.attach_new_node(body)
        bodyNP.node().add_shape(shape)
        bodyNP.node().set_mass(1.0)
        bodyNP.node().set_linear_velocity(v)
        bodyNP.node().set_ccd_motion_threshold(1e-7)
        bodyNP.node().set_ccd_swept_sphere_radius(0.50)
        bodyNP.set_collide_mask(BitMask32.all_on())
        bodyNP.set_pos(pFrom)

        visNP = loader.load_model('models/ball.egg')
        visNP.set_scale(0.8)
        visNP.reparent_to(bodyNP)

        self.world.attach(bodyNP.node())

        # Remove the bullet again after 2 seconds
        taskMgr.do_method_later(2,
                                self.do_remove,
                                'doRemove',
                                extraArgs=[bodyNP],
                                appendTask=True)

    def do_remove(self, bodyNP, task):
        self.world.remove(bodyNP.node())
        bodyNP.remove_node()
        return task.done

    # ____TASK___

    def update(self, task):
        dt = globalClock.get_dt()
        self.world.do_physics(dt, 20, 1.0 / 180.0)
        return task.cont

    def cleanup(self):
        self.worldNP.remove_node()
        self.worldNP = None
        self.world = None

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()
        self.debugNP.node().show_wireframe(True)
        self.debugNP.node().show_constraints(True)
        self.debugNP.node().show_bounding_boxes(False)
        self.debugNP.node().show_normals(False)

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Box A
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        bodyA = BulletRigidBodyNode('Box A')
        bodyNP = self.worldNP.attach_new_node(bodyA)
        bodyNP.node().add_shape(shape)
        bodyNP.set_collide_mask(BitMask32.all_on())
        bodyNP.set_pos(-4, 0, 4)

        visNP = loader.load_model('models/box.egg')
        visNP.clear_model_nodes()
        visNP.reparent_to(bodyNP)

        self.world.attach(bodyA)

        # Box B
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        bodyB = BulletRigidBodyNode('Box B')
        bodyNP = self.worldNP.attach_new_node(bodyB)
        bodyNP.node().add_shape(shape)
        bodyNP.node().set_mass(1.0)
        bodyNP.node().set_deactivation_enabled(False)
        bodyNP.set_collide_mask(BitMask32.all_on())
        bodyNP.set_pos(1, 0, 0)

        visNP = loader.load_model('models/box.egg')
        visNP.clear_model_nodes()
        visNP.reparent_to(bodyNP)

        self.world.attach(bodyB)

        # Generic
        frameA = TransformState.make_pos_hpr(LPoint3(4, 0, 0),
                                             LVector3(0, 0, 0))
        frameB = TransformState.make_pos_hpr(LPoint3(2, 0, 0),
                                             LVector3(0, 0, 0))

        generic = BulletGenericConstraint(bodyA, bodyB, frameA, frameB, True)
        generic.set_debug_draw_size(2.0)
        generic.set_linear_limit(0, 0, 0)
        generic.set_linear_limit(1, 0, 3)
        generic.set_linear_limit(2, 0, 1)
        generic.set_angular_limit(0, -60, 60)
        generic.set_angular_limit(1, -30, 30)
        generic.set_angular_limit(2, -120, 120)

        self.world.attach(generic)
コード例 #15
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -60, 20)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def update(self, task):
        dt = globalClock.get_dt()
        self.world.do_physics(dt, 10, 0.008)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        #self.debugNP.show_tight_bounds()
        #self.debugNP.show_bounds()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        p0 = LPoint3(-20, -20, 0)
        p1 = LPoint3(-20, 20, 0)
        p2 = LPoint3(20, -20, 0)
        p3 = LPoint3(20, 20, 0)
        mesh = BulletTriangleMesh()
        mesh.add_triangle(p0, p1, p2)
        mesh.add_triangle(p1, p2, p3)
        shape = BulletTriangleMeshShape(mesh, dynamic=False)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Mesh'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -2)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Stair
        origin = LPoint3(0, 0, 0)
        size = LVector3(2, 10, 1)
        shape = BulletBoxShape(size * 0.5)
        for i in range(10):
            pos = origin + size * i
            pos.setY(0)

            np = self.worldNP.attach_new_node(
                BulletRigidBodyNode('Stair{}'.format(i)))
            np.node().add_shape(shape)
            np.set_pos(pos)
            np.set_collide_mask(BitMask32.all_on())

            npV = loader.load_model('models/box.egg')
            npV.reparent_to(np)
            npV.set_scale(size)

            self.world.attach(np.node())

        # Soft body world information
        info = self.world.get_world_info()
        info.set_air_density(1.2)
        info.set_water_density(0)
        info.set_water_offset(0)
        info.set_water_normal(LVector3(0, 0, 0))

        # Softbody
        center = LPoint3(0, 0, 0)
        radius = LVector3(1, 1, 1) * 1.5
        node = BulletSoftBodyNode.make_ellipsoid(info, center, radius, 128)
        node.set_name('Ellipsoid')
        node.get_material(0).set_linear_stiffness(0.1)
        node.get_cfg().set_dynamic_friction_coefficient(1)
        node.get_cfg().set_damping_coefficient(0.001)
        node.get_cfg().set_pressure_coefficient(1500)
        node.set_total_mass(30, True)
        node.set_pose(True, False)

        np = self.worldNP.attach_new_node(node)
        np.set_pos(15, 0, 12)
        #np.setH(90.0)
        #np.show_bounds()
        #np.show_tight_bounds()
        self.world.attach(np.node())

        geom = BulletHelper.make_geom_from_faces(node)
        node.link_geom(geom)
        nodeV = GeomNode('EllipsoidVisual')
        nodeV.add_geom(geom)
        npV = np.attach_new_node(nodeV)
コード例 #16
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def process_input(self, dt):
        force = LVector3(0, 0, 0)
        torque = LVector3(0, 0, 0)

        if inputState.isSet('forward'): force.y = 1.0
        if inputState.isSet('reverse'): force.y = -1.0
        if inputState.isSet('left'): force.x = -1.0
        if inputState.isSet('right'): force.x = 1.0
        if inputState.isSet('turnLeft'): torque.z = 1.0
        if inputState.isSet('turnRight'): torque.z = -1.0

        force *= 30.0
        torque *= 10.0

        self.boxNP.node().set_active(True)
        self.boxNP.node().apply_central_force(force)
        self.boxNP.node().apply_torque(torque)

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())
        self.world.set_filter_callback(PythonCallbackObject(self.filter))

        # Ground
        shape = BulletPlaneShape(LVector3(0, 0, 1), -1)
        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -1)
        np.set_python_tag('foo', 2)
        self.world.attach(np.node())

        # Box 1
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))
        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box-1'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.set_pos(3, 0, 4)
        np.set_python_tag('foo', 0)
        self.world.attach(np.node())
        self.boxNP = np

        # Box 2
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))
        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box-2'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.set_pos(-3, 0, 4)
        np.set_python_tag('foo', -1)
        self.world.attach(np.node())

    def filter(self, cb_data):
        """
        cb_data is of type BulletFilterCallbackData.
        A rather silly collision filtering algorithm. We assume every node
        has the Python tag 'foo' set, and that the value of this tag is integer.
        Then we add the values and if the result is greater than zero we want
        the nodes to collide.
        """
        x1 = cb_data.get_node_0().get_python_tag('foo')
        x2 = cb_data.get_node_1().get_python_tag('foo')
        cb_data.set_collide(x1 + x2 > 0)
コード例 #17
0
ファイル: rigidbodybullet.py プロジェクト: wanweiwei07/wrs
# node.addShape(shape)

# np = base.render.attachNewNode(node)
# np.setPos(0, 0, 0)

model = cm.CollisionModel("./objects/bunnysim.meshes")
# model.reparentTo(base.render)
# model.setMat(Mat4.rotateMat(10, Vec3(1,0,0)))
# model.setPos(0,0,300)

bulletnode = bch.genBulletCDMesh(model)
bulletnode.setMass(1)
rigidbody = base.render.attachNewNode(bulletnode)
model.reparentTo(rigidbody)

world = BulletWorld()
world.setGravity(Vec3(0, 0, -9.8))
world.attach(bulletnode)

def update(task):
    dt = globalClock.getDt()
    world.doPhysics(dt)
    # vecw= topbullnode.getAngularVelocity()
    # arrownp = pg.plotArrow(base.render, epos = vecw*1000, thickness = 15)
    # print rotmat
    # model.setMat(base.pg.np4ToMat4(rm.homobuild(rbd.pos, rbd.rotmat)))

    return task.cont

taskMgr.add(update, 'update')
base.run()
コード例 #18
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

        # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

        # ____TASK___

    def process_input(self, dt):
        if not self.box:
            return

        force = LVector3(0, 0, 0)
        torque = LVector3(0, 0, 0)

        if inputState.isSet('forward'): force.y = 1.0
        if inputState.isSet('reverse'): force.y = -1.0
        if inputState.isSet('left'): force.x = -1.0
        if inputState.isSet('right'): force.x = 1.0
        if inputState.isSet('turnLeft'): torque.z = 1.0
        if inputState.isSet('turnRight'): torque.z = -1.0

        force *= 30.0
        torque *= 10.0

        self.box.set_active(True)
        self.box.apply_central_force(force)
        self.box.apply_torque(torque)

    def process_contacts(self):
        if not self.box or not self.sphere:
            return

        result = self.world.contact_test_pair(self.box, self.sphere)
        #result = self.world.contact_test(self.box)

        #print '-->', result.get_num_contacts()
        for contact in result.get_contacts():
            cp = contact.get_manifold_point()
            node0 = contact.get_node0()
            node1 = contact.get_node1()
            print(node0.get_name(), node1.get_name(), cp.get_local_point_a())

            #print(contact.get_node0(), cp.get_position_world_on_a())
            #print(contact.get_idx0(), contact.get_idx1(), \
            #      contact.get_part_id0(), contact.get_part_id1())

            self.remove_node(node1)

    def remove_node(self, node):
        self.world.remove(node)
        if node == self.sphere: self.sphere = None
        if node == self.box: self.box = None
        np = NodePath(node)
        np.remove_node()

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt, 10, 0.008)
        self.process_contacts()
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    #def on_contact_added(self, node1, node2):
    #    print('contact added:', node1, node2)

    #def on_contact_destroyed(self, node1, node2):
    #    print('contact destroyed:', node1, node2)

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Plane
        shape = BulletPlaneShape(LVector3(0, 0, 1), 0)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -1)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Box
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.node().set_deactivation_enabled(False)
        np.set_pos(2, 0, 4)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        visualNP = loader.load_model('models/box.egg')
        visualNP.reparent_to(np)

        self.box = np.node()

        # Sphere
        shape = BulletSphereShape(0.6)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Sphere'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.set_pos(-2, 0, 4)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        self.sphere = np.node()
コード例 #19
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -40, 10)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(5, 0, -2))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def update(self, task):
        dt = globalClock.get_dt()
        self.world.do_physics(dt, 10, 0.008)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        p0 = LPoint3(-20, -20, 0)
        p1 = LPoint3(-20, 20, 0)
        p2 = LPoint3(20, -20, 0)
        p3 = LPoint3(20, 20, 0)
        mesh = BulletTriangleMesh()
        mesh.add_triangle(p0, p1, p2)
        mesh.add_triangle(p1, p2, p3)
        shape = BulletTriangleMeshShape(mesh, dynamic=False)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Mesh'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -4)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Soft body world information
        info = self.world.get_world_info()
        info.set_air_density(1.2)
        info.set_water_density(0)
        info.set_water_offset(0)
        info.set_water_normal(LVector3(0, 0, 0))

        ## Softbody - From points/indices
        #import cube
        #points = [LPoint3(x,y,z) * 3 for x,y,z in cube.nodes]
        #indices = sum([list(x) for x in cube.elements], [])

        #node = BulletSoftBodyNode.make_tet_mesh(info, points, indices, True)
        #node.set_volume_mass(300);
        #node.get_shape(0).set_margin(0.01)
        #node.get_material(0).set_linear_stiffness(0.8)
        #node.get_cfg().set_positions_solver_iterations(1)
        #node.get_cfg().clear_all_collision_flags()
        #node.get_cfg().set_collision_flag(
        #BulletSoftBodyConfig.CF_cluster_soft_soft, True)
        #node.get_cfg().set_collision_flag(
        #BulletSoftBodyConfig.CF_cluster_rigid_soft, True)
        #node.generate_clusters(16)

        #softNP = self.worldNP.attach_new_node(node)
        #softNP.set_pos(0, 0, 8)
        #softNP.set_hpr(0, 0, 45)
        #self.world.attach(node)

        # Softbody - From tetgen data
        ele = open('models/cube/cube.1.ele', 'r').read()
        face = open('models/cube/cube.1.face', 'r').read()
        node = open('models/cube/cube.1.node', 'r').read()

        node = BulletSoftBodyNode.make_tet_mesh(info, ele, face, node)
        node.set_name('Tetra')
        node.set_volume_mass(300)
        node.get_shape(0).set_margin(0.01)
        node.get_material(0).set_linear_stiffness(0.1)
        node.get_cfg().set_positions_solver_iterations(1)
        node.get_cfg().clear_all_collision_flags()
        node.get_cfg().set_collision_flag(
            BulletSoftBodyConfig.CF_cluster_soft_soft, True)
        node.get_cfg().setCollisionFlag(
            BulletSoftBodyConfig.CF_cluster_rigid_soft, True)
        node.generate_clusters(6)

        softNP = self.worldNP.attach_new_node(node)
        softNP.set_pos(0, 0, 8)
        softNP.set_hpr(45, 0, 0)
        self.world.attach(node)

        # Option 1:
        visNP = loader.load_model('models/cube/cube.egg')
        visNP.reparent_to(softNP)
        geom = (visNP.findAllMatches('**/+GeomNode').getPath(
            0).node().modifyGeom(0))
        node.link_geom(geom)
コード例 #20
0
class Game(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

        # ____TASK___

    def process_input(self, dt):
        force = LVector3(0, 0, 0)
        torque = LVector3(0, 0, 0)

        if inputState.isSet('forward'): force.y = 1.0
        if inputState.isSet('reverse'): force.y = -1.0
        if inputState.isSet('left'): force.x = -1.0
        if inputState.isSet('right'): force.x = 1.0
        if inputState.isSet('turnLeft'): torque.z = 1.0
        if inputState.isSet('turnRight'): torque.z = -1.0

        force *= 30.0
        torque *= 10.0

        self.boxNP.node().set_active(True)
        self.boxNP.node().apply_central_force(force)
        self.boxNP.node().apply_torque(torque)

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt)
        self.raycast()
        return task.cont

    def raycast(self):
        pFrom = LPoint3(-4, 0, 0.5)
        pTo = LPoint3(4, 0, 0.5)
        #pTo = pFrom + LVector3(1, 0, 0) * 99999

        # Raycast for closest hit
        result = self.world.ray_test_closest(pFrom, pTo)
        print(result.has_hit(), \
        result.get_hit_fraction(), \
        result.get_node(), \
        result.get_hit_pos(), \
        result.get_hit_normal())

        # Raycast for all hits
        #result = self.world.ray_test_all(pFrom, pTo)
        #print result.has_hits(), \
        #      result.get_closest_hit_fraction(), \
        #      result.get_num_hits()
        #print [hit.get_hit_pos() for hit in result.get_hits()]

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        shape = BulletPlaneShape(LVector3(0, 0, 1), 0)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, 0)
        np.set_collide_mask(BitMask32(0x0f))

        self.world.attach(np.node())

        # Box
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Box'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.set_pos(0, 0, 4)
        np.set_collide_mask(BitMask32(0x0f))

        self.world.attach(np.node())

        self.boxNP = np
        visualNP = loader.load_model('models/box.egg')
        visualNP.reparent_to(self.boxNP)

        # Sphere
        shape = BulletSphereShape(0.6)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Sphere'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.set_pos(3, 0, 4)
        np.set_collide_mask(BitMask32(0x0f))

        self.world.attach(np.node())

        # Cone
        shape = BulletConeShape(0.6, 1.0)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Cone'))
        np.node().set_mass(1.0)
        np.node().add_shape(shape)
        np.set_pos(6, 0, 4)
        np.set_collide_mask(BitMask32(0x0f))

        self.world.attach(np.node())
コード例 #21
0
class Game(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('turnLeft', 'a')
        inputState.watchWithModifiers('turnRight', 'd')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def process_input(self, dt):
        engineForce = 0.0
        brakeForce = 0.0

        if inputState.isSet('forward'):
            engineForce = 1000.0
            brakeForce = 0.0

        if inputState.isSet('reverse'):
            engineForce = 0.0
            brakeForce = 100.0

        if inputState.isSet('turnLeft'):
            self.steering += dt * self.steeringIncrement
            self.steering = min(self.steering, self.steeringClamp)

        if inputState.isSet('turnRight'):
            self.steering -= dt * self.steeringIncrement
            self.steering = max(self.steering, -self.steeringClamp)

        # Apply steering to front wheels
        self.vehicle.setSteeringValue(self.steering, 0);
        self.vehicle.setSteeringValue(self.steering, 1);

        # Apply engine and brake to rear wheels
        self.vehicle.applyEngineForce(engineForce, 2);
        self.vehicle.applyEngineForce(engineForce, 3);
        self.vehicle.setBrake(brakeForce, 2);
        self.vehicle.setBrake(brakeForce, 3);

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        self.world.do_physics(dt, 10, 0.008)
        #print self.vehicle.getWheel(0).getRaycastInfo().isInContact()
        #print self.vehicle.getWheel(0).getRaycastInfo().getContactPointWs()
        #print self.vehicle.getChassis().isKinematic()
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Plane
        shape = BulletPlaneShape(LVector3(0, 0, 1), 0)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Ground'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -1)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Chassis
        shape = BulletBoxShape(LVector3(0.6, 1.4, 0.5))
        ts = TransformState.make_pos(LPoint3(0, 0, 0.5))

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Vehicle'))
        np.node().add_shape(shape, ts)
        np.set_pos(0, 0, 1)
        np.node().set_mass(800.0)
        np.node().set_deactivation_enabled(False)

        self.world.attach(np.node())

        #np.node().set_ccd_swept_sphere_radius(1.0)
        #np.node().set_ccd_motion_threshold(1e-7) 

        # Vehicle
        self.vehicle = BulletVehicle(self.world, np.node())
        self.vehicle.set_coordinate_system(ZUp)
        self.world.attach(self.vehicle)

        self.yugoNP = loader.load_model('models/yugo/yugo.egg')
        self.yugoNP.reparent_to(np)

        # Right front wheel
        np = loader.load_model('models/yugo/yugotireR.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3( 0.70,  1.05, 0.3), True, np)

        # Left front wheel
        np = loader.load_model('models/yugo/yugotireL.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3(-0.70,  1.05, 0.3), True, np)

        # Right rear wheel
        np = loader.load_model('models/yugo/yugotireR.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3( 0.70, -1.05, 0.3), False, np)

        # Left rear wheel
        np = loader.load_model('models/yugo/yugotireL.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3(-0.70, -1.05, 0.3), False, np)

        # Steering info
        self.steering = 0.0            # degree
        self.steeringClamp = 45.0      # degree
        self.steeringIncrement = 120.0 # degree per second

    def add_wheel(self, pos, front, np):
        wheel = self.vehicle.create_wheel()

        wheel.set_node(np.node())
        wheel.set_chassis_connection_point_cs(pos)
        wheel.set_front_wheel(front)

        wheel.set_wheel_direction_cs(LVector3(0, 0, -1))
        wheel.set_wheel_axle_cs(LVector3(1, 0, 0))
        wheel.set_wheel_radius(0.25)
        wheel.set_max_suspension_travel_cm(40.0)

        wheel.set_suspension_stiffness(40.0)
        wheel.set_wheels_damping_relaxation(2.3)
        wheel.set_wheels_damping_compression(4.4)
        wheel.set_friction_slip(100.0);
        wheel.set_roll_influence(0.1)
コード例 #22
0
class Game(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos_hpr(0, 0, 25, 0, -90, 0)
        base.disable_mouse()

        # Input
        self.accept('escape', self.exitGame)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        # Setup scene 1: World
        self.debugNP = render.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.node().show_wireframe(True)
        self.debugNP.node().show_constraints(True)
        self.debugNP.node().show_bounding_boxes(True)
        self.debugNP.node().show_normals(True)
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Setup scene 2: Ball
        #visNP = loader.load_model('models/ball.egg')
        visNP = loader.load_model('samples/ball-in-maze/models/ball.egg.pz')
        visNP.clear_model_nodes()

        bodyNPs = BulletHelper.from_collision_solids(visNP, True)
        self.ballNP = bodyNPs[0]
        self.ballNP.reparent_to(render)
        self.ballNP.node().set_mass(1.0)
        self.ballNP.set_pos(4, -4, 1)
        self.ballNP.node().set_deactivation_enabled(False)

        visNP.reparent_to(self.ballNP)

        # Setup scene 3: Maze
        visNP = loader.load_model('models/maze.egg')
        #visNP = loader.load_model('samples/ball-in-maze/models/maze.egg.pz')
        visNP.clear_model_nodes()
        visNP.reparent_to(render)

        self.holes = []
        self.maze = []
        self.mazeNP = visNP

        bodyNPs = BulletHelper.from_collision_solids(visNP, True);
        for bodyNP in bodyNPs:
            bodyNP.reparent_to(render)

            if isinstance(bodyNP.node(), BulletRigidBodyNode):
                bodyNP.node().set_mass(0.0)
                bodyNP.node().set_kinematic(True)
                self.maze.append(bodyNP)

            elif isinstance(bodyNP.node(), BulletGhostNode):
                self.holes.append(bodyNP)

        # Lighting and material for the ball
        ambientLight = AmbientLight('ambientLight')
        ambientLight.set_color(LVector4(0.55, 0.55, 0.55, 1))
        directionalLight = DirectionalLight('directionalLight')
        directionalLight.set_direction(LVector3(0, 0, -1))
        directionalLight.set_color(LVector4(0.375, 0.375, 0.375, 1))
        directionalLight.set_specular_color(LVector4(1, 1, 1, 1))
        self.ballNP.set_light(render.attach_new_node(ambientLight))
        self.ballNP.set_light(render.attach_new_node(directionalLight))

        m = Material()
        m.set_specular(LVector4(1,1,1,1))
        m.set_shininess(96)
        self.ballNP.set_material(m, 1)

        # Startup
        self.start_game()

    def exitGame(self):
        sys.exit()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    def start_game(self):
        self.ballNP.set_pos(4, -4, 1)
        self.ballNP.node().set_linear_velocity(LVector3(0, 0, 0))
        self.ballNP.node().set_angular_velocity(LVector3(0, 0, 0))

        # Mouse
        p = base.win.get_properties()
        base.win.move_pointer(0, int(p.get_x_size()/2), int(p.get_y_size()/2))

        # Add bodies and ghosts
        self.world.attach(self.ballNP.node())
        for bodyNP in self.maze:
            self.world.attach(bodyNP.node())
        for ghostNP in self.holes:
            self.world.attach(ghostNP.node())

        # Simulation task
        taskMgr.add(self.update_game, 'updateGame')

    def stop_game(self):

        # Remove bodies and ghosts
        self.world.remove(self.ballNP.node())
        for bodyNP in self.maze:
            self.world.remove(bodyNP.node())
        for ghostNP in self.holes:
            self.world.remove(ghostNP.node())

        # Simulation task
        taskMgr.remove('updateGame')

    def update_game(self, task):
        dt = globalClock.get_dt()

        # Get mouse position and tilt maze
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.get_mouse()
            hpr = LVector3(0, mpos.y * -10, mpos.x * 10)

            # Maze visual node
            self.mazeNP.set_hpr(hpr)

            # Maze body nodes
            for bodyNP in self.maze:
                bodyNP.set_hpr(hpr)

        # Update simulation
        self.world.do_physics(dt)

        # Check if ball is touching a hole
        for holeNP in self.holes:
            if holeNP.node().get_num_overlapping_nodes() > 2:
                if self.ballNP.node() in holeNP.node().get_overlapping_nodes():
                    self.lose_game(holeNP)

        return task.cont

    def lose_game(self, holeNP):
        toPos = holeNP.node().get_shape_pos(0)
        self.stop_game()

        Sequence(
            Parallel(
                LerpFunc(self.ballNP.set_x, fromData = self.ballNP.get_x(),
                         toData = toPos.get_x(), duration = .1),
                LerpFunc(self.ballNP.set_y, fromData = self.ballNP.get_y(),
                         toData = toPos.get_y(), duration = .1),
                LerpFunc(self.ballNP.set_z, fromData = self.ballNP.get_z(),
                         toData = self.ballNP.get_z() - .9, duration = .2)),
                Wait(1),
                Func(self.start_game)).start()
コード例 #23
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -20, 4)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('turnLeft', 'q')
        inputState.watchWithModifiers('turnRight', 'e')

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def process_input(self, dt):
        force = LVector3(0, 0, 0)
        torque = LVector3(0, 0, 0)

        if inputState.isSet('forward'): force.y = 1.0
        if inputState.isSet('reverse'): force.y = -1.0
        if inputState.isSet('left'): force.x = -1.0
        if inputState.isSet('right'): force.x = 1.0
        if inputState.isSet('turnLeft'): torque.z = 1.0
        if inputState.isSet('turnRight'): torque.z = -1.0

        force *= 30.0
        torque *= 10.0

        force = render.get_relative_vector(self.boxNP, force)
        torque = render.get_relative_vector(self.boxNP, torque)

        self.boxNP.node().set_active(True)
        self.boxNP.node().apply_central_force(force)
        self.boxNP.node().apply_torque(torque)

    def update(self, task):
        dt = globalClock.get_dt()
        self.process_input(dt)
        #self.world.doPhysics(dt)
        self.world.do_physics(dt, 5, 1.0 / 180.0)
        return task.cont

    def cleanup(self):
        self.world.remove(self.groundNP.node())
        self.world.remove(self.boxNP.node())
        self.world = None
        self.debugNP = None
        self.groundNP = None
        self.boxNP = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()
        self.debugNP.node().show_wireframe(True)
        self.debugNP.node().show_constraints(True)
        self.debugNP.node().show_bounding_boxes(False)
        self.debugNP.node().show_normals(True)

        #self.debugNP.show_tight_bounds()
        #self.debugNP.show_bounds()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground (static)
        shape = BulletPlaneShape(LVector3(0, 0, 1), 1)

        self.groundNP = self.worldNP.attach_new_node(
            BulletRigidBodyNode('Ground'))
        self.groundNP.node().add_shape(shape)
        self.groundNP.set_pos(0, 0, -2)
        self.groundNP.set_collide_mask(BitMask32.all_on())

        self.world.attach(self.groundNP.node())

        # Box (dynamic)
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        self.boxNP = self.worldNP.attach_new_node(BulletRigidBodyNode('Box'))
        self.boxNP.node().set_mass(1.0)
        self.boxNP.node().add_shape(shape)
        self.boxNP.set_pos(0, 0, 2)
        #self.boxNP.set_scale(2, 1, 0.5)
        self.boxNP.set_collide_mask(BitMask32.all_on())
        #self.boxNP.node().set_deactivation_enabled(False)

        self.world.attach(self.boxNP.node())

        visualNP = loader.load_model('models/box.egg')
        visualNP.clear_model_nodes()
        visualNP.reparent_to(self.boxNP)
コード例 #24
0
class HeightfieldVehicle(ShowBase):

    def __init__(self, heightfield_fn="heightfield.png"):
        # Store the heightfield's filename.
        self.heightfield_fn = heightfield_fn
        
        """
        Load some configuration variables, it's important for this to happen
        before ShowBase is initialized
        """
        load_prc_file_data("", """
            sync-video #t
            textures-power-2 none
            ###gl-coordinate-system default
            notify-level-gobj warning
            notify-level-grutil debug
            notify-level-shader_terrain debug
            notify-level-bullet debug
            ### model paths
            model-path /usr/share/panda3d
            model-path /home/juzzuj/code/prereq/bullet-samples/bullet-samples
            """)            
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)
        
        # Increase camera Field Of View and set near and far planes
        base.camLens.set_fov(90)
        base.camLens.set_near_far(0.1, 50000)

        # Lights
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Basic game controls
        self.accept('escape', self.do_exit)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)
        self.accept('r', self.do_reset)
        
        # Vehicle controls
        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('turnLeft', 'a')
        inputState.watchWithModifiers('reverse', 's')
        inputState.watchWithModifiers('turnRight', 'd')
        inputState.watchWithModifiers('forward', 'arrow_up')
        inputState.watchWithModifiers('turnLeft', 'arrow_left')
        inputState.watchWithModifiers('reverse', 'arrow_down')
        inputState.watchWithModifiers('turnRight', 'arrow_right')
        
        self.accept('space', self.reset_vehicle)
        
        # Controls to do with the terrain
        #self.accept('t', self.rise_in_front)
        self.accept('t', self.deform_terrain, ["raise"])
        self.accept('g', self.deform_terrain, ["depress"])
        self.accept('b', self.drop_boxes)
        
        # Some debugging and miscellaneous controls
        self.accept('e', self.query_elevation)
        self.accept('c', self.convert_coordinates)
        self.accept('p', self.save)
        self.accept('h', self.hide_terrain)
        
        # Task
        taskMgr.add(self.update, 'updateWorld')

        self.setup()

    """
    Macro-like function used to reduce the amount to code needed to create the
    on screen instructions
    """
    def genLabelText(self, i, text, parent="a2dTopLeft"):
        return OnscreenText(text=text, parent=getattr(base, parent), scale=.05,
                            pos=(0.06, -.065 * i), fg=(1, 1, 1, 1),
                            align=TextNode.ALeft)

    # _____HANDLER_____

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()
        self.terrain.remove_node()
        self.skybox.remove_node()
        del self.terrain_node

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
          self.debugNP.show()
        else:
          self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('HeightfieldVehicle')

    # ____TASK___

    def update(self, task):
        # Get the time passed since the last frame
        dt = globalClock.get_dt()
        # Pass dt as parameter (we need it for sensible steering calculations)
        self.process_input(dt)
        
        """
        Basically, we want to put our camera where the camera floater is. We
        need the floater's world (=render-relative) position (it's parented to
        the vehicle)
        """
        floater_pos = render.get_relative_point(self.camera_floater,
                                                LVector3(0))
        """
        If the camera floater is under the terrain surface, adjust it, so that
        it stays above the terrain.
        """         
        elevation_at_floater_pos = self.query_elevation(floater_pos)
        if elevation_at_floater_pos.z >= floater_pos.z:
            floater_pos.z = elevation_at_floater_pos.z + 1.
        # Now we set our camera's position and make it look at the vehicle.
        base.cam.set_pos(floater_pos)
        base.cam.look_at(self.vehicleNP)
        
        # Let the Bullet library do physics calculations.
        self.world.do_physics(dt, 10, 0.008)
        return task.cont

    def process_input(self, dt):
        # Relax steering towards straight
        self.steering *= 1 - self.steering_relax_factor * dt
        
        engine_force = 0.0
        brake_force = 0.0

        if inputState.isSet('forward'):
            engine_force = 1000.0
            brake_force = 0.0

        if inputState.isSet('reverse'):
            engine_force = 0.0
            brake_force = 100.0

        if inputState.isSet('turnLeft'):
            self.steering += dt * self.steering_increment
            self.steering = min(self.steering, self.steering_clamp)

        if inputState.isSet('turnRight'):
            self.steering -= dt * self.steering_increment
            self.steering = max(self.steering, -self.steering_clamp)

        # Lower steering intensity for high speeds
        self.steering *= 1. - (self.vehicle.get_current_speed_km_hour() * 
                               self.steering_speed_reduction_factor)

        # Apply steering to front wheels
        #self.vehicle.get_wheels()[0].set_steering(self.steering)
        #self.vehicle.get_wheels()[1].set_steering(self.steering)        
        #self.vehicle.wheels[0].steering = self.steering
        #self.vehicle.wheels[1].steering = self.steering
        self.vehicle.set_steering_value(self.steering, 0)
        self.vehicle.set_steering_value(self.steering, 1)

        # Apply engine and brake to rear wheels
        #self.vehicle.wheels[2].engine_force = engine_force
        #self.vehicle.wheels[3].engine_force = engine_force
        #self.vehicle.wheels[2].brake = brake_force
        #self.vehicle.wheels[3].brake = brake_force
        self.vehicle.apply_engine_force(engine_force, 2)
        self.vehicle.apply_engine_force(engine_force, 3)
        self.vehicle.set_brake(brake_force, 2)
        self.vehicle.set_brake(brake_force, 3)

    def setup(self):        
        # Bullet physics world
        self.worldNP = render.attach_new_node('World')
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Vehicle
        # Steering info
        self.steering = 0.0              # degrees
        self.steering_clamp = 45.0       # degrees
        self.steering_increment = 120.0  # degrees per second        
        # How fast steering relaxes to straight ahead
        self.steering_relax_factor = 2.0
        # How much steering intensity decreases with higher speeds
        self.steering_speed_reduction_factor = 0.003
        
        # Chassis collision box (note: Bullet uses half-measures)
        shape = BulletBoxShape(LVector3(0.6, 1.4, 0.5))
        ts = TransformState.make_pos(LPoint3(0, 0, 0.5))
        self.vehicleNP = self.worldNP.attach_new_node(
            BulletRigidBodyNode('Vehicle'))
        self.vehicleNP.node().add_shape(shape, ts)
        # Set initial position
        self.vehicleNP.set_pos(0, 70, -10)
        self.vehicleNP.node().set_mass(800.0)
        self.vehicleNP.node().set_deactivation_enabled(False)
        self.world.attach(self.vehicleNP.node())
        # Camera floater
        self.attach_camera_floater()
        # BulletVehicle
        self.vehicle = BulletVehicle(self.world, self.vehicleNP.node())
        self.world.attach(self.vehicle)
        
        # Vehicle model
        self.yugoNP = loader.load_model('models/yugo/yugo.egg')
        self.yugoNP.reparent_to(self.vehicleNP)
        # Right front wheel
        np = loader.load_model('models/yugo/yugotireR.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3( 0.70,  1.05, 0.3), True, np)
        # Left front wheel
        np = loader.load_model('models/yugo/yugotireL.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3(-0.70,  1.05, 0.3), True, np)
        # Right rear wheel
        np = loader.load_model('models/yugo/yugotireR.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3( 0.70, -1.05, 0.3), False, np)
        # Left rear wheel
        np = loader.load_model('models/yugo/yugotireL.egg')
        np.reparent_to(self.worldNP)
        self.add_wheel(LPoint3(-0.70, -1.05, 0.3), False, np)
        
        # Load a skybox
        self.skybox = self.loader.load_model(
            "samples/shader-terrain/models/skybox.bam")
        self.skybox.reparent_to(self.render)
        self.skybox.set_scale(20000)
        skybox_texture = self.loader.load_texture(
            "samples/shader-terrain/textures/skybox.jpg")
        skybox_texture.set_minfilter(SamplerState.FT_linear)
        skybox_texture.set_magfilter(SamplerState.FT_linear)
        skybox_texture.set_wrap_u(SamplerState.WM_repeat)
        skybox_texture.set_wrap_v(SamplerState.WM_mirror)
        skybox_texture.set_anisotropic_degree(16)
        self.skybox.set_texture(skybox_texture)
        skybox_shader = Shader.load(Shader.SL_GLSL, 
            "samples/shader-terrain/skybox.vert.glsl", 
            "samples/shader-terrain/skybox.frag.glsl")
        self.skybox.set_shader(skybox_shader)

        # Terrain
        self.setup_terrain()
        
    def add_wheel(self, pos, front, np):
        wheel = self.vehicle.create_wheel()

        wheel.set_node(np.node())
        wheel.set_chassis_connection_point_cs(pos)
        wheel.set_front_wheel(front)

        wheel.set_wheel_direction_cs(LVector3(0, 0, -1))
        wheel.set_wheel_axle_cs(LVector3(1, 0, 0))
        wheel.set_wheel_radius(0.25)
        wheel.set_max_suspension_travel_cm(40.0)

        wheel.set_suspension_stiffness(40.0)
        wheel.set_wheels_damping_relaxation(2.3)
        wheel.set_wheels_damping_compression(4.4)
        wheel.set_friction_slip(100.0)
        wheel.set_roll_influence(0.1)

    def attach_camera_floater(self):
        """
        Set up an auxiliary camera floater, which is parented to the vehicle.
        Every frame base.cam's position will be set to the camera floater's.
        """
        camera_behind = 8
        camera_above = 3
        self.camera_floater = NodePath("camera_floater")
        self.camera_floater.reparent_to(self.vehicleNP)
        self.camera_floater.set_y(-camera_behind)
        self.camera_floater.set_z(camera_above)

    def reset_vehicle(self):
        reset_pos = self.vehicleNP.get_pos()
        reset_pos.z += 3
        self.vehicleNP.node().clear_forces()
        self.vehicleNP.node().set_linear_velocity(LVector3(0))
        self.vehicleNP.node().set_angular_velocity(LVector3(0))
        self.vehicleNP.set_pos(reset_pos)
        self.vehicleNP.set_hpr(LVector3(0))
        
    def drop_boxes(self):
        """
        Puts a stack of boxes at a distance in front of the vehicle.
        The boxes will not necessarily spawn above the terrain and will not
        be cleaned up.
        """ 
        model = loader.load_model('models/box.egg')
        model.set_pos(-0.5, -0.5, -0.5)
        model.flatten_light()
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))
        ahead = self.vehicleNP.get_pos() + self.vehicle.get_forward_vector()*15
        
        for i in range(6):
            node = BulletRigidBodyNode('Box')
            node.set_mass(5.0)
            node.add_shape(shape)
            node.set_deactivation_enabled(False)
            np = render.attach_new_node(node)
            np.set_pos(ahead.x, ahead.y, ahead.z + i*2)
            self.world.attach(node)
            model.copy_to(np)
        
    def query_elevation(self, xy_pos=None):
        """
        Query elevation for xy_pos if present, else for vehicle position.
        No xy_pos means verbose mode.
        """
        query_pos = xy_pos or self.vehicleNP.get_pos()
        """
        This method is accurate and may be useful for placing 
        objects on the terrain surface.
        """
        result = self.world.ray_test_closest(
            LPoint3(query_pos.x, query_pos.y, -10000),
            LPoint3(query_pos.x, query_pos.y, 10000))
        if result.has_hit():
            hit_pos = result.get_hit_pos()
            if not xy_pos:
                print("Bullet heightfield elevation at "
                    "X {:.2f} | Y {:.2f} is {:.3f}".format(
                    hit_pos.x, hit_pos.y, hit_pos.z))
        else:
            hit_pos = None
            if not xy_pos:
                print("Could not query elevation at {}".format(xy_pos))
        
        """
        This method is less accurate than the one above.
        Under heavy ray-testing stress (ray tests are performed for all vehicle
        wheels, the above elevation query etc.) Bullet sometimes seems to be a
        little unreliable.
        """
        texspace_pos = self.terrain.get_relative_point(render, query_pos)
        stm_pos = self.terrain_node.uv_to_world(
            LTexCoord(texspace_pos.x, texspace_pos.y))
        if not xy_pos:
            print("ShaderTerrainMesh elevation at "
                "X {:.2f} | Y {:.2f} is {:.3f}".format(
                stm_pos.x, stm_pos.y, stm_pos.z))
        
        return hit_pos or stm_pos
    
    def setup_terrain(self):
        """
        Terrain info
        Units are meters, which is preferable when working with Bullet.
        """
        self.terrain_scale = LVector3(512, 512, 100)
        self.terrain_pos = LVector3(-256, -256, -70)
        # sample values for a 4096 x 4096px heightmap.
        #self.terrain_scale = LVector3(4096, 4096, 1000)
        #self.terrain_pos = LVector3(-2048, -2048, -70)
        """
        Diamond_subdivision is an alternating triangulation scheme and may
        produce better results.
        """
        use_diamond_subdivision = True
        
        """
        Construct the terrain
        Without scaling, any ShaderTerrainMesh is 1x1x1 units.
        """
        self.terrain_node = ShaderTerrainMesh()
        """
        Set a heightfield, the heightfield should be a 16-bit png and
        have a quadratic size of a power of two.
        """
        heightfield = Texture()
        heightfield.read(self.heightfield_fn)
        heightfield.set_keep_ram_image(True)        
        self.terrain_node.heightfield = heightfield
        
        # Display characteristic values of the heightfield texture
        #minpoint, maxpoint, avg = LPoint3(), LPoint3(), LPoint3()
        #heightfield.calc_min_max(minpoint, maxpoint)
        #heightfield.calc_average_point(avg, 0.5, 0.5, 0.5)
        #print("avg: {} min: {} max: {}".format(avg.x, minpoint.x, maxpoint.x))

        """
        Set the target triangle width. For a value of 10.0 for example,
        the ShaderTerrainMesh will attempt to make every triangle 10 pixels
        wide on screen.
        """
        self.terrain_node.target_triangle_width = 10.0
        if use_diamond_subdivision:
            """
            This has to be specified before calling .generate()
            The default is false.
            """
            load_prc_file_data("", "stm-use-hexagonal-layout true")
        
        self.terrain_node.generate()
        """
        Attach the terrain to the main scene and set its scale. With no scale
        set, the terrain ranges from (0, 0, 0) to (1, 1, 1)
        """
        self.terrain = self.render.attach_new_node(self.terrain_node)
        self.terrain.set_scale(self.terrain_scale)
        self.terrain.set_pos(self.terrain_pos)
        """
        Set a vertex and a fragment shader on the terrain. The
        ShaderTerrainMesh only works with an applied shader.
        """
        terrain_shader = Shader.load(Shader.SL_GLSL, 
            "samples/shader-terrain/terrain.vert.glsl", 
            "samples/shader-terrain/terrain.frag.glsl")
        self.terrain.set_shader(terrain_shader)
        self.terrain.set_shader_input("camera", base.camera)
        # Set some texture on the terrain
        grass_tex = self.loader.load_texture(
            "samples/shader-terrain/textures/grass.png")
        grass_tex.set_minfilter(SamplerState.FT_linear_mipmap_linear)
        grass_tex.set_anisotropic_degree(16)
        self.terrain.set_texture(grass_tex)

        """
        Set up the DynamicHeightfield (it's a type of PfmFile). We load the
        same heightfield image as with ShaderTerrainMesh.
        """
        self.DHF = DynamicHeightfield()
        self.DHF.read(self.heightfield_fn)
        """
        Set up empty PfmFiles to prepare stuff in that is going to
        dynamically modify our terrain.
        """
        self.StagingPFM = PfmFile()
        self.RotorPFM = PfmFile()
        
        """
        Set up the BulletHeightfieldShape (=collision terrain) and give it
        some sensible physical properties.
        """
        self.HFS = BulletHeightfieldShape(self.DHF, self.terrain_scale.z,
                                          STM=True)
        if use_diamond_subdivision:
            self.HFS.set_use_diamond_subdivision(True)
        HFS_rigidbody = BulletRigidBodyNode("BulletTerrain")
        HFS_rigidbody.set_static(True)
        friction = 2.0
        HFS_rigidbody.set_anisotropic_friction(
            LVector3(friction, friction, friction/1.3))
        HFS_rigidbody.set_restitution(0.3)
        HFS_rigidbody.add_shape(self.HFS)
        self.world.attach(HFS_rigidbody)
        
        HFS_NP = NodePath(HFS_rigidbody)
        HFS_NP.reparent_to(self.worldNP)
        """
        This aligns the Bullet terrain with the ShaderTerrainMesh rendered
        terrain. It will be exact as long as the terrain vertex shader from
        the STM sample is used and no additional tessellation shader.
        For Bullet (as for other physics engines) the origin of objects is at
        the center.
        """
        HFS_NP.set_pos(self.terrain_pos + self.terrain_scale/2)
        HFS_NP.set_sx(self.terrain_scale.x / heightfield.get_x_size())
        HFS_NP.set_sy(self.terrain_scale.y / heightfield.get_y_size())
        
        # Disables Bullet debug rendering for the terrain, because it is slow.
        #HFS_NP.node().set_debug_enabled(False)
        
        """
        Finally, link the ShaderTerrainMesh and the BulletHeightfieldShape to
        the DynamicHeightfield. From now on changes to the DynamicHeightfield
        will propagate to the (visible) ShaderTerrainMesh and the (collidable)
        BulletHeightfieldShape.
        """
        self.HFS.set_dynamic_heightfield(self.DHF)
        self.terrain_node.set_dynamic_heightfield(self.DHF)

    def deform_terrain(self, mode="raise", duration=1.0):
        self.deform_duration = duration
        """
        Calculate distance to the spot at which we want to raise the terrain.
        At its current speed the vehicle would reach it in 2.5 seconds.
        [km/h] / 3.6 = [m/s] * [s] = [m]
        """
        distance = self.vehicle.get_current_speed_km_hour() / 3.6 * 2.5
        spot_pos_world = (self.vehicleNP.get_pos() +
                          self.vehicle.get_forward_vector() * distance)

        spot_pos_heightfield = self.terrain_node.world_to_heightfield(
            spot_pos_world)
        xcenter = spot_pos_heightfield.x
        ycenter = spot_pos_heightfield.y
        """
        To create a smooth hill/depression we call PfmFile.pull_spot to create
        a sort of gradient. You can use self.cardmaker_debug to view it.
        
        From the Panda3D API documentation of PfmFile.pull_spot:
        Applies delta * t to the point values within radius (xr, yr)
        distance of (xc, yc). The t value is scaled from 1.0 at the center
        to 0.0 at radius (xr, yr), and this scale follows the specified
        exponent. Returns the number of points affected.
        """
        # Delta to apply to the point values in DynamicHeightfield array.
        delta = LVector4(0.001)
        # Make the raised spot elliptical.
        xradius = 10.0  # meters
        yradius = 6.0  # meters
        # Choose an exponent
        exponent = 0.6
        # Counter-clockwise angle between Y-axis 
        angle = self.vehicle.get_forward_vector().signed_angle_deg(
            LVector3.forward(), LVector3.down())
            
        # Define all we need to repeatedly deform the terrain using a task.    
        self.spot_params = [delta, xcenter, ycenter, xradius, yradius,
                            exponent, mode]
                            
        # Clear staging area to a size that fits our raised region.
        self.StagingPFM.clear(int(xradius)*2, int(yradius)*2, num_channels=1)
        
        """
        There are two options:
        (1) Rotate our hill/depression to be perpendicular
            to the vehicle's trajectory. This is the default.
        (2) Just put it in the terrain unrotated.
        """

        # Option (1)
        self.StagingPFM.pull_spot(delta,
                                  xradius-0.5, yradius-0.5,
                                  xradius, yradius,
                                  exponent)
        
        # Rotate wider side so it's perpendicular to vehicle's trajectory.
        self.RotorPFM.rotate_from(self.StagingPFM, angle)
        
        self.raise_start_time = globalClock.get_real_time()
        taskMgr.do_method_later(0.03, self.deform_perpendicular,
                                "DeformPerpendicularSpot")
                                
        # Option (2)
        #taskMgr.do_method_later(0.03, self.deform_regular, "RaiseASpot")
        
    def deform_perpendicular(self, task):
        if (globalClock.get_real_time() - self.raise_start_time <
            self.deform_duration):
            (delta, xcenter, ycenter,
             xradius, yradius, exponent, mode) = self.spot_params

            """
            Copy rotated hill to our DynamicHeightfield.
            The values from RotorPFM are added to the ones found in the
            DynamicHeightfield.
            """
            self.DHF.add_sub_image(self.RotorPFM, 
                int(xcenter - self.RotorPFM.get_x_size()/2),
                int(ycenter - self.RotorPFM.get_y_size()/2),
                0, 0, self.RotorPFM.get_x_size(), self.RotorPFM.get_y_size(),
                1.0 if mode == "raise" else -1.0)
            
            # Output images of our PfmFiles.
            #self.RotorPFM.write("dbg_RotorPFM.png")
            #self.StagingPFM.write("dbg_StagingPFM.png")
            return task.again
        
        self.cardmaker_debug()
        return task.done
        
    def deform_regular(self, task):
        if (globalClock.get_real_time() - self.raise_start_time <
            self.deform_duration):
            (delta, xcenter, ycenter,
             xradius, yradius, exponent, mode) = self.spot_params
            self.DHF.pull_spot(delta * (1.0 if mode == "raise" else -1.0),
                               xcenter, ycenter, xradius, yradius, exponent)
            return task.again
        return task.done

    def convert_coordinates(self):
        vpos = self.vehicleNP.get_pos()
        print("VPOS world: ", vpos)
        W2H = self.terrain_node.world_to_heightfield(vpos)
        print("W2H: ", W2H)
        H2W = self.terrain_node.heightfield_to_world(LTexCoord(W2H.x, W2H.y))
        print("H2W: ", H2W)
        
        W2U = self.terrain_node.world_to_uv(vpos)
        print("W2U: ", W2U)
        U2W = self.terrain_node.uv_to_world(LTexCoord(W2U.x, W2U.y))
        print("U2W: ", U2W)

    def hide_terrain(self):
        if self.terrain.is_hidden():
            self.terrain.show()
        else:
            self.terrain.hide()

    def save(self):
        self.DHF.write("dbg_dynamicheightfield.png")

    def pfmvizzer_debug(self, pfm):
        vizzer = PfmVizzer(pfm)
        """
        To align the mesh we generate with PfmVizzer with our 
        ShaderTerrainMesh, BulletHeightfieldShape, and DynamicHeightfield, we
        need to set a negative scale on the Y axis. This reverses the winding
        order of the triangles in the mesh, which is why we choose
        PfmVizzer.MF_back
        Note that this does not accurately match up with our mesh because the
        interpolation differs. Still, PfmVizzer can be useful when
        inspecting, distorting, etc. PfmFiles.
        """
        self.vizNP = vizzer.generate_vis_mesh(PfmVizzer.MF_back)
        self.vizNP.set_texture(loader.load_texture("maps/grid.rgb"))
        self.vizNP.reparent_to(render)
        if pfm == self.DHF or pfm == self.terrain_node.heightfield:
            self.vizNP.set_pos(self.terrain_pos.x, -self.terrain_pos.y,
                               self.terrain_pos.z)
            self.vizNP.set_scale(self.terrain_scale.x, -self.terrain_scale.y,
                                 self.terrain_scale.z)

    def cardmaker_debug(self):
        for node in render2d.find_all_matches("pfm"):
            node.remove_node()
        for text in base.a2dBottomLeft.find_all_matches("*"):
            text.remove_node()
        width = 0.2  # render2d coordinates range: [-1..1]
        # Pseudo-normalize our PfmFile for better contrast.
        normalized_pfm = PfmFile(self.RotorPFM)
        max_p = LVector3()
        normalized_pfm.calc_min_max(LVector3(), max_p)
        normalized_pfm *= 1.0 / max_p.x
        # Put it in a texture
        tex = Texture()
        tex.load(normalized_pfm)
        # Apply the texture to a quad and put it in the lower left corner.
        cm = CardMaker("pfm")
        cm.set_frame(0, width, 0,
            width / normalized_pfm.get_x_size() * normalized_pfm.get_y_size())
        card = base.render2d.attach_new_node(cm.generate())
        card.set_pos(-1, 0, -1)        
        card.set_texture(tex)
        # Display max value text
        self.genLabelText(-3,
                          "Max value: {:.3f} == {:.2f}m".format(max_p.x,
                            max_p.x * self.terrain_scale.z),
                          parent="a2dBottomLeft")
コード例 #25
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -40, 10)
        base.cam.look_at(0, 0, 5)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(1, 1, -1))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        self.accept('1', self.do_shoot, [True])
        self.accept('2', self.do_shoot, [False])

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    def do_shoot(self, ccd):
        # Get from/to points from mouse click
        pMouse = base.mouseWatcherNode.get_mouse()
        pFrom = LPoint3()
        pTo = LPoint3()
        base.camLens.extrude(pMouse, pFrom, pTo)

        pFrom = render.get_relative_point(base.cam, pFrom)
        pTo = render.get_relative_point(base.cam, pTo)

        # Calculate initial velocity
        v = pTo - pFrom
        v.normalize()
        v *= 10000.0

        # Create bullet
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))
        body = BulletRigidBodyNode('Bullet')
        bodyNP = self.worldNP.attach_new_node(body)
        bodyNP.node().add_shape(shape)
        bodyNP.node().set_mass(2.0)
        bodyNP.node().set_linear_velocity(v)
        bodyNP.set_pos(pFrom)
        bodyNP.set_collide_mask(BitMask32.all_on())

        if ccd:
            bodyNP.node().set_ccd_motion_threshold(1e-7)
            bodyNP.node().set_ccd_swept_sphere_radius(0.50)

        self.world.attach(bodyNP.node())

        # Remove the bullet again after 1 second
        taskMgr.do_method_later(1,
                                self.do_remove,
                                'doRemove',
                                extraArgs=[bodyNP],
                                appendTask=True)

    def do_remove(self, bulletNP, task):
        self.world.remove(bulletNP.node())
        return task.done

    # ____TASK___

    def update(self, task):
        dt = globalClock.get_dt()
        self.world.do_physics(dt, 20, 1.0 / 180.0)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()
        self.worldNP = None

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        shape = BulletPlaneShape(LVector3(0, 0, 1), 0)
        body = BulletRigidBodyNode('Ground')
        bodyNP = self.worldNP.attach_new_node(body)
        bodyNP.node().add_shape(shape)
        bodyNP.set_pos(0, 0, -1)
        bodyNP.set_collide_mask(BitMask32.all_on())
        self.world.attach(bodyNP.node())

        # Some boxes
        shape = BulletBoxShape(LVector3(0.5, 0.5, 0.5))

        for i in range(10):
            for j in range(10):
                x = i - 5.0
                y = 0.0
                z = j - 0.5

                body = BulletRigidBodyNode('Box-{}-{}'.format(i, j))
                bodyNP = self.worldNP.attach_new_node(body)
                bodyNP.node().add_shape(shape)
                bodyNP.node().set_mass(1.0)
                bodyNP.node().set_deactivation_enabled(False)
                bodyNP.set_pos(x, y, z)
                bodyNP.set_collide_mask(BitMask32.all_on())

                self.world.attach(bodyNP.node())

                visNP = loader.load_model('models/box.egg')
                visNP.clear_model_nodes()
                visNP.reparent_to(bodyNP)
コード例 #26
0
class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        base.set_background_color(0.1, 0.1, 0.8, 1)
        base.set_frame_rate_meter(True)

        base.cam.set_pos(0, -40, 10)
        base.cam.look_at(0, 0, 0)

        # Light
        alight = AmbientLight('ambientLight')
        alight.set_color(LVector4(0.5, 0.5, 0.5, 1))
        alightNP = render.attach_new_node(alight)

        dlight = DirectionalLight('directionalLight')
        dlight.set_direction(LVector3(5, 0, -2))
        dlight.set_color(LVector4(0.7, 0.7, 0.7, 1))
        dlightNP = render.attach_new_node(dlight)

        render.clear_light()
        render.set_light(alightNP)
        render.set_light(dlightNP)

        # Input
        self.accept('escape', self.do_exit)
        self.accept('r', self.do_reset)
        self.accept('f1', base.toggle_wireframe)
        self.accept('f2', base.toggle_texture)
        self.accept('f3', self.toggle_debug)
        self.accept('f5', self.do_screenshot)

        # Task
        taskMgr.add(self.update, 'updateWorld')

        # Physics
        self.setup()

    # _____HANDLER_____

    def do_exit(self):
        self.cleanup()
        sys.exit(1)

    def do_reset(self):
        self.cleanup()
        self.setup()

    def toggle_debug(self):
        if self.debugNP.is_hidden():
            self.debugNP.show()
        else:
            self.debugNP.hide()

    def do_screenshot(self):
        base.screenshot('Bullet')

    # ____TASK___

    def update(self, task):
        dt = globalClock.get_dt()
        #dt *= 0.01
        self.world.do_physics(dt, 10, 0.008)
        return task.cont

    def cleanup(self):
        self.world = None
        self.worldNP.remove_node()

    def setup(self):
        self.worldNP = render.attach_new_node('World')

        # World
        self.debugNP = self.worldNP.attach_new_node(BulletDebugNode('Debug'))
        self.debugNP.show()

        self.world = BulletWorld()
        self.world.set_gravity(LVector3(0, 0, -9.81))
        self.world.set_debug_node(self.debugNP.node())

        # Ground
        p0 = LPoint3(-20, -20, 0)
        p1 = LPoint3(-20, 20, 0)
        p2 = LPoint3(20, -20, 0)
        p3 = LPoint3(20, 20, 0)
        mesh = BulletTriangleMesh()
        mesh.add_triangle(p0, p1, p2)
        mesh.add_triangle(p1, p2, p3)
        shape = BulletTriangleMeshShape(mesh, dynamic=False)

        np = self.worldNP.attach_new_node(BulletRigidBodyNode('Mesh'))
        np.node().add_shape(shape)
        np.set_pos(0, 0, -2)
        np.set_collide_mask(BitMask32.all_on())

        self.world.attach(np.node())

        # Soft body world information
        info = self.world.get_world_info()
        info.set_air_density(1.2)
        info.set_water_density(0)
        info.set_water_offset(0)
        info.set_water_normal(LVector3(0, 0, 0))

        # Softbody
        def make_SB(pos, hpr):

            #use this to construct a torus geom.
            #import torus
            #geom = torus.make_geom()

            geom = (loader.load_model('models/torus.egg').find_all_matches(
                '**/+GeomNode').get_path(0).node().modify_geom(0))

            geomNode = GeomNode('')
            geomNode.add_geom(geom)

            node = BulletSoftBodyNode.make_tri_mesh(info, geom)
            node.link_geom(geomNode.modify_geom(0))

            node.generate_bending_constraints(2)
            node.get_cfg().set_positions_solver_iterations(2)
            node.get_cfg().set_collision_flag(
                BulletSoftBodyConfig.CF_vertex_face_soft_soft, True)
            node.randomize_constraints()
            node.set_total_mass(50, True)

            softNP = self.worldNP.attach_new_node(node)
            softNP.set_pos(pos)
            softNP.set_hpr(hpr)
            self.world.attach(node)

            geomNP = softNP.attach_new_node(geomNode)

        make_SB(LPoint3(-3, 0, 4), (0, 0, 0))
        make_SB(LPoint3(0, 0, 4), (0, 90, 90))
        make_SB(LPoint3(3, 0, 4), (0, 0, 0))
コード例 #27
0
class Demo(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        # Bullet Physics Setup
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0, 0, -9.81))

        shape = BulletPlaneShape(Vec3(0, 0, 1), 1)
        node = BulletRigidBodyNode('Ground')
        node.addShape(shape)
        ground_np = self.render.attachNewNode(node)
        ground_np.setPos(0, 0, -60)
        # noinspection PyArgumentList
        self.world.attach(node)

        # Mouse and Camera Setup
        self.disable_mouse()
        self.camera.set_pos(20, -150, 5)
        self.follow_np = self.render.attach_new_node('Follow')

        # Instructions
        self.add_instruction('(p) to generate a Plane', 0.06)
        self.add_instruction('(b) to generate a Cuboid/Box', 0.12)
        self.add_instruction('(s) to generate a Spheroid', 0.18)
        self.add_instruction('(c) to generate a Cylinder', 0.24)
        self.add_instruction('(f1) to toggle wireframe', 0.30)
        self.add_instruction('(esc) to exit', 0.36)
        # Input
        self.accept('escape', sys.exit, [0])
        self.accept('p', self.generate_plane)
        self.accept('b', self.generate_cuboid)
        self.accept('s', self.generate_spheroid)
        self.accept('c', self.generate_cylinder)
        self.accept('f1', self.toggle_wireframe)

        self.task_mgr.add(self.update, 'update')

    def add_instruction(self, text, y_pos, x_pos=0.06):
        _ = OnscreenText(
            text,
            pos=(x_pos, y_pos),
            fg=(1, 1, 1, 1),
            parent=self.a2dBottomLeft,
            scale=0.06,
            align=TextNode.ALeft
        )

    def update(self, task):
        dt = globalClock.getDt()
        self.world.doPhysics(dt)
        self.camera.look_at(self.follow_np)
        return task.cont

    # noinspection PyArgumentList
    def generate_plane(self):
        bounds = Vec3(*[random.uniform(5.0, 30.0) for _ in range(2)])
        pos = Vec3(
            *[random.uniform(-100.0, 100.0) for _ in range(2)],
            random.uniform(50.0, 400.0)
        )
        normal = Vec3(
            *[random.uniform(-1.0, 1.0) for _ in range(3)],
        )
        color = tuple(normal * 0.5 + 0.5) + (1.,)
        p = Plane((0., 0., 0.), bounds, normal, two_sided=True)
        p.subdivide_dist(4)
        p.geom_store.set_color(color)
        geom_node = p.geom_node
        plane_np = self.render.attach_new_node(geom_node)
        shape = get_bullet_shape(geom_node)
        node = BulletRigidBodyNode('Plane')
        node.set_mass(random.uniform(0.1, 1000.0))
        node.add_shape(shape)
        visual_np = self.render.attach_new_node(node)
        self.world.attach(node)
        plane_np.reparent_to(visual_np)
        self.follow_np.reparent_to(visual_np)
        visual_np.set_pos(pos)

    # noinspection PyArgumentList
    def generate_cuboid(self):
        bounding_box = Vec3(*[random.uniform(5.0, 30.0) for _ in range(3)])
        pos = Vec3(
            *[random.uniform(-100.0, 100.0) for _ in range(2)],
            random.uniform(50.0, 400.0)
        )
        hpr = Vec3(*[random.random() * 360 for _ in range(3)])
        c = Cuboid(bounding_box)
        c.subdivide_dist(4)
        c.geom_store.normals_as_colors()
        geom_node = c.geom_node
        cuboid_np = self.render.attach_new_node(geom_node)
        shape = get_bullet_shape(geom_node)
        node = BulletRigidBodyNode('Cuboid')
        node.set_mass(random.uniform(0.1, 1000.0))
        node.add_shape(shape)
        visual_np = self.render.attach_new_node(node)
        self.world.attach(node)
        cuboid_np.reparent_to(visual_np)
        self.follow_np.reparent_to(visual_np)
        visual_np.set_pos(pos)
        visual_np.set_hpr(hpr)

    # noinspection PyArgumentList
    def generate_spheroid(self):
        bounding_box = Vec3(*[random.uniform(5.0, 30.0) for _ in range(3)])
        pos = Vec3(
            *[random.uniform(-100.0, 100.0) for _ in range(2)],
            random.uniform(50.0, 400.0)
        )
        hpr = Vec3(*[random.random() * 360 for _ in range(3)])
        s = Spheroid(bounding_box)
        s.subdivide_dist(4)
        s.geom_store.normals_as_colors()
        geom_node = s.geom_node
        spheroid_np = self.render.attach_new_node(geom_node)
        shape = get_bullet_shape(geom_node)
        node = BulletRigidBodyNode('Cuboid')
        node.set_mass(random.uniform(0.1, 1000.0))
        node.add_shape(shape)
        visual_np = self.render.attach_new_node(node)
        self.world.attach(node)
        spheroid_np.reparent_to(visual_np)
        self.follow_np.reparent_to(visual_np)
        visual_np.set_pos(pos)
        visual_np.set_hpr(hpr)

    # noinspection PyArgumentList
    def generate_cylinder(self):
        start_point = Vec3(*[random.uniform(-30.0, 30.0) for _ in range(3)])
        end_point = -start_point
        radii = [random.randint(0, 10) for _ in range(2)]
        pos = Vec3(
            *[random.uniform(-100.0, 100.0) for _ in range(2)],
            random.uniform(50.0, 400.0)
        )
        c = SingleCylinder(12, start_point, radii[0], end_point, radii[1])
        c.subdivide_dist(4)
        c.geom_store.normals_as_colors()
        geom_node = c.geom_node
        cylinder_np = self.render.attach_new_node(geom_node)
        shape = get_bullet_shape(geom_node)
        node = BulletRigidBodyNode('Cuboid')
        node.set_mass(random.uniform(0.1, 1000.0))
        node.add_shape(shape)
        visual_np = self.render.attach_new_node(node)
        self.world.attach(node)
        cylinder_np.reparent_to(visual_np)
        self.follow_np.reparent_to(visual_np)
        visual_np.set_pos(pos)