def map3dToAspect2d(node, point):
“”“Maps the indicated 3-d point (a Point3), which is relative to
the indicated NodePath, to the corresponding point in the aspect2d
scene graph. Returns the corresponding Point3 in aspect2d.
Returns None if the point is not onscreen. “””

# Convert the point to the 3-d space of the camera
p3 = base.cam.getRelativePoint(node, point)
# Convert it through the lens to render2d coordinates
p2 = Point2()
if not base.camLens.project(p3, p2):
return None
r2d = Point3(p2[0], 0, p2[1])
# And then convert it to aspect2d coordinates
a2d = aspect2d.getRelativePoint(render2d, r2d)
return a2d

It hadn’t even occured to me to wonder if Panda3D had this feature. We have some effects that should apply in 2D space that we’ve been faking in 3D because they need to align with models in 3-space; this mechanism should allow us to simplify that code greatly.

I used this code in my program, but because of the definition of camLens.project(), my objects would pop out of existence when their centers moved off the edge of the screen. The following code will return a point in aspect2d even if when the 3d point is not on the screen. It never returns None.

Some possible issues… the nodal point of the lens would result in a division-by-zero, so I just return a point that would never render on the screen for my code. Also, an object behind the camera will probably have its screen position mirrored left-to-right and top-to-bottom.

def project_carelessly(lens, point):
''' Similar to Lens.project(), but never returns None. '''
# stolen vigourously from panda cvs src/gobj/lens.cxx,
# Lens::project_impl().
projection_mat = lens.getProjectionMat()
full = projection_mat.xform( VBase4(point[0], point[1], point[2], 1.0) )
if full[3] == 0.0:
# There is no meaningful projection for the nodal point of the lens.
# So return a value that is Very Far Away.
return (1000000.0, 1000000.0, -1000000.0)
recip_full3 = 1.0 / full[3]
return (full[0] * recip_full3,
full[1] * recip_full3,
full[2] * recip_full3)
def map3dToAspect2d(node, point):
"""Maps the indicated 3-d point (a Point3), which is relative to
the indicated NodePath, to the corresponding point in the aspect2d
scene graph. Returns the corresponding Point3 in aspect2d.
Returns None if the point is not onscreen. """
# Convert the point to the 3-d space of the camera
p3 = base.cam.getRelativePoint(node, point)
# Convert from camera 3d space to camera 2d space.
# Manual override.
p2 = project_carelessly(base.camLens, p3)
r2d = Point3(p2[0], 0, p2[1])
# And then convert it to aspect2d coordinates
a2d = aspect2d.getRelativePoint(render2d, r2d)
return a2d