getNumContacts() do not work

Hi,I am a novice, I tried to use getNumContacts () in bullet to detect collision.But it returns 0.I’m dying
print (self.world.contactTestPair(self.cone1NP.node(), self.body2NP.node()).getNumContacts())
It always returns 0.

Here is part of the code:

def processInput(self, dt):
if inputState.isSet(‘get’): print (self.world.contactTestPair(self.cone1 NP.node(), self.body2NP.node()).getNumContacts())

#Body2
visNP = loader.loadModel('models/arm.egg')
geom = visNP.findAllMatches('**/+GeomNode').getPath(0).node().getGeom(0)
mesh2 = BulletTriangleMesh()
mesh2.addGeom(geom)
shape = BulletTriangleMeshShape(mesh2, dynamic=True)
self.body2NP = self.worldNP.attachNewNode(BulletRigidBodyNode('body2'))
self.body2NP.node().addShape(shape)
self.body2NP.node().setMass(10)
self.body2NP.node().setInertia(Vec3(10000,10000,10000))
self.body2NP.setPos(0, 10, 0)
self.body2NP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(self.body2NP.node())
visNP.reparentTo(self.body2NP)
self.body2NP.setScale(6)

# Cone1 (dynamic)
radius = 6
height = 8
shape = BulletConeShape(radius, height, 2)
self.cone1NP = self.worldNP.attachNewNode(BulletRigidBodyNode('cone1'))
self.cone1NP.node().setMass(1.0)
self.cone1NP.node().addShape(shape)
self.cone1NP.setPos(-8,-8,3)
self.cone1NP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(self.cone1NP.node())

Does anyone know the reason? Plead for help

You can switch the model to a contour. The physical geometry may differ from the visible geometry.

It’s hard to see from just the code that you posted what might be going wrong. It may be helpful to post a more complete bit of code with the assets so that we can run it and debug it for ourselves.

Looking at the screenshot, I don’t see wireframe lines around the “arm”–could the process of adding geometry to that object’s Bullet-shape be failing?

Another question: if you simple move the two objects together, does either of them react physically at all?

Oh, and finally: do you have the Bullet world updating its physics simulation?

Sorry, I cannot upload attachments, here is my code:

#from pandac.PandaModules import loadPrcFileData
#loadPrcFileData(’’, ‘load-display tinydisplay’)

#loadPrcFileData(’’, ‘bullet-additional-damping true’)
#loadPrcFileData(’’, ‘bullet-additional-damping-linear-factor 0.005’)
#loadPrcFileData(’’, ‘bullet-additional-damping-angular-factor 0.01’)
#loadPrcFileData(’’, ‘bullet-additional-damping-linear-threshold 0.01’)
#loadPrcFileData(’’, ‘bullet-additional-damping-angular-threshold 0.01’)

import sys
import direct.directbase.DirectStart

from direct.showbase.DirectObject import DirectObject
from direct.showbase.InputStateGlobal import inputState

from panda3d.core import AmbientLight
from panda3d.core import DirectionalLight
from panda3d.core import Vec3
from panda3d.core import Vec4
from panda3d.core import Point3
from panda3d.core import TransformState
from panda3d.core import BitMask32

from panda3d.bullet import BulletWorld
from panda3d.bullet import BulletPlaneShape
from panda3d.bullet import BulletRigidBodyNode
from panda3d.bullet import BulletDebugNode
from panda3d.bullet import BulletConeShape
from panda3d.bullet import BulletConvexHullShape
from panda3d.bullet import BulletTriangleMesh
from panda3d.bullet import BulletTriangleMeshShape
from panda3d.core import CollisionSegment
from panda3d.core import CollisionRay
from panda3d.core import CollisionNode
from panda3d.core import CollisionHandlerFloor
from panda3d.bullet import BulletSliderConstraint
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletHingeConstraint
from panda3d.bullet import BulletContactResult
from panda3d.bullet import BulletGhostNode

global a,b,c,d
a=0;b=0;c=0;d=0
class Game(DirectObject):

