Hi,
I studied the doc and the demo that shows how to use picking. Seem quite easy, but I have to make picking on procedural generated nodes so I modified the demo to have a minimal test scenario.
This is the code:
import direct.directbase.DirectStart
#for the events
from direct.showbase import DirectObject
#for collision stuff
from pandac.PandaModules import *
def PlaneFactory( _l, _b, _w, _h ):
#creates format
vertexFormat=GeomVertexFormat.getV3n3c4()
# now the associated vertex data
vertexData = GeomVertexData('plane', vertexFormat, Geom.UHStatic)
#vertex writers ....
vertexWriter = GeomVertexWriter(vertexData, 'vertex')
normalWriter = GeomVertexWriter(vertexData, 'normal')
colorWriter = GeomVertexWriter(vertexData, 'color')
color = ( 1, 1, 1, 1 )
vertexWriter.addData3f( _l + _w, _b, 0 ) #A
normalWriter.addData3f( 0, 0, 1 )
colorWriter.addData4f( color[0], color[1], color[2], color[3] )
vertexWriter.addData3f( _l + _w, _b + _h, 0 ) #B
normalWriter.addData3f( 0, 0, 1 )
colorWriter.addData4f( color[0], color[1], color[2], color[3] )
vertexWriter.addData3f( _l, _b + _h, 0 ) #C
normalWriter.addData3f( 0, 0, 1 )
colorWriter.addData4f( color[0], color[1], color[2], color[3] )
vertexWriter.addData3f( _l, _b, 0 ) #D
normalWriter.addData3f( 0, 0, 1 )
colorWriter.addData4f( color[0], color[1], color[2], color[3] )
# primitives
primitives = GeomTriangles( Geom.UHStatic )
primitives.addVertices( 0, 1, 3 )
primitives.closePrimitive()
primitives.addVertices( 1, 2, 3 )
primitives.closePrimitive()
geom = Geom(vertexData)
geom.addPrimitive(primitives)
node = GeomNode('planeNode')
node.addGeom(geom)
return node
class Picker(DirectObject.DirectObject):
def __init__(self):
#setup collision stuff
self.picker= CollisionTraverser()
base.cTrav = self.picker
self.queue=CollisionHandlerQueue()
self.pickerNode=CollisionNode('mouseRay')
self.pickerNP=camera.attachNewNode(self.pickerNode)
self.pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
self.pickerRay=CollisionRay()
self.pickerNode.addSolid(self.pickerRay)
self.picker.addCollider(self.pickerNP, self.queue)
#this holds the object that has been picked
self.pickedObj=None
self.accept('mouse1', self.printMe)
#this function is meant to flag an object as being somthing we can pick
def makePickable(self,newObj):
newObj.setTag('pickable','true')
#this function finds the closest object to the camera that has been hit by our ray
def getObjectHit(self, mpos): #mpos is the position of the mouse on the screen
self.pickedObj=None #be sure to reset this
self.pickerRay.setFromLens(base.camNode, mpos.getX(),mpos.getY())
self.picker.traverse(render)
if self.queue.getNumEntries() > 0:
self.queue.sortEntries()
self.pickedObj=self.queue.getEntry(0).getIntoNodePath()
parent=self.pickedObj.getParent()
self.pickedObj=None
while parent != render:
if parent.getTag('pickable')=='true':
self.pickedObj=parent
return parent
else:
parent=parent.getParent()
return None
def getPickedObj(self):
return self.pickedObj
def printMe(self):
self.getObjectHit( base.mouseWatcherNode.getMouse())
print self.pickedObj
mousePicker=Picker()
#load thest models
panda=loader.loadModel('panda')
teapot=loader.loadModel('teapot')
box=loader.loadModel('box')
basePlane = PlaneFactory( 0, 0, 100, 100)
planeNode = NodePath(basePlane)
#put them in the world
panda.reparentTo(render)
panda.setPos(camera, 0, 50,0)
teapot.reparentTo(render)
teapot.setPos(panda, -30, 0, 0)
box.reparentTo(render)
box.setPos(panda, 30,0,0)
planeNode.reparentTo(render)
planeNode.setPos( panda, 0,0,-10)
mousePicker.makePickable(panda)
mousePicker.makePickable(teapot)
mousePicker.makePickable(box)
mousePicker.makePickable(planeNode)
run()
If you are familiar with the code, each picking action causes the name of the model to be printed. After adding the procedure generated plane, picking keeps working for the loaded models, but fails on the plane, causing ‘None’ to be printed. After doing some debug, I found that the queue is empty after the traverse operation. This is funny. Seems like the world is unable to recognize the plane at all.
Thanks for your help
Omar