Get the "selected" object.

Hello everyone,

In these past days I’ve though about how I could possibly get the mouse selected object in a game simply.

I’m still quite new to panda, but here is what I though I could do:
-use a collision ray,that points from the 3d camera pos to the 3d mouse pos, and find the “camera-nearest” occurence of collision, though that might be slow with big geometry, I must say I didnt try yet.
-make one of my parallel scenes, with no lights and no textures, a unique color is applied to every object, thus creating a segmentable image,(I think treeform already submitted this idea?) though it might be even slower, since it nearly doubles the drawing time.
-Map all my selectable objects in some 2D array, and find out, with the X,Y of the 3d mouse pos, what object(s) are in the selected “mini-area”, this might be tricky since multiple objects might be really close, thus in the same coordinate of this array.

So, what do you think?
are there better solutions already implemented/created?

Thanks for your time.

i’d go for rays. code should be in the samples and the manual.

Well, after some brief tests and much code reading, the best time I’ve done was with collision ray, though now I’d need either to:
-calculate a collision tube of of the vertices of an object
-or create a collision polygon ,for more precision, (out of the vertices?) with a geomnode.

I didnt find such things on the forum yet, I’ll continue searching, if anyone has code to propose he’s welcome!

I’m pretty sure you’re going to need to use spheres as the collision solids to wrap around your models. You can always use multiple spheres parented to the model with different positions to approximate the model’s shape if it’s really that important.

Collision rays are optimal for picking one object. If you need to drag select multiple objects- there’s code for this in the code snippets section.

I have used both concurrently- collision rays for single objects and drag selecting for multiple objects within the same program. I didn’t have any performance issues. Just be sure to stick with spheres for the collision solids.

Thanks a lot, I wonder what I would do without you, I can be so blind sometimes when searching for stuff… You know, when you search your glasses everywhere, just to realize you’re holding them in your hands!

Thanks, though I dont understand, the tutorial talks about GeomNodes, shouldn’t it be Collision Solids?

If you’re referring to “GeomNode.getDefaultCollideMask()”, then that, as I recall, allows the ray to collide with normal, visible geometry instead of special collision geometry. This, while probably less efficient than using collision geometry, has certain advantages, such as allowing one to click on an object without it having pre-defined collision geometry, and having more accurate collision geometry.

Of course, the decision of whether to have the ray intersect with normal geometry or collision geometry most probably depends on your situation - I’ve found use for both at different times, as I recall.

Parts of my,well, taken from examples, code:

        self.picker = CollisionTraverser( )
        self.queue= CollisionHandlerQueue( )
        self.pickerRay = CollisionRay( ) 
        self.pickerNode = CollisionNode( 'mouseRay' ) 
        self.solidIndex = self.pickerNode.addSolid( self.pickerRay )  
        self.pickerNode.setIntoCollideMask( GeomNode.getDefaultCollideMask() ) 
        self.pickerNP = self.pickerNode 
        self.picker.addCollider( self.pickerNP, self.queue)
        myNodePath.setTag('myObjectTag', '1')
        cNode = CollisionNode( name )
        cNodePath = myNodePath.attachNewNode( cNode )
        cNodePath.node().setFromCollideMask( GeomNode.getDefaultCollideMask())

I get no collision, nothing in my collision queue, don’t I need to register myNodePath somewhere? It would sound more logical…

Edit: ok I solved it, so what I needed is to set a From collide mask for my pickerNode and a into for my picked object,

If you’re creating collision geometry, you probably don’t want to use GeomNode.getDefaultCollideMask(). If you’re not creating specific collision geometry, and want to collide with normal geometry, then just set the ray’s

You seem to be setting the wrong mask here - I believe that you want the from mask, in other words the mask to use when considering a collision from the ray into the other object. Similarly, in the first-quoted section, you probably want to set the into mask if anything (although again you should probably not be setting the mask of a collision node to the mask of normal geometry).

Finally, are you calling your traverser’s traverse() method? If not, this should look something like this “self.picker.traverse()”, and probably be placed before you check your queue, I believe.

Note that, if I recall correctly, the default traverser, base.cTrav, is traversed automatically, whereas traversers of your own are not.

Now that I have followed your advice, I managed to pick objects though after experimenting with the camera I get very weird behaviors.

ive set,0,40), object that I know being at pos 0,0,0),
then when, I do ray.setFromLens(base.camNode, mpos x,y…), and the check for the ray’s origin, i get something like (0,-1.1912,2.14), and the direction is worse ,its like Vec3(0.1, 981.182…,622.123)…

Now, isn’t the origin the start of the ray? and the direction the normalized vector where it should point?,
here it should be something like (0,0,-1), and the origin should be (0,0,40), as I understand Panda’s rays

The ray’s origin and direction are computed to be relative to the camera. That’s why you parent the CollisionNode to the camera node, so they will inherit the camera’s transform; but still, if you query the ray directly, it will tell you its own, relative values. Thus, the camera’s setPos() and lookAt() have no effect on the values queried directly from the ray.

The ray, for the record, is drawn from the camera’s near plane to the camera’s far plane, along the line that corresponds to the (x, y) point you provide. If you provide (0, 0), it will be drawn directly down the center of the camera’s view, and the ray will be something like (0, 0.1, 0) to (0, 1000, 0).


I use #3 because i have a box i select with. I convert every object to 2d point and check if that point is in the 2d select box.