I’m trying to create a small test program that would do picking and object highlighting but I’m having problems running it. I’ve had many error messages but this one I have been unable to solve:
…
File “picktest.py”, line 87, in hiliteTask
mousePicker.getObjHit(base.mouseWatcherNode.getMouse())
AssertionError: _has_mouse at line 55 of c:\temp\mkpr\panda3d-1.1.0\panda\src\tform\mouseWatcher.I
I’d appreciate it if anyone could help me with this. Here’s the code I’m using if you want to give it a try:
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.gui.DirectGui import *
from direct.task import Task
# Globals:
HILITECOL = Vec4(1, 1, 1, 1) # Vertex color of objects when highlighted
NORMCOL = Vec4(0.8, 0.8, 0.8, 1) # Vertex color of objects when not highlighted
ballModel = loader.loadModel('models/misc/sphere')
ballModel.reparentTo(render)
ballModel.setColor(NORMCOL)
#The class that handles the picking
class Picker:
def __init__(self):
self.picker = CollisionTraverser()
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.collisionNP = ballModel.attachNewNode(self.pickerNode)
self.picker.addCollider(self.collisionNP, self.queue)
self.pickedObj = None
def makePickable(self, newObj):
newObj.setTag('pickable', 'true')
def getObjHit(self, mpos):
self.pickedObj = None
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
mousePicker = Picker()
mousePicker.makePickable(ballModel)
#The last object that was highlighted
lastHiliteObj = None
#This function highlights an object that has been picked
def hiliteObj(pickedObj):
pickedObj.getParent().setColor(HILITE)
lastHiliteObj = pickedObj
def unhiliteObj():
lastHiliteObj.getParent().setColor(NORMCOL)
lastHiliteObj = None
def hiliteTask(task):
if lastHiliteObj == True:
unhiliteObj()
else:
mousePicker.getObjHit(base.mouseWatcherNode.getMouse())
hiliteObj(mousePicker.getPickedObj())
return Task.cont
#Our application class
class World(DirectObject):
def __init__(self):
taskMgr.add(hiliteTask, 'hiliteTask')
w = World()
run()
Oh, sorry, this was a dump question. I solved that error. All I had to do was add “if base.mouseWatcherNode.getMouse():” before I call the mousePicker.getObjHit(…) method. Well maybe this thread can still be useful to someone. If anyone is trying to get this code working (I still get errors) could you please post the final working version if you manage to get it to work correctly before I do.
Allright. Now I got it to run. I put the getMouse() calls inside a try-except block and it works. Only thing that bothers me is that if, while the program is running, the mouse is moved outside the Panda3d window area I get a long list of AssertionFailed: _has_mouse messages. I guess this is not a big deal, I got the program running after all. Now I just need to get the model to show up and see if it gets highlighted when the mouse howers over it.
Thankyou David. I finally managed to get this program to work. Here’s the final version of the code if anyone is interested, it does the picking and then highlights the picked object in green:
import direct.directbase.DirectStart
#for the events
from direct.showbase import DirectObject
#for collision stuff
from pandac.PandaModules import *
from direct.task import Task
class Picker(DirectObject.DirectObject):
def __init__(self):
#setup collision stuff
self.picker= CollisionTraverser()
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.pickerNP = camera.attachNewNode(self.pickerNode)
self.picker.addCollider(self.pickerNP, self.queue)
#this holds the object that has been picked
self.pickedObj=None
#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
mousePicker=Picker()
HILITECOL = Vec4(0.7,1,0.7,1)
NORMCOL = Vec4(1,1,1,1)
#load thest models
panda=loader.loadModel('panda')
teapot=loader.loadModel('teapot')
box=loader.loadModel('box')
#put them in the world
panda.reparentTo(render)
panda.setPos(camera, 0, 100,0)
panda.setColor(NORMCOL)
teapot.reparentTo(render)
teapot.setPos(panda, -30, 0, 0)
teapot.setColor(NORMCOL)
box.reparentTo(render)
box.setPos(panda, 30,0,0)
box.setColor(NORMCOL)
mousePicker.makePickable(panda)
mousePicker.makePickable(teapot)
mousePicker.makePickable(box)
lastHiliteObj = []
def setHiliteCol(pickObj):
pickObj.setColor(HILITECOL)
lastHiliteObj.append(pickObj)
def setNormCol():
lastHiliteObj[0].setColor(NORMCOL)
lastHiliteObj.pop()
def hiliteTask(task):
if lastHiliteObj != []:
setNormCol()
if base.mouseWatcherNode.hasMouse() == True:
if mousePicker.getObjectHit(base.mouseWatcherNode.getMouse()) != None:
setHiliteCol(mousePicker.getPickedObj())
return Task.cont
taskMgr.add(hiliteTask,'hiliteTask')
run()