コード例 #1
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
コード例 #2
0
ファイル: main.py プロジェクト: r3t/master-term1-gamedev
class Balls(ShowBase):
  def __init__(self):
    ShowBase.__init__(self)
    self.title = OnscreenText(text="0 balls",
      parent=base.a2dBottomRight, align=TextNode.ARight,
      fg=(1, 1, 1, 1), pos=(-0.1, 0.1), scale=.08,
      shadow=(0, 0, 0, 0.5))
    # exit on esc
    self.accept('escape', sys.exit)
    # disable standart mouse based camera control
    self.disableMouse()
    # set camera position
    self.camera.setPos(0, -30, 25)
    self.camera.lookAt(0, 0, 0)
    #
    self.world = BulletWorld()
    self.world.setGravity(Vec3(0, 0, -9.81))

    self.taskMgr.add(self.updateWorld, 'updateWorld')
    self.setupLight()
    # down
    self.makePlane(0, Vec3(0, 0, 1), (0, 0, 0), (0, 0, 0))
    # up
    self.makePlane(1, Vec3(0, 0, -1), (0, 0, 10), (0, 0, 0))
    # left
    self.makePlane(2, Vec3(1, 0, 0), (-5, 0, 5), (0, 0, 90))
    # right
    self.makePlane(3, Vec3(-1, 0, 0), (5, 0, 5), (0, 0, -90))
    # top
    self.makePlane(4, Vec3(0, 1, 0), (0, -5, 5), (0, 90, 0))
    # buttom
    self.makePlane(5, Vec3(0, -1, 0), (0, 5, 5), (0, -90, 0))

    self.accept('mouse1', self.pickBall)
    self.accept('mouse3', self.releaseBall)
    self.accept('arrow_up', partial(self.rotateCube, hpr = (0, ROTATE_SPEED, 0)))
    self.accept('arrow_down', partial(self.rotateCube, hpr = (0, -ROTATE_SPEED, 0)))
    self.accept('arrow_left', partial(self.rotateCube, hpr = (0, 0, -ROTATE_SPEED)))
    self.accept('arrow_right', partial(self.rotateCube, hpr = (0, 0, ROTATE_SPEED)))
    self.accept('space', self.shakeBalls)
    self.accept('page_up', self.addRandomBall)
    self.accept('page_down', self.rmBall)

    self.ballCnt = 0
    self.ballColors = {}
    for num in xrange(DEFAULT_BALLS):
      self.addRandomBall()
    self.picked = set([])

  def setupLight(self):
    ambientLight = AmbientLight("ambientLight")
    ambientLight.setColor((.8, .8, .8, 1))
    directionalLight = DirectionalLight("directionalLight")
    directionalLight.setDirection(LVector3(0, 45, -45))
    directionalLight.setColor((0.2, 0.2, 0.2, 1))
    render.setLight(render.attachNewNode(directionalLight))
    render.setLight(render.attachNewNode(ambientLight))

  def updateWorld(self, task):
    dt = globalClock.getDt()
    # bug #1455084, simple doPhysics(dt) does nothing
    # looks like fixed already
    self.world.doPhysics(dt, 1, 1. / 60.)
    return task.cont

  def rayCollision(self):
    if self.mouseWatcherNode.hasMouse():
      mouse = self.mouseWatcherNode.getMouse()
      pointFrom, pointTo = Point3(), Point3()
      self.camLens.extrude(mouse, pointFrom, pointTo)
      pointFrom = render.getRelativePoint(self.cam, pointFrom)
      pointTo = render.getRelativePoint(self.cam, pointTo)
      hits = self.world.rayTestAll(pointFrom, pointTo).getHits()
      return sorted(hits, key = lambda x: (x.getHitPos() - pointFrom).length())
    return []

  def pickBall(self):
      hits = self.rayCollision()
      for hit in hits:
        hit_node = hit.getNode()
        if 'ball' in hit_node.getName():
          self.picked.add(hit_node.getName())
          NodePath(hit_node.getChild(0).getChild(0)).setColor(HIGHLIGHT)

  def releaseBall(self):
    hits = self.rayCollision()
    if hits:
      foundBall = False
      for picked in hits:
        hit_node = picked.getNode()
        if 'ball' in hit_node.getName():
          foundBall = True
          x, y, z = picked.getHitPos()
          bodies = self.world.getRigidBodies()
          for elem in bodies:
            name = elem.getName()
            if name in self.picked:
              # apply some physics
              node = NodePath(elem.getChild(0).getChild(0))
              node_x, node_y, node_z = node.getPos(render)
              ix = (x - node_x)
              iy = (y - node_y)
              dir = atan2(iy, ix)
              dx, dy = SPEED * cos(dir), SPEED * sin(dir)
              elem.applyCentralImpulse(LVector3(dx, dy, z))
              node.setColor(self.ballColors[elem.getName()])
      if foundBall:
        self.picked = set([])

  def rotateCube(self, hpr = (0, 0, 0)):
    # h, p, r = z, x, y
    # FIXME: something completely wrong goes here
    # need some time to figure it out
    planes = render.findAllMatches('**/plane*')
    for plane in planes:
      oldParent = plane.getParent()
      pivot = render.attachNewNode('pivot')
      pivot.setPos(render, 0, 0, 5)
      plane.wrtReparentTo(pivot)
      pivot.setHpr(render, Vec3(hpr))
      if oldParent.getName() != 'render':
        oldParent.removeNode()

  def shakeBalls(self):
    balls = filter(lambda x: 'ball' in x.getName(), self.world.getRigidBodies())
    for ball in balls:
      dx = uniform(-SHAKE_SPEED, SHAKE_SPEED)
      dy = uniform(-SHAKE_SPEED, SHAKE_SPEED)
      dz = uniform(-SHAKE_SPEED, SHAKE_SPEED)
      ball.applyCentralImpulse(LVector3(dx, dy, dz))

  def updateBallsCounter(self, num):
    self.ballCnt += num
    self.title.setText('%d balls' % (self.ballCnt))

  def addRandomBall(self):
    planes = render.findAllMatches('**/plane*')
    x, y, z = zip(*[tuple(plane.getPos()) for plane in planes])
    xPos = uniform(min(x), max(x))
    yPos = uniform(min(y), max(y))
    zPos = uniform(min(z), max(z))
    self.makeBall(self.ballCnt, (xPos, yPos, zPos))
    self.updateBallsCounter(1)

  def rmBall(self):
    if self.ballCnt != 0:
      ball = render.find('**/ball_' + str(self.ballCnt - 1))
      self.ballColors.pop(ball.getName())
      ball.removeNode()
      self.updateBallsCounter(-1)

  def makePlane(self, num, norm, pos, hpr):
    shape = BulletPlaneShape(norm, 0)
    node = BulletRigidBodyNode('plane_' + str(num))
    node.addShape(shape)
    physics = render.attachNewNode(node)
    physics.setPos(*pos)
    self.world.attachRigidBody(node)
    model = loader.loadModel('models/square')
    model.setScale(10, 10, 10)
    model.setHpr(*hpr)
    model.setTransparency(TransparencyAttrib.MAlpha)
    model.setColor(1, 1, 1, 0.25)
    model.reparentTo(physics)

  def makeColor(self):
    return (random(), random(), random(), 1)

  def makeBall(self, num, pos = (0, 0, 0)):
    shape = BulletSphereShape(0.5)
    node = BulletRigidBodyNode('ball_' + str(num))
    node.setMass(1.0)
    node.setRestitution(.9)
    node.setDeactivationEnabled(False)
    node.addShape(shape)
    physics = render.attachNewNode(node)
    physics.setPos(*pos)
    self.world.attachRigidBody(node)
    model = loader.loadModel('models/ball')
    color = self.makeColor()
    model.setColor(color)
    self.ballColors['ball_' + str(num)] = color
    model.reparentTo(physics)
