The problem seems to come from the camera rotation, if there is no rotation applied on the camera, the effect works fine and the ray collision detect the click and the exact location. However, if there is a rotation applied on the camera, this goes quickly wrong.
Here is a (ugly) test code that show the problem :
#!/usr/bin/env python
from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionTraverser, CollisionNode, DecalEffect, NodePath
from panda3d.core import TransparencyAttrib, TextNode, CardMaker
from panda3d.core import CollisionHandlerQueue, CollisionRay, BillboardEffect
from direct.task.Task import Task
base = ShowBase()
pickerRay = None
picker = None
pq = None
box = None
card = None
flipped = False
def click():
if base.mouseWatcherNode.hasMouse():
mpos = base.mouseWatcherNode.getMouse()
pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY())
picker.traverse(render)
if pq.getNumEntries() > 0:
pq.sortEntries()
np = pq.getEntry(0).getIntoNodePath()
print("Click on", np)
return Task.cont
def flip():
global flipped
base.camera.set_pos(0, 0, 0)
if not flipped:
base.cam.set_pos(0, 20, 0)
base.cam.set_hpr(180, 0, 0)
else:
base.cam.set_pos(0, 0, 0)
base.cam.set_hpr(0, 0, 0)
flipped = not flipped
picker = CollisionTraverser()
pq = CollisionHandlerQueue()
pickerNode = CollisionNode('mouseRay')
pickerNP = base.cam.attachNewNode(pickerNode)
pickerNode.setFromCollideMask(CollisionNode.getDefaultCollideMask())
pickerRay = CollisionRay()
pickerNode.addSolid(pickerRay)
picker.addCollider(pickerNP, pq)
picker.showCollisions(render)
label = TextNode('text')
label.set_text("CLICK ME")
cardMaker = CardMaker('card')
cardMaker.setFrame(label.getFrameActual())
cardMaker.setColor(0, 0, 0, 0)
card_node = cardMaker.generate()
card = NodePath(card_node)
tnp = card.attachNewNode(label)
card.setTransparency(TransparencyAttrib.MAlpha)
card.setEffect(DecalEffect.make())
card.setEffect(BillboardEffect.make((0, 0, 1), True, False, 0.0, base.cam, (0, 0, 0)))
card.reparent_to(render)
card.setCollideMask(CollisionNode.getDefaultCollideMask())
card.set_pos(-1, 10, 0)
box = loader.loadModel('box')
box.reparent_to(render)
box.set_pos(0, 10, 0)
box.setCollideMask(CollisionNode.getDefaultCollideMask())
box.setEffect(BillboardEffect.make((0, 0, 1), True, False, 0.0, base.cam, (0, 0, 0)))
base.accept("mouse1-up", click)
base.accept("mouse3-up", flip)
base.run()
You can use the right button to move the camera on the other side of the “scene” and rotate it. When H is 0, everything works as excepted, when H is 180, the collision solids are highlighted when no collision is detected.