Overlay 3D scene

Hi

I’m wondering if it’s possible to overlay a scene of 3D objects parented to a specific nodepath on top of my main 3D scene. An example is a 3D user-interface that uses models as interface elements.

I have tried creating two nodepaths to act as two separate scenes (both with separate lighting), but the objects in each still occupy the same 3D space and intersect with each other. This is probably a really obvious result for those who are more experienced with Panda3D. I understand why it happens, but I’m not sure where to go from here. I would need the “overlay scene” to stay fixed in the camera’s view, so it is always in view as any regular HUD would be.

Is such a scene graph setup possible, using two separate nodepath “scenes” to overlay the image of one scene onto the other in real-time, without the objects of the two intersecting with each other?

If the camera can see both scenes, it’s because you’ve parented both of them to the nodepath called render. If you don’t attach a nodepath to render, it won’t be seen by the default camera.

If you want an orthographic view, you can parent 3d objects directly into one of the 2d nodepaths already provided like render2d or aspect2d. It might take a bit of work to get your head around the coordinate system that these ones use, though.

If you need a perspective camera, you’re going to have to make a second camera and tell it to look at the nodepath not attached to the main scene graph, then work out some way to overlay it on top of the main screen.

Edit: Or a possible simpler solution would be to parent your UI nodepath to the camera itself. The camera is a nodepath, so you should be able to do this. The UI objects will follow the camera when it moves. Then you can ensure the UI is always drawn later by using render bins (panda3d.org/manual/index.php … nder_Order).

You can use DisplayRegions to achieve this. Overlay a second DisplayRegion on top of the existing one, connected to a different camera. Just like render2d is being rendered to a separate DisplayRegion than render is.

Be sure to clear the depth buffer before the second display region is being rendered (setClearDepth) otherwise your models will still intersect.

Thanks. The Display Region method worked and was fairly easy to set up.

Here’s my Scene code for others to use/improve on:

from panda3d.core import *

class SceneBase:
	def __init__(self, name, sortIndex):
		self.name = name
		
		# Display Region
		self.display = base.win.makeDisplayRegion()
		self.display.setClearDepthActive(True)
		self.display.setClearDepth(1)
		self.display.setSort(sortIndex)
		
		# Scene Node & Camera
		self.scene = NodePath('SCENE_' + self.name)
		self.camera = self.scene.attachNewNode(Camera('CAMERA_' + self.name))
		self.display.setCamera(self.camera)
		
		# Adjust Camera aspect ratio
		self.camera.node().getLens().setAspectRatio(float(self.display.getPixelWidth()) / float(self.display.getPixelHeight()))
		
		# Scene Properties
		self.visible = True
		
	# End scene
	def end(self):
		self.scene.removeNode()
		base.win.removeDisplayRegion(self.display)
	
	# Add PandaNode to scene
	def addNode(self, name):
		node = self.scene.attachNewNode(PandaNode(name))
		return node
	
	# Add Model to scene
	def addModel(self, filename):
		model = base.loader.loadModel('resources/models/' + filename)
		model.reparentTo(self.scene)
		return model
		
	# Add Point light to scene
	def addPoint(self, color=Vec4(1, 1, 1, 1), name='point'):
		point = PointLight(name)
		point.setColor(color)
		pointNP = self.scene.attachNewNode(point)
		self.scene.setLight(pointNP)
		return pointNP
	
	# Add Sun light to scene
	def addSun(self, color=Vec4(1, 1, 1, 1), name='sun'):
		sun = DirectionalLight(name)
		sun.setColor(color)
		sunNP = self.scene.attachNewNode(sun)
		self.scene.setLight(sunNP)
		return sunNP
	
	# Add Ambient light to scene
	def addAmbient(self, color=Vec4(.15, .15, .15, 1), name='ambient'):
		amb = AmbientLight(name)
		amb.setColor(color)
		ambNP = self.scene.attachNewNode(amb)
		self.scene.setLight(ambNP)
		return ambNP
	
	# Set/Toggle scene visibility
	def setVisible(self, visible=None):
		if visible in [True, False]:
			self.visible = visible
		else:
			self.visible = not self.visible
		
		if self.visible:
			self.scene.show()
		else:
			self.scene.hide()