コード例 #3
0
class PhysicsManager(object):    

    def __init__(self, gravity=(0,0,-9.81) ):
        self.world = BulletWorld()
        self.world.setGravity(Vec3(gravity) )        

        self.addShape = {}
        self.addShape['plane']    = self.__addTriangleMesh
        self.addShape['sphere']   = self.__addSphere  
        self.addShape['box']      = self.__addBox
        self.addShape['cylinder'] = self.__addCylinder
        self.addShape['capsule']  = self.__addCapsule
        self.addShape['cone']     = self.__addCone
        self.addShape['hull']     = self.__addConvexHull
        self.addShape['trimesh']  = self.__addTriangleMesh
        self.addShape['compound'] = self.__addCompound

        self.num_rigidBodies = 0
        self.num_ghosts      = 0

    def getRigidBodyDefaultProps(self):
        props = {}
        props['mass']         = .0
        props['friction']     = .5
        props['restitution']  = .0
        props['adamping']     = .0
        props['ldamping']     = .0
        props['asleep']       = .08
        props['lsleep']       = 1.
        props['deactivation'] = True
        props['kinematic']    = False
        return props

    def getRigidBody(self, name=None):
        self.num_rigidBodies+=1
        return BulletRigidBodyNode(name or 'rigidbody'+str(self.num_rigidBodies) )

    def createRigidBody(self, shapetype, model, props={}, name=None):
        body = self.getRigidBody(name)
        self.addShape[shapetype](body, model)
        props = dict(self.getRigidBodyDefaultProps().items() + props.items() )
        self.setBodyProps(body, props)
        self.world.attachRigidBody( body )
        return body         

    def getGhost(self, name=None):
        self.num_ghosts+=1
        return BulletGhostNode(name or 'ghost'+str(self.num_ghosts) )

    def createGhost(self, shapetype, size, name=None):        
        ghost = self.getGhost(name)
        self.addShape[shapetype](ghost, size) 
        self.world.attachGhost(ghost)
        return ghost  

    def attachRigidBody(self, body, props):
        self.setBodyProps(body, props)
        self.world.attachRigidBody(body)

    def __addCompound(self, body, model):
        self.createCompound(model,body)   

    def __addSphere(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1) ):
        size = self.getSize(model)
        shape = BulletSphereShape( max(size)/2 )
        body.addShape(shape, TransformState.makePosHprScale(pos,hpr,scale) )

    def __addBox(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1) ):
        size = self.getSize(model)
        shape = BulletBoxShape( size/2 )
        body.addShape(shape, TransformState.makePosHprScale(pos,hpr,scale) )

    def __addCylinder(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1) ):
        size = self.getSize(model)
        shape = BulletCylinderShape(max(size.x,size.y)/2, size.z, ZUp)
        body.addShape( shape, TransformState.makePosHprScale(pos,hpr,scale) )

    def __addCapsule(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1) ):
        size = self.getSize(model)
        diam = max(size.x,size.y)
        shape = BulletCapsuleShape(diam/2, size.z-diam, ZUp)       
        body.addShape( shape, TransformState.makePosHprScale(pos,hpr,scale) )

    def __addCone(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1) ):
        size = self.getSize(model)
        shape = BulletConeShape(max(size.x,size.y)/2, size.z, ZUp)
        body.addShape( shape, TransformState.makePosHprScale(pos,hpr,scale) )

    def __addConvexHull(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1) ):        
        
        def one():
            geom = model.node().getGeom(0)          
            shape = BulletConvexHullShape()
            shape.addGeom(geom)
            body.addShape( shape, TransformState.makePosHprScale(pos,hpr,scale) )
            return []

        children =  model.findAllMatches('**/+GeomNode') or one()

        model.flattenLight()

        for piece in children:
            shape = BulletConvexHullShape()
            geom = piece.node().getGeom(0)
            shape.addGeom(geom)
            body.addShape( shape, TransformState.makePosHprScale(pos,hpr,scale) )

    def __addTriangleMesh(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1), dynamic=True):        
        
        mesh = BulletTriangleMesh()
      
        def one():
            geom = model.node().getGeom(0)            
            mesh.addGeom(geom)
            return []

        children =  model.findAllMatches('**/+GeomNode') or one()

        model.flattenLight()

        for piece in children:
            geom = piece.node().getGeom(0)
            mesh.addGeom(geom)

        shape = BulletTriangleMeshShape(mesh, dynamic=dynamic )
        body.addShape( shape, TransformState.makePosHprScale(pos,hpr,scale) )

    # def __addPlane(self, body, model, pos=(0,0,0), hpr=(0,0,0), scale=(1,1,1) ):
    #     shape = BulletPlaneShape(Vec3(0, 0, 1), 1)
    #     node = BulletRigidBodyNode(model.getName())
    #     node.addShape(shape)
    #     np = render.attachNewNode(node)
    #     np.setPos( pos )
    #     model.reparentTo(np)
    #     self.world.attachRigidBody(node)

    def setBodyProps(self, body, props):        
        body.setMass( props['mass'] )
        body.setFriction( props['friction'] )
        body.setRestitution( props['restitution'] )
        body.setAngularDamping( props['adamping'] )
        body.setLinearDamping( props['ldamping'] )
        body.setAngularSleepThreshold( props['asleep'] )
        body.setLinearSleepThreshold( props['lsleep'] )
        if not props['deactivation']:
            body.setDeactivationEnabled( False )
        body.setKinematic( props['kinematic'] )

    def characterController(self, name, height, mass, radius, step_height):
        shape = BulletCapsuleShape(radius, height - 2*radius, ZUp)
        body = BulletRigidBodyNode(name)
        body.setMass(mass)
        body.addShape(shape)
        return BulletCharacterControllerNode(shape, step_height, name)
    
    def debug(self):
        from panda3d.bullet import BulletDebugNode
        debugNP = render.attachNewNode(BulletDebugNode('Debug') )
        #debugNP.show()
        debugNP.node().showWireframe(True)
        debugNP.node().showConstraints(True)
        debugNP.node().showBoundingBoxes(False)
        debugNP.node().showNormals(False)        
        self.world.setDebugNode(debugNP.node())
        return debugNP

    def getSize(self,model):        
        hpr = model.getHpr()
        model.setHpr(0,0,0)
        minLimit, maxLimit = model.getTightBounds()
        model.setHpr(hpr) 
        return maxLimit - minLimit

    def setShape(self, model, body):        
        #To Re-Do
        name = model.getName()

        pos,hpr,scale = model.getPos(), model.getHpr(), model.getScale()    

        shapetype = re.findall("[-a-z]+",name.lower())[0].split('-')

        shapetype = filter(None,shapetype)
        
        if shapetype[0] in self.addShape.keys():
            self.addShape[shapetype[0]](body,model,pos,hpr,scale)

        not '-' in name or model.remove()

    def createCompound(self, model, body):
        children = model.find('**/*').getChildren() or model.getChildren()

        [self.setShape(child,body) for child in children]

    def cleanup(self):
        rbs = self.world.getRigidBodies()
        for body in rbs:
            self.world.removeRigidBody(body)
            print 'PhysicsManager: removing rigidbody'

    def destroy(self):
        self.cleanup()
        del self.addShape
        del self.world
        print 'destroy PhysicsManager'

    def __del__(self):
        print 'delete PhysicsManager'