Mapping a point in render to aspect2d

Thanks to DRose for helping me out on this.

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

That is exceedingly cool :slight_smile:

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.

Thank you for sharing; this is awesome!

Take care,
Mark

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

~ Happy Coding.

Question, does object.getPos(base.camera) not return the same thing? Or am I wrong?

That returns the object in the 3-d space of the camera, which is not the same thing as the object in the 2-d space of the camera’s film.

David