Skip to content

Instantly share code, notes, and snippets.

@AWhetter
Created May 29, 2014 10:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AWhetter/4dee6698e96b335f238d to your computer and use it in GitHub Desktop.
Save AWhetter/4dee6698e96b335f238d to your computer and use it in GitHub Desktop.
Generates the collision shape of a model in Panda3D
import itertools
from panda3d.core import NodePath
from panda3d.core import TransformState
from panda3d.core import Vec3
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletConeShape
from panda3d.bullet import BulletConvexHullShape
from panda3d.bullet import BulletCylinderShape
from panda3d.bullet import BulletSphereShape
from panda3d.bullet import BulletTriangleMesh
from panda3d.bullet import BulletTriangleMeshShape
class Entity():
@staticmethod
def calcSize(model):
entityModel = loader.loadModel(model)
return Entity.calcNodeSize(entityModel)
@staticmethod
def calcNodeSize(node):
bottomLeft, topRight = node.getTightBounds()
width = topRight.x - bottomLeft.x
depth = topRight.y - bottomLeft.y
height = topRight.z - bottomLeft.z
return Vec3(width, depth, height)
@staticmethod
def calcTransform(nodePath, root):
bottomLeft, topRight = nodePath.getTightBounds()
shapeOrigin = (bottomLeft + topRight)/2
originOffset = shapeOrigin - nodePath.getPos()
if root is None:
# We only needed to calculate the shape offset
return TransformState.makePos(originOffset)
else:
# Combine the shape offset with nodePath's transform to the root node
transform = nodePath.getTransform(root)
return transform.setPos(transform.getPos() + originOffset)
@staticmethod
def calcCollisionShape(shape, model):
if shape == "geometry":
return Entity.calcCollisionGeometryShapes(model)
modelNode = loader.loadModel(model).find('**/+GeomNode')
return Entity.calcNodeCollisionShape(shape, modelNode, None)
@staticmethod
def calcNodeCollisionShape(shape, nodePath, root):
width, depth, height = Entity.calcNodeSize(nodePath)
transform = Entity.calcTransform(nodePath, root)
if shape == "box":
return [(BulletBoxShape(Vec3(width/2, depth/2, height/2)), transform)]
elif shape == "sphere":
return [(BulletSphereShape(width/2), transform)]
elif shape == "cylinder":
return [(BulletCylinderShape(width/2, height, 2), transform)]
elif shape == "cone":
return [(BulletConeShape(width/2, height), transform)]
elif shape == "hull":
geom = nodePath.node().getGeom(0)
hull = BulletConvexHullShape()
hull.addGeom(geom)
return [(hull, TransformState.makeIdentity())]
elif shape == "mesh":
geom = nodePath.node().getGeom(0)
mesh = BulletTriangleMesh()
mesh.addGeom(geom)
return [(BulletTriangleMeshShape(mesh, dynamic=False), TransformState.makeIdentity())]
else:
raise AttributeError('Collision type ' + str(shape) + ' does not exist!')
@staticmethod
def calcCollisionGeometryShapes(model):
root = loader.loadModel(model)
shapes = []
# Find any collider geometry and transform it into a collision shape
for shape in ["box", "sphere", "cylinder", "cone", "hull", "mesh"]:
for child in root.findAllMatches('**/collision_{0}_*'.format(shape)):
shapes = itertools.chain(shapes, Entity.calcNodeCollisionShape(shape, NodePath(child), root))
child.removeNode()
return shapes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment