Only certain nodes to be rendered using ortho

How do I add an ortho rendered card to use as backdrop behind the perspective rendations? aspect2d does exactly what I want, only it renders above the perspective scene.

If there’s a way to add ortho rendered nodes on any “level” that would be great information for me.

Panda can have multiple cameras that all render, one after the other, into the same window. By default, there are two cameras: base.cam, and base.cam2d. You can create more, if you want. Look at the function

ShowBase.makeCamera2d

You can control the render-order like this:

mycamera.getDisplayRegion().setSort(1)
base.cam.getDisplayRegion().setSort(2)
base.cam2d.getDisplayRegion().setSort(3)

Thanks a lot!

I’ve been making new scene graphs, sorting display regions and experimenting wildly. I’ll try this immediately.

Here’s my code:

    scene = NodePath("background scene")
    camera = base.makeCamera2d(base.win, 100, lens=OrthographicLens())
    camera.setPos(base.cam2d.getPos())
    camera.reparentTo(scene)
    cm = CardMaker("cm")
    cardNode = scene.attachNewNode(cm.generate())
    cardNode.setPos(0, 0, 0)
    cardNode.setScale(1)
    cardNode.setColor(1.0, 0.0, 1.0, 1.0)

If I attach the card to render2d instead of my background scene it renders fine, but my background scene just isn’t rendered. Why and how can I fix it?

Actually, there was a lot that didn’t work in that suggestion. Mainly the node paths don’t have getDisplayRegion methods, you need the base.camNode (and for some reason base.cam2dNode does not exist, I guess there’s some uninuitive scheme as to how they are named).

So far, all examples in both the manual and all forum posts I’ve been reading lack one, fundamental and very important feature: working code!
They crash or do not yield the desired results.

Where can I find a complete example of how to add new scene graphs and make then render in a specific order relative to the render and render2d scene graphs? I don’t understand why this would be so difficult to accomplish.

I’ve managed to add new scene graphs using extremely elaborate display region creations, texture buffers and other odd suggestions I’ve come by on the Internet, none give the desired results.
The closest I got was with the texture buffers, at least they rendered, albet in the wrong order and without showing anything behind it, but still rendered. That’s as close as I’ve gotten on this mission.

Should I ever come by a solution I will make sure to add a small tutorial on the subject. With working code, no less. :slight_smile:

Hi, I’ve been struggling w/this issue myself. I would like to have a 3d scene sandwiched between a foreground 2d scene and a background 2d scene. After reading the above posts I did a bit of research on my own and came up w/the following results.

Josh’s method works great but only when all of the cameras have the same lens type. This method does not seem to work in a mixed-lens environment.

Below is a detailed account of how I arrived at this conclusion. If anyone can help me figure out how to get this to work properly or has suggestions, I would be very grateful.

I did the following:

a.) Create 3 cameras that are all parented to sibling nodes in the scene graph. One for a foreground, midground and background layer.

b.) Mask out everything for each camera except for one nodepath so each camera only displays what’s in the nodepath it was assigned to (not sure why I had to do this, I thought having the above scene heriarchy would do this)

c.)Provide some controls that allow me to cycle the depth of the layers using Josh’s method and toggle the lenses between Perspective and Orthographic.

I noticed the following:
When all of the layers use the same lens, I have no problem configuring the layers in any order.

When I toggle the lenses to be mixed the orthographic layers ALWAYS appear in front of the perspective layers.

Below is my code: (Sorry for the length, I wanted to be thorough)
To run it you should just have to copy/paste it into a file and then copy the following files from C:\Panda3D-1.3.0\models\maps to a subfolder named “samples” in whatever dir you run this out of

“envir-reeds.png”
“envir-tree2.png”
“envir-mountain1.png”

The desired result is to have the reeds and the mountain cameras be Orthographic (2d) and the tree camera use a Perspective Lens.

The reeds should appear in front of the tree and the tree to appear in front of the mountain.

When this demo launches all of the cameras are Perspective and the affect appears to work. But if you press the [6] button to make the mountain camera use an Orthographic Lens, the mountains pop up in front of the trees and reeds.

Controls:
[1] Toggle the reeds camera on/off
[2] Toggle the tree camera on/off
[3] Toggle the mountain camera on/off

[4] Toggle the reeds camera lens to be Perspective/Orthographic
[5] Toggle the tree camera lens to be Perspective/Orthographic
[6] Toggle the mountain camera lens to be Perspective/Orthographic

[c] Cycle the depth of the cameras using Josh’s method

import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject

#hideFromCameras(...)
#uses drawmasks to hide a nodepath from two cameras.
#I had to do it this way bc. I couldn't figure out how
#to setup the mask so the node was only visible to one camera
#instead I had to specify all cameras that it wasn't visible to
def hideFromCameras(camera1,camera2,nodePath):
    camera1Bits = BitArray()
    camera1Bits.setWord(0,camera1.node().getCameraMask())
    camera2Bits = BitArray()
    camera2Bits.setWord(0,camera2.node().getCameraMask())
    showMask =~(camera1Bits|camera2Bits)
    hideMask = camera1Bits|camera2Bits
    clearMask = BitArray.allOff()
    nodePath.node().adjustDrawMask(showMask.getWord(0),
                                   hideMask.getWord(0),
                                   clearMask.getWord(0))

#cleanScene(...)
#Disables all of the standard cameras and removes them from the scene
#I wanted to try to set everything up from scratch w/none of panda's default stuff
def cleanScene():
    base.cam2d.node().setActive(0)
    base.cam.node().setActive(0)
    camera.hide()
    render.node().removeAllChildren()
    render.ls()

#class CameraTester
# Lab class for figuring out how to do interesting stuff w/ multiple cameras in panda
#
class CameraTester(DirectObject):
    #I'm setting up the scene so we can have 3 seperate cameras each pointing at a
    #different and totally independant part of the scene graph
    #to do this I create a new node for each camera to render and make them siblings to a one overarching node that's
    #attached to "render"
    
    def __init__(self):
        #First setup the heirarchy. One root node w/3 siblings (one for each camera to render)
        self._rootNode = PandaNode("root")
        self._foregroundRoot= PandaNode("foregroundRoot")
        self._midgroundRoot = PandaNode("midgroundRoot")
        self._backgroundRoot = PandaNode("backgroundRoot")
        self._rootNodePath = render.attachNewNode(self._rootNode )
        self._fgRootNodePath = self._rootNodePath.attachNewNode(self._foregroundRoot)
        self._mgRootNodePath = self._rootNodePath.attachNewNode(self._midgroundRoot)
        self._bgRootNodePath = self._rootNodePath.attachNewNode(self._backgroundRoot)
       
        #Now create some brand spanking new cameras one for each layer
        self._foregroundCamera = base.makeCamera(base.win,camName='camFor')
        self._midgroundCamera= base.makeCamera(base.win,camName='camMid')
        self._backgroundCamera= base.makeCamera(base.win,camName='camBak')
        
        #Make them render ONLY their little corner of the scenegraph
        self._foregroundCamera.reparentTo(self._fgRootNodePath)
        self._midgroundCamera.reparentTo(self._mgRootNodePath)
        self._backgroundCamera.reparentTo(self._bgRootNodePath)
        
        #Create some stuff for them to render
        #I probably don't need sperate cardmakers for each of these, but their here and it shouldn't matter
        self._foregroundCards= self.createCardMaker("foregroundCard")
        self._midgroundCards= self.createCardMaker("midgroundCard")
        self._backgroundCards = self.createCardMaker("backgroundCard")
        
        #Create each card using textures found in C:\Panda3D-1.3.0\models\maps
        self._foregroundCard =self.setupCard(self._foregroundCards,
                                            self._fgRootNodePath,
                                            "sample/envir-reeds.png")
        self._midgroundCard =self.setupCard(self._midgroundCards,
                                            self._mgRootNodePath,
                                            "sample/envir-tree2.png")
        self._backgroundCard =self.setupCard(self._backgroundCards,
                                             self._bgRootNodePath,
                                             "sample/envir-mountain1.png")
        
        #for some reason pointing each camera at its own nodepath didn't keep them from rendering the other parts of the
        #nodepath so I also explicitly hide everything else in the scene from the cameras exept their personal nodepath
        
        #Here I'm setting up each camera w/an exclusive mask
        fg = BitArray.bit(0) 
        mg = BitArray.bit(1)
        bg = BitArray.bit(2)
        print "foreground bits: "+repr(fg.getWord(0))
        print "midground bits: "+repr(mg.getWord(0))
        print "background bits: "+repr(bg.getWord(0))
        
        self._foregroundCamera.node().setCameraMask(fg.getWord(0))
        self._midgroundCamera.node().setCameraMask(mg.getWord(0))
        self._backgroundCamera.node().setCameraMask(bg.getWord(0))
        
        #Now use my helper function to hide each nodepath from the other cameras
        hideFromCameras(self._midgroundCamera,self._backgroundCamera,self._fgRootNodePath)
        hideFromCameras(self._foregroundCamera,self._backgroundCamera,self._mgRootNodePath)
        hideFromCameras(self._foregroundCamera,self._midgroundCamera,self._bgRootNodePath)
        
        #Press d to cycle the order of the different cameras
        self.accept("d", self.displaySortCycleCameras)
        
        
        #Turn the cameras on/off
        self.accept("1", self.toggleCameraActive,[self._foregroundCamera])
        self.accept("2", self.toggleCameraActive,[self._midgroundCamera])
        self.accept("3", self.toggleCameraActive,[self._backgroundCamera])
        
        #Toggle each camera between Perspective/ Orthographic
        self.accept("4", self.toggleCameraLens,[self._foregroundCamera])
        self.accept("5", self.toggleCameraLens,[self._midgroundCamera])
        self.accept("6", self.toggleCameraLens,[self._backgroundCamera])
        
    #Creates a card attached to a camera node and sets some default settings
    def setupCard(self,cardmaker,camera,texture):
        outputNode = camera.attachNewNode(cardmaker.generate())
        outputNode.setTexture(loader.loadTexture(texture))
        outputNode.setTransparency(1)
        outputNode.setPos(0, 2, 0) 
        outputNode.setScale(1)
        return outputNode
    
    #Prints stats on the sorting stuff done on this camera
    def printSortStats(self,camera):
        print "NodePath Sort: "+str(camera.getSort())
        print "Bin: "+str(camera.getBinName())
        print "Bin Order: "+str(camera.getBinDrawOrder())
        print "Display Region Sort: "+str(camera.node().getDisplayRegion(0).getSort())
        
    #Displays the current foreground , midground and background cameras
    def printCamStats(self):
        print "Foreground Camera is: "+repr( self._foregroundCamera)
        print "Midground Camera is: "+repr(self._midgroundCamera)
        print "Background Camera is: "+repr(self._backgroundCamera)
       
    #Sets up the display region sort order as per Josh Yolen's suggestion
    #To make the foreground camera appear in front of the others and the midground appear in front of the background
    #This method works fine as long as all of the cameras have the same lens type
    #When the cameras have different lenses however the orthographic lenses get rendered first always
    def displaysort(self):
        print "Display Depth Sorting cameras"
        self._foregroundCamera.node().getDisplayRegion(0).setSort(10)
        self._midgroundCamera.node().getDisplayRegion(0).setSort(20)
        self._backgroundCamera.node().getDisplayRegion(0).setSort(30)
        self.printCamStats()
        
    
    #Cycle the cameras and sort them using the displayRegion Method    
    def displaySortCycleCameras(self):
        self.cycleCameras()
        self.displaysort()
     
    #Cycles the cameras so foreground->midground->background->(new)foreground    
    def cycleCameras(self):
        #copy the current midground
        oldMid = self._midgroundCamera
        #Move the foreground to the midground
        self._midgroundCamera = self._foregroundCamera
        #Move the  background to the foreground
        self._foregroundCamera = self._backgroundCamera 
        #Move the old midground to the background
        self._backgroundCamera = oldMid

    #Use [1,2,3] to deactivate each camera. This proves that each scene is being rendered to
    #and independant camera
    def toggleCameraActive(self,camera):
        if(camera.node().isActive()):
            print "De-Activating Camera: "+repr(camera)
            camera.node().setActive(0)
        else:
            print "Activating Camera: "+repr(camera)
            camera.node().setActive(1)
    
    #Use [4,5,6] to toggle the lens of each camera
    def toggleCameraLens(self,camera):
        if(camera.node().getLens().isOrthographic()):
            print "Setting Camera: "+repr(camera)+" to Perspective Lens"
            camera.node().setLens(PerspectiveLens())
        else:
            print "Setting Camera: "+repr(camera)+" to Orthographic Lens"
            orthoLens = OrthographicLens()
            orthoLens.setFilmSize(2,2)
            orthoLens.setAspectRatio(base.camLens.getAspectRatio())
            camera.node().setLens(orthoLens)
            

    #Create a new cardmaker w/default settings
    def createCardMaker(self, name):
        cardMaker = CardMaker(name)
        cardMaker.setFrame(-base.camLens.getAspectRatio(),
                                 base.camLens.getAspectRatio(),
                                 -1,1)
        return cardMaker
        

    

cleanScene() #Hide/Disable all of the default stuff so I can play
camTester = CameraTester()
run()