There may be a ‘built-in’ way to ignore back-face intersections when ray-casting, but I couldn’t find it in the docs. Here’s how I did it:
# Initialize ray-cast collision so we can find the point of a mesh clicked on with the mouse def init_raycast(self): traverser = self.traverser = CollisionTraverser('mouse picker') handler = self.coll_handler = CollisionHandlerQueue() # make a new collision node pickerNode = CollisionNode('mouseRay') # attach it to the camera pickerNP = camera.attachNewNode(pickerNode) # set it to collide with default (i.e. everything, currently) pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) # make a new collision ray pickerRay = self.picker_ray = CollisionRay() # add it to the collision node pickerNode.addSolid(pickerRay) # add the pickerNode (via its path) & the handler to the collision traverser traverser.addCollider(pickerNP, handler) def get_mouse_pick(self) -> CollisionEntry: # Make sure the mouse is in the bounds of the panda3d window if not base.mouseWatcherNode.hasMouse(): return None # Get the mouse screen coordinates. mpos = base.mouseWatcherNode.getMouse() # set the direction of the collision ray based on the camera's settings # and the clicked screen-space position base.picker_ray.setFromLens(base.camNode, mpos.getX(), mpos.getY()) # kick off the collision detection base.traverser.traverse(base.render) handler = base.coll_handler num_entries = handler.getNumEntries() # if there were any collision entries... if num_entries > 0: # sort the entries in distance order (closest first) handler.sort_entries() # find the closest collision that isn't on a back-face index = -1 dot = 1 while dot > 0 and index < num_entries: index+=1 closest = handler.get_entry(index) # get the surface normal of the collision, relative to the camera surface_norm = closest.get_surface_normal(base.camera) dot = surface_norm.dot(base.picker_ray.direction) return closest return None
I’m curious if there’s a better way to do this. Let me know!