def init(self):
base.setBackgroundColor(0.1, 0.1, 0.8, 1)
base.setFrameRateMeter(True)

base.cam.setPos(0, -20, 4)
base.cam.lookAt(0, 0, 0)

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

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

render.clearLight()
render.setLight(alightNP)
render.setLight(dlightNP)

# Input
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)

inputState.watchWithModifiers('up', 'w')
inputState.watchWithModifiers('down', 's')
inputState.watchWithModifiers('left', 'a')
inputState.watchWithModifiers('right', 'd')
inputState.watchWithModifiers('turnLeft', 'q')
inputState.watchWithModifiers('turnRight', 'e')
inputState.watchWithModifiers('dis', 'f')
inputState.watchWithModifiers('get', 'g')

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

# Physics
self.setup()

HANDLER

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

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

def toggleWireframe(self):
base.toggleWireframe()

def toggleTexture(self):
base.toggleTexture()

def toggleDebug(self):
if self.debugNP.isHidden():
self.debugNP.show()
else:
self.debugNP.hide()

def doScreenshot(self):
base.screenshot(‘Bullet’)

_TASK

def processInput(self, dt):
force = Vec3(0, 0, 0)
torque = Vec3(0, 0, 0)
torque1 = Vec3(0, 0, 0)

global a,b,c,d

if inputState.isSet('left'):    self.bodyNP.setPos(a, 5, -2);a=a+0.01
if inputState.isSet('right'):   self.bodyNP.setPos(a, 5, -2);a=a-0.01
if inputState.isSet('turnLeft'):  self.body1NP.setHpr(b, 0, 0);b=b+0.1
if inputState.isSet('turnRight'): self.body1NP.setHpr(b, 0, 0);b=b-0.1
if inputState.isSet('up'): self.body2NP.setHpr(b, 0, c);c=c+0.1
if inputState.isSet('down'): self.body2NP.setHpr(b, 0, c);c=c-0.1
if inputState.isSet('dis'): print (self.body2NP.getDistance(self.cone1NP))
#if inputState.isSet('get'): print (self.world.contactTest(self.coneNP.node()).getNumContacts())
if inputState.isSet('get'): print (self.world.contactTestPair(self.cone1NP.node(), self.body2NP.node()).getNumContacts())

def update(self, task):
dt = globalClock.getDt()
self.processInput(dt)
#self.world.doPhysics(dt)
self.world.doPhysics(dt, 5, 1.0/180.0)

return task.cont

def cleanup(self):
self.world.removeRigidBody(self.groundNP.node())
self.world.removeRigidBody(self.coneNP.node())
self.world.removeRigidBody(self.bodyNP.node())
self.world.removeRigidBody(self.body2NP.node())
self.world.removeRigidBody(self.body1NP.node())

self.world = None
self.debugNP = None
self.groundNP = None
self.coneNP = None
self.cone1NP = None
self.bodyNP = None
self.body1NP = None
self.body2NP = None

self.worldNP.removeNode()

def setup(self):
self.worldNP = render.attachNewNode(‘World’)

# World
self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug'))
self.debugNP.show()
self.debugNP.node().showWireframe(True)
self.debugNP.node().showConstraints(True)
self.debugNP.node().showBoundingBoxes(False)
self.debugNP.node().showNormals(True)

#self.debugNP.showTightBounds()
#self.debugNP.showBounds()

self.world = BulletWorld()
self.world.setGravity(Vec3(0, 0, 0))
self.world.setDebugNode(self.debugNP.node())

# Ground (static)
shape = BulletPlaneShape(Vec3(0, 0, 1), 0)
self.groundNP = self.worldNP.attachNewNode(BulletRigidBodyNode('Ground'))
self.groundNP.node().addShape(shape)
self.groundNP.setPos(0, 0, -2)
self.groundNP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(self.groundNP.node())

