Greetings,
I am getting really desperate to solve this issue and could really use some help. I have read several past solutions but I simply cannot get object selection to work.
Goal:
My goal is to be able to select or pick a 3D object using the mouse. As simple as it sounds, I have had no success implementing the recommended CollisionRay technique shown in:
https://docs.panda3d.org/1.10/python/programming/collision-detection/clicking-on-3d-objects .
Every time I click on any of the pickable objects no collision is registered.
I have also looked at similar problems like: Adding pickable objects during runtime , but I haven’t found a solution.
Here is the relevant code
def cursorWatch(mouseWasDown,objcmlist,task):
if base.mouseWatcherNode.hasMouse():
if base.mouseWatcherNode.isButtonDown(MouseButton.one()):
if not mouseWasDown[0]:
mouseWasDown[0] = True
myTraverser = CollisionTraverser()
myHandler = CollisionHandlerQueue()
pickerNode = CollisionNode('mouseRay')
pickerNP = base.camera.attachNewNode(pickerNode)
pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())
pickerRay = CollisionRay()
pickerNode.addSolid(pickerRay)
myTraverser.addCollider(pickerNP, myHandler)
mpos = base.mouseWatcherNode.getMouse()
pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
oocnp = NodePath("collision nodepath")
for obstaclecm in objcmlist:
obstaclecm.copycdnpTo(oocnp)
myTraverser.traverse(oocnp)
# Assume for simplicity's sake that myHandler is a CollisionHandlerQueue.
if myHandler.getNumEntries() > 0:
print("Collision Registered")
# Do stuff...
else:
mouseWasDown[0] = False
return task.again
taskMgr.doMethodLater(0.05, cursorWatch, "cursorWatch",
extraArgs=[self.mouseWasDown,self.objcmList],
appendTask=True)
In my code, I implemented a Task and task manager to monitor the state of the mouse so, whenever the user clicks we check if the mouse is over one of the objects on a list of pickable objects.
objcmlist is a python list filled with one or more CollisionModel objects. CollisionModel is a custom made class that lets me handle the collision nodes, nodepath and other necessary elements for loading a .stl file as a 3D object and handle possible collisions.
The method “copycdnpTo(oocnp)” basically lets me attach the associated object’s collision Node (self.__cdcn) to the oocnp NodePath as shown in the code:
def copycdnpTo(self, nodepath):
"""
return a nodepath including the cdcn,
the returned nodepath is attached to the given one
:param nodepath: parent np
:return:
"""
returnnp = nodepath.attachNewNode(copy.deepcopy(self.__cdcn))
returnnp.setMat(self.__objnp.getMat())
return returnnp
The object is surrounded by a collisionBox generated by the code:
#self.__objnp is a nodePath associated to the loaded object
self.__cdcn = self.__gencdboxcn(self.__objnp, radius = expand_radius)
def __gencdboxcn(self, pandanp, name='boxcd', radius=15.0):
"""
:param obstacle:
:return:
"""
cnp = CollisionNode(name)
bottomLeft, topRight = pandanp.getTightBounds()
center = (bottomLeft + topRight) / 2.0
# enlarge the bounding box
bottomLeft -= (bottomLeft - center).normalize() * radius
topRight += (topRight - center).normalize() * radius
cbn = CollisionBox(bottomLeft, topRight)
cnp.addSolid(cbn)
return cnp
Now, the collision box is correctly surrounding the objects as you can see in the following picture:
But every time I tried to click on the object boxes no collision is detected whatsoever. I started suspecting that the CollisionRay might be guilty so I decided to print out the Ray Data. So I added a print statement so every time I click on the screen the code does a print(pickerRay) and I got the following rays:
ray, o (-0.283897 1 0.119706), d (-14217.6 50080.2 5994.89)
ray, o (0.0566176 1 -0.125368), d (2835.42 50080.2 -6278.44)
ray, o (-0.317059 1 0.139118), d (-15878.4 50080.2 6967.04)
ray, o (0.129412 1 -0.118088), d (6480.97 50080.2 -5913.88)
…
Now, I am not exactly sure how the CollisionRay is supposed to work, but I find it really odd that the origin coordinates ALWAYS include a “1” in the, I assume Y-axis, If I understand correctly the CollisionRay is an infinite straight line that connects points “o” and “d” right? however, I tried showing that line in my worldbase and it just doesnt make sense:
Do you have any idea what could be the problem? Did I explain myself correctly?
Thanks for your time and reading this,
Hope you can help me.