Panda3D Manual: Example for Clicking on 3D Objects
  <<prev top next>>     

This is a small example program for clicking on 3D objects. A panda, a teapot, and a cube will be on screen. When you click on the screen the console will tell you the nodePath of what you have clicked on. Its basically a watered down version the tutorial included with Panda 3D 1.0.4. However, all the functionality for picking 3D objects is encapsulated into the Picker class which you may feel free to use in your own code.

import direct.directbase.DirectStart
#for the events
from direct.showbase import DirectObject
#for collision stuff
from pandac.PandaModules import *


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.picker.addCollider(self.pickerNode, 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')

#put them in the world
panda.reparentTo(render)
panda.setPos(camera, 0, 100,0)

teapot.reparentTo(render)
teapot.setPos(panda, -30, 0, 0)

box.reparentTo(render)
box.setPos(panda, 30,0,0)

mousePicker.makePickable(panda)
mousePicker.makePickable(teapot)
mousePicker.makePickable(box)

run()

If you are running this example on Panda 1.1, replace line 24 with

self.picker.addCollider(self.pickerNP, self.queue)

Note: If you switch to another window, the mouse picker may not work when you are back to the panda window. If that happens, just select the perform some window action.If it still doesn't work still, replace printMe method with this:

  def printMe(self):
  	if base.mouseWatcherNode.hasMouse():
       	self.getObjectHit( base.mouseWatcherNode.getMouse())
       	print self.pickedObj
  <<prev top next>>