# Cone (dynamic)
radius = 0.6
height = 0.8
shape = BulletConeShape(radius, height, 2)
self.coneNP = self.worldNP.attachNewNode(BulletRigidBodyNode('cone'))
#self.coneNP.node().setMass(1.0)
self.coneNP.node().addShape(shape)
self.coneNP.setPos(5,5,-2)
#self.coneNP.setScale(2, 1, 0.5)
self.coneNP.setCollideMask(BitMask32.allOn())
#self.coneNP.node().setDeactivationEnabled(False)
self.world.attachRigidBody(self.coneNP.node())

# Cone1 (dynamic)
radius = 6
height = 8
shape = BulletConeShape(radius, height, 2)
self.cone1NP = self.worldNP.attachNewNode(BulletRigidBodyNode('cone1'))
self.cone1NP.node().setMass(1.0)
self.cone1NP.node().addShape(shape)
self.cone1NP.setPos(-8,-8,3)
#self.coneNP.setScale(2, 1, 0.5)
self.cone1NP.setCollideMask(BitMask32.allOn())
#self.coneNP.node().setDeactivationEnabled(False)
self.world.attachRigidBody(self.cone1NP.node())

# Body
visNP = loader.loadModel('models/body.egg')
geom = visNP.findAllMatches('**/+GeomNode').getPath(0).node().getGeom(0)
mesh = BulletTriangleMesh()
#mesh=BulletConvexHullShape()
mesh.addGeom(geom)
shape = BulletTriangleMeshShape(mesh, dynamic=True)
self.bodyNP = self.worldNP.attachNewNode(BulletRigidBodyNode('body'))
self.bodyNP.node().addShape(shape)
self.bodyNP.node().setMass(100)
self.bodyNP.node().setInertia(Vec3(100000000,100000000,100000000))
self.bodyNP.setPos(0, 0, -1)
self.bodyNP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(self.bodyNP.node())

visNP.reparentTo(self.bodyNP)
self.bodyNP.setScale(6)

#Body1
visNP = loader.loadModel('models/body1.egg')
geom = visNP.findAllMatches('**/+GeomNode').getPath(0).node().getGeom(0)
#mesh1 = BulletTriangleMesh()
mesh1=BulletConvexHullShape()
mesh1.addGeom(geom)
#shape = BulletTriangleMeshShape(mesh, dynamic=True)
self.body1NP = self.worldNP.attachNewNode(BulletRigidBodyNode('body1'))
self.body1NP.node().addShape(shape)
self.body1NP.node().setMass(10)
self.body1NP.node().setInertia(Vec3(100000000,100000000,100000000))
self.body1NP.setPos(0, 10, 0)
self.body1NP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(self.body1NP.node())
visNP.reparentTo(self.body1NP)
self.body1NP.setScale(6)

#Body2
visNP = loader.loadModel('models/arm.egg')
geom = visNP.findAllMatches('**/+GeomNode').getPath(0).node().getGeom(0)
mesh2 = BulletTriangleMesh()
#mesh2=BulletConvexHullShape()
mesh2.addGeom(geom)
shape = BulletTriangleMeshShape(mesh2, dynamic=True)
self.body2NP = self.worldNP.attachNewNode(BulletRigidBodyNode('body2'))
self.body2NP.node().addShape(shape)
self.body2NP.node().setMass(10)
self.body2NP.node().setInertia(Vec3(10000,10000,10000))
self.body2NP.setPos(0, 10, 0)
self.body2NP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(self.body2NP.node())
visNP.reparentTo(self.body2NP)
self.body2NP.setScale(6)

# Slider
frameA = TransformState.makePosHpr(Point3(0, 0, 0), Vec3(0, 0, 0))
frameB = TransformState.makePosHpr(Point3(0, 0, 0), Vec3(0, 0, 0))
slider =BulletSliderConstraint(self.bodyNP.node(),self.coneNP.node(),frameA,frameB, True)
slider.setDebugDrawSize(2.0)
slider.setLowerLinearLimit(0)
slider.setUpperLinearLimit(20)
#slider.setLowerAngularLimit(0)
#slider.setUpperAngularLimit(0)
self.world.attachConstraint(slider)

