Getting the position of a mouse click!

Hi all,
I’m still struggling to get my mouse point and click controls working. So I’ve decided to go right back to the basics.

I’ve written a program that is supposed to print out the position of a mouse click on a 3d model. For this, I’m loading two models from the ‘Picking’ tutorial (the ‘square.egg’ to represent my environment and the ‘bishop.egg’ which I eventually plan to make move to the clicked positions).

I’d really appreciate it, if somebody could take a look at this code and tell me if it’s doing what it’s supposed to do.

# This program prints the position (point 3) of a left mouse click on a 3d 
# model.

import direct.directbase.DirectStart 
from direct.showbase.DirectObject import DirectObject 
from pandac.PandaModules import * 

class Picker(DirectObject): 
    def __init__(self): 
        base.disableMouse()
        self.position = None  
        # Load an environment
        self.environ = loader.loadModel("MODELS/square")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)
        self.environ.setScale(15) # Scale the model up 15 times larger.
        self.bishop = loader.loadModel("MODELS/bishop")
        self.bishop.reparentTo(render)
        self.bishop.setPos(0, 0, 0)
        # Position the camera
        camera.setPos(0, -25, 10) # X = left & right, Y = zoom, Z = Up & down.
        camera.setHpr(0, -20, 0) # Heading, pitch, roll. 
        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) 
        self.accept('mouse1', self.printMe) 

    def getPosition(self, mousepos):
        self.pickerRay.setFromLens(base.camNode, mousepos.getX(),mousepos.getY()) 
        self.picker.traverse(render) 
        if self.queue.getNumEntries() > 0: 
            self.queue.sortEntries() 
            self.position = self.queue.getEntry(0).getSurfacePoint(self.environ) 
            return None

    def printMe(self): 
        self.getPosition( base.mouseWatcherNode.getMouse()) 
        print self.position  

p = Picker() 

run()

If I click on the grey area around the model, it prints ‘None’ (as it should, because I haven’t clicked on anything, right?).

When I click on different parts of the model, it prints a Point3 thingummy, with numbers that I think represent the X, Y, Z coordinates, like so:

[Point3 at: 81113176]
-0.0159621 -0.0712293 0
[Point3 at: 81106184]
-0.443531 0.436835 0
[Point3 at: 81113176]
-0.374774 -0.452085 0
[Point3 at: 81106184]
0.407363 -0.443407 0
[Point3 at: 81113176]
0.44033 0.355872 0

Is this correct? Have I gone about this the right way? The first program I tried (using getIntoNodePath from the picker example in the manual) printed the position of a nodepath, which didn’t seem to be the right thing to use for what I’m trying to achieve.

Thanks a lot.

Hmmm it sort of works. I did a little more experimenting and updated my code to look like this:

# This program moves a model to the position (point 3) of a left mouse click.

import direct.directbase.DirectStart 
from direct.showbase.DirectObject import DirectObject 
from pandac.PandaModules import * 

class Picker(DirectObject): 
    def __init__(self): 
        base.disableMouse()
        self.position = None  
        # Load an environment
        self.environ = loader.loadModel("MODELS/square")
        self.environ.reparentTo(render)
        self.environ.setPos(0, 0, 0)
        self.environ.setScale(15) # Scale the model up 15 times larger.
        self.bishop = loader.loadModel("MODELS/bishop")
        self.bishop.reparentTo(render)
        self.bishop.setPos(0, 0, 0)
        # Position the camera
        camera.setPos(0, -25, 10) # X = left & right, Y = zoom, Z = Up & down.
        camera.setHpr(0, -20, 0) # Heading, pitch, roll. 
        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) 
        self.accept('mouse1', self.moveToPosition) 

    def getPosition(self, mousepos):
        self.pickerRay.setFromLens(base.camNode, mousepos.getX(),mousepos.getY()) 
        self.picker.traverse(render) 
        if self.queue.getNumEntries() > 0: 
            self.queue.sortEntries() 
            self.position = self.queue.getEntry(0).getSurfacePoint(self.environ) 
            return None

    def moveToPosition(self): 
        self.getPosition(base.mouseWatcherNode.getMouse()) 
        self.bishop.setPos(self.position)
        return  

p = Picker() 

run()

When I run this code and click on my environment model, the bishop model does move, but only a couple of units in the general direction of the click. It’s not what I’m after, but I guess it’s a start.

Sigh I just want the bishop model to move to the position I clicked. Clearly I’ve done something wrong, but I don’t know what, anybody have any ideas?

Cheers

I am going to guess that the bishop moves about 1/15th towards the direction of the spot you picked, since the environment model was scaled up by 15. The coordiantes returned from the geometry of the collision would then be 1/15th smaller than what you want.

    def moveToPosition(self):
        self.getPosition(base.mouseWatcherNode.getMouse())
        self.bishop.setPos(self.position*15)
        return 

This will fix your immediate problem, but won’t apply to every situation.

There are other ways to handle this, such as parenting the bishop to the environment and scaling the bishop back down by 15. This way, the position returned by the picker would not have to be scaled in moveToPosition as above since the bishop already in the scaled coordinate system.

You brilliant man Russ! That’s fixed it!

Never in a milion years would it have occured to me that scaling the model had anything to do with this. Thankyou very, very much. I’m so incredibly relieved and happy :smiley:. This was a really tough challenge for me.

Well, I’m off to experiment with some different models (not scaled) to see if I can still get the same wonderful results.

Thanks heaps.