# Hinge1
pivotA = Point3(4, -1.55, 0)
pivotB = Point3(5.5, 1, 0)
axisA = Vec3(0, 0, 1)
axisB = Vec3(0, 0, 1)
hinge1 = BulletHingeConstraint(self.bodyNP.node(), self.body1NP.node(), pivotA, pivotB, axisA, axisB, True)
hinge1.setDebugDrawSize(2.0)
hinge1.setLimit(-90, 90, softness=0.9, bias=0.1, relaxation=1.0)
self.world.attachConstraint(hinge1)

# Hinge2
pivotC = Point3(3.55, 1, 3.9)
pivotD = Point3(3.55, 1, 3.9)
axisC = Vec3(0, 1, 0)
axisD = Vec3(0, 1, 0)
hinge2 = BulletHingeConstraint(self.body1NP.node(), self.body2NP.node(), pivotC, pivotD, axisC, axisD, True)
hinge2.setDebugDrawSize(2.0)
hinge2.setLimit(0, 30, softness=0.9, bias=0.1, relaxation=1.0)
self.world.attachConstraint(hinge2)

game = Game()
run()

oh,yes,only model and no wireframe lines,I do not know why.The arm directly through the cone,No collision.

Hmm… One possibility comes to mind: I note that you’re only adding one geom to the collider for your “arm”, and that’s simply the first NodePath in the graph-search results–are you sure that this geom is the appropriate one to serve as its collision? Might you perhaps be grabbing some other part of the model instead?

You mean this? It still does not work, maybe there is a problem with my egg file.

visNP = loader.loadModel(‘models/arm.egg’)
for geomNP in visNP.findAllMatches(’**/+GeomNode’):
geomNode = geomNP.node()
ts = geomNode.getTransform()
for geom in geomNode.getGeoms():
mesh.addGeom(geom, True, ts)
shape = BulletTriangleMeshShape(mesh, dynamic=True)
self.body2NP = self.worldNP.attachNewNode(BulletRigidBodyNode(‘body2’))

Maybe I can use a box instead of gemo, like this:

shape = BulletBoxShape(Vec3(0.5, 0.5, 0.5))
np = self.worldNP.attachNewNode(BulletRigidBodyNode(‘Box’))
np.node().setMass(1.0)
np.node().addShape(shape)
np.node().addShape(shape, TransformState.makePos(Point3(0, 1, 0)))
np.node().setDeactivationEnabled(False)
np.setPos(2, 0, 4)
np.setCollideMask(BitMask32.allOn())

self.world.attachRigidBody(np.node())

visualNP = loader.loadModel('models/arm.egg')
visualNP.reparentTo(np)

self.box = np.node()

However, the model is not in the middle of the box.I need to adjust other parameters.Or maybe my direction is wrong.

Hmm… Indentation aside, that does look more or less as I’d expect. You could always print out the geoms that your scene-graph search has returned, I suppose.

Well, it looks like you are offsetting the box by 1 unit in the y-direction. However, it is indeed also possible that the model isn’t centred as you’re expecting.

yes,i don’t know how to 123

OH,It is misplaced


They are not in the same location

Hmm… This may not be relevant, but looking at the fuller code that you posted earlier, I don’t see anything that looks like it would update your BulletWorld.

As described here, one generally runs a task that calls the “doPhysics” method of BulletWorld, thus updating the simulation.

It’s possible that this is the reason that you’re not getting any contacts. It may also account for the offset collision objects: you’re moving the visible object, but Bullet isn’t being updated and thus isn’t updating its collision objects.

I have added it in my fuller code

def update(self, task):
dt = globalClock.getDt()
self.processInput(dt)
#self.world.doPhysics(dt)
self.world.doPhysics(dt, 5, 1.0/180.0)

return task.cont

Ah, you’re right–I presumably missed it previously! Sorry about that! ^^;

In that case, the issue may well be with the model. Do you have a blend-file, or an egg-file, and if so are you willing to share it?

New users ca n’t upload attachments, so ask me boldly, how do I share files.

Dropbox, or another such file-hosting service, should do the job.

All right, looking at your model I do note that there is a slight offset in the model’s position. Whether it’s large enough to account for the offset that you’re observing, I’m not sure.