Sandwiching 3d render nodes between aspect2d nodes ?

Hi,

I am trying to setup a 3d scene with a 2d background and foreground.I used the Cardmaker interface to create my 2d background and foreground and attached them to the aspect2d render path. I put my 3d scene in the regular render path.

I then tried to setup the bins for all of the nodes so they render in a way that places the 3d stuff in between the 2d stuff.

Something like this:


cardMaker = CardMaker
#create the cards so the background and foreground take up the whole #screen
cardMaker.setFrame(-base.camLens.getAspectRatio(),
                                      base.camLens.getAspectRatio(),-1,1)

background = cardMaker.generate()
foreground = cardMaker.generate()

background.setTexture("myBgTexture.png")
foreground .setTexture("myFgTexture.png")

#so we can see through the foreground 
background.setTransperancy(1)
foreground.setTransperancy(1)

threeDstuff = loader.loadModel("myCool3Dscene")      

#put the 2d stuff in aspect2d, this makes it easier to position
#and it seems to make the texture transperancy non-crufty
background.reparentTo(aspect2d)
foreground.reparentTo(aspect2d)

#puth the 3d stuff in the render path so it is rendered w/perspective
threeDstuff.reparentTo(render)

#try to setup the bins so the 3d stuff renderes in between the 2d stuff
background.setBin("fixed",0)
threeDstuff.setBin("fixed",1)
foreground.setBin("fixed",2)

What seems to be happening is the items in aspect2d are being sorted correctly, but the items in render always appear behind. Does anyone have a suggestion for a better way of doing this (i.e. one that works)?

Thanks

Perhaps you should follow the progress of discourse.panda3d.org/viewtopic.php?t=2241

Since the graph scene found in the symbol “render2d” is already on top of the “render” scene, it provides the frontmost rendering layer. It also happens to be 2D, sp yay!, it’s done. Adding more 2D layers is quite simple. However, sorting them is another matter.

I have been able to add more 2D scene graphs that sort well amongst other 2D scenes, but I’ve yet to find a way to put the 3D layer in between.
Nobody in this universe seems to have a concrete solutions, all I’ve gotten so far are non-working snippets and pseudo code.

I’m thinking, perhaps there should be a repository of working code snippets. Maybe a forum or Wiki, somewhere to search topics and keywords and find actual code that does what you want. I’ll make sure to share my findings with the world if I ever manage to write working code.

This works :

from direct.actor import Actor

aspRatio=base.camLens.getAspectRatio()

####### background ########
farSmileys=NodePath('lil smileys')
for z in range(17):
    for x in range(17):
        lilS=loader.loadModelCopy('misc/lilsmiley')
        lilS.reparentTo(farSmileys)
        lilS.setScale(.1)
        lilS.setPos(-.8+x*.1,0,-.8+z*.1)
farSmileys.hprInterval(120,Vec3(0,0,-360)).loop()
far2d=base.makeCamera2d(base.win)
far2d.node().getDisplayRegion(0).setSort(1)
far2d.node().setScene(farSmileys)
far2d.node().getLens().setAspectRatio(aspRatio)

####### big smiley ########
bigSmiley=loader.loadModelCopy('misc/lilsmiley')
bigSmiley.setScale(1.4)
big2d=base.makeCamera2d(base.win)
big2d.node().getDisplayRegion(0).setSort(2)
big2d.node().setScene(bigSmiley)
big2d.node().getLens().setAspectRatio(aspRatio)

####### 3D ########
panda=Actor.Actor('panda-model',{'walk':'panda-walk4'})
panda.reparentTo(render)
panda.setScale(.05)
panda.actorInterval('walk',playRate=1.8).loop()
base.cam.setPos(50,-120,70)
base.cam.lookAt(panda)
base.cam.setP(base.cam.getP()+5)
base.cam.node().getDisplayRegion(0).setSort(4)

####### foreground ########
nearSmileys=NodePath('near smileys')
for z in range(17):
    for x in range(17):
        lilS=loader.loadModelCopy('misc/lilsmiley')
        lilS.reparentTo(nearSmileys)
        lilS.setScale(.05)
        lilS.setPos(-.8+x*.1,0,-.8+z*.1)
nearSmileys.hprInterval(30,Vec3(0,0,360)).loop()
near2d=base.makeCamera2d(base.win)
near2d.node().getDisplayRegion(0).setSort(3)
near2d.node().setScene(nearSmileys)
near2d.node().getLens().setAspectRatio(aspRatio)

The sorting is quite strange to me, don’t know why.

This does not:

        scene = NodePath("background scene")
        camera = base.makeCamera2d(base.win)
        camera.node().setScene(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)
        camera.node().getDisplayRegion(0).setSort(1)
        base.cam.node().getDisplayRegion(0).setSort(4)

I have no idea why. The card renders on top. The 3D scene only renders on top if I set the sort higher than render2d’s sort. I’m not even using render2d in my example, but if I lower the cam2d sort both “background scene” and “cam2d” will render behind the 3D. Odd, to say the least.
[/code]

Just with 1 2d scene and 1 3d scene, just like your code, try this:

  • 2d scene sort : 1
  • 3d scene sort : 10
    it will behave just like your experience, but this :
  • 2d scene sort : 1
  • 3d scene sort : 11
    will bring the 3d scene up.
    Seems we have to figure out what is exacly going on here.

I don’t get it at all. I can see no logic. Anyway, one interresting fact is that changing the base.cam2d sort will render the base.cam on top of both cam2d and the background 2d camera.

        camera.node().getDisplayRegion(0).setSort(1)
        base.cam2d.node().getDisplayRegion(0).setSort(2)
        base.cam.node().getDisplayRegion(0).setSort(3)

As logic would suggest, this puts camera in the bottom, cam2d in the middle and cam on top.
Now for the tricky part:

        camera.node().getDisplayRegion(0).setSort(1)
        base.cam2d.node().getDisplayRegion(0).setSort(3) # Note: on top!
        base.cam.node().getDisplayRegion(0).setSort(2)

LOGIC would suggest that this would put camera in the back, cam in the middle and cam2d on top, but in fact base.cam ends up on the bottom.

It seems that my 2d-camera is somehow sorted in a group of 2d cameras The default sort for base.cam2d is 10, which explains why you need to put your newly created 2D camera sort at 11. But how are they related? Why would the sort of base.cam2d matter to the newly created camera and it’s newly created graph scene?

Changing base.cam2d sort will effectively also change the sort of all your other 2D scene graphs. I have no idea why anybody would want this kind of behaviour, so I can’t rule out the possibility of a bug.

Perhaps base.makeCamera2d creates a camera that is somehow related to base.cam2d? Panda3D certainly is one of the more enigmatic API’s I’ve seen. :slight_smile:
Perhaps it’s time to read the source code…

From the source code:

////////////////////////////////////////////////////////////////////
//     Function: DisplayRegion::set_sort
//       Access: Published
//  Description: Sets the sort value associated with the
//               DisplayRegion.  Within a window, DisplayRegions will
//               be rendered in order from the lowest sort value to
//               the highest.
////////////////////////////////////////////////////////////////////

That is obviously not how it actualy behaves. It has got to be a bug. I use version 1.3.2 (the deb package).

Hi, I posted a bunch of code where I test this stuff here. But it basically amounts to the same as what you guys have but more complicated.

https://discourse.panda3d.org/viewtopic.php?t=2241

I tinkered w/the example that ynjh_jo sent. Which, by the way thank you for posting. And I got it working using 2d cards. I then went back and fixed my test. Basically the conslusion that I drew is that if you set the 3d layer’s sort to 11 everything works fine and logically, you can sort the 2d layers around the 3d layers the way you would expect. However, when I set the 3d layer’s sort to other values it’s basically a crap shoot of trial and error.

I’m not sure if there’s some numeric reason why this should be or if as jaeger says, just a panda bug. I tried having multiple 3d layers and that throws the whole thing out of whack as well ( maybe bin sorting is the answer here).

Anyways, this answers by question and gets me where I want to be for now, thanks for everyone’s help. Hopefully the panda maintainers can chime in on this issue w/some answers.

here’s the modifications I made to ynjh_jo’s code:

from direct.actor import Actor 
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
aspRatio=base.camLens.getAspectRatio() 

cm = CardMaker('background')
cm.setFrame(-aspRatio,aspRatio,-1,1)
####### background ######## 
farSmileys=NodePath('lil smileys') 

bg = farSmileys.attachNewNode(cm.generate())
bg.setTexture(loader.loadTexture("sample/envir-mountain1.png"))
bg.setTransparency(1)
print "Background "+str(bg)
farSmileys.hprInterval(120,Vec3(0,0,-360)).loop() 
far2d=base.makeCamera2d(base.win) 
far2d.node().getDisplayRegion(0).setSort(1) 
far2d.node().setScene(farSmileys) 
far2d.node().getLens().setAspectRatio(aspRatio)
#far2d.node().setActive(False)
print "Loaded background" 
####### big smiley ########
midSmileys= NodePath("midground")
print "Midground "+str(midSmileys)
mg= midSmileys.attachNewNode(cm.generate())
mg.setTexture(loader.loadTexture("sample/envir-tree2.png"))
mg.setTransparency(1)
mg.setPos(0,2,0)
big2d=base.makeCamera2d(base.win)

big2d.node().getDisplayRegion(0).setSort(2)
big2d.node().setScene(mg)

big2d.node().getLens().setAspectRatio(aspRatio)
#big2d.node().setActive(False)
print "Loaded big smiley"
####### 3D ######## 
panda=Actor.Actor('panda-model',{'walk':'panda-walk4'}) 
panda.reparentTo(render) 
panda.setScale(.05) 
panda.actorInterval('walk',playRate=1.8).loop() 
base.cam.setPos(50,-120,70) 
base.cam.lookAt(panda) 
base.cam.setP(base.cam.getP()+5) 
base.cam.node().getDisplayRegion(0).setSort(11)
#base.cam.node().setActive(False)
print "Loaded panda"
####### foreground ######## 
nearSmileys=NodePath('near smileys') 

print "Near Smiles "+str(nearSmileys)
mg= nearSmileys.attachNewNode(cm.generate())
mg.setTexture(loader.loadTexture("sample/envir-reeds.png"))
mg.setTransparency(1)

nearSmileys.hprInterval(30,Vec3(0,0,360)).loop() 
near2d=base.makeCamera2d(base.win) 
near2d.node().getDisplayRegion(0).setSort(13) 
near2d.node().setScene(nearSmileys) 
near2d.node().getLens().setAspectRatio(aspRatio)
#near2d.node().setActive(False)
run()

The documentation mentions nothing special about the sorting. It just says it sorts the order in which they are rendered, nothing extra.
The source code comment for DisplayRegion::set_sort says that it sorts the order of rendering from lowest to highest with the same window.

From the comments, documentation and tests I can only conclude that it is indeed a bug OR extremely thin, or even erronous, documentation. EIther way something has to be fixed.

I’m browsing the source code like crazy, I can’t find anything in GraphicsOutput (the window) that does any sorting.
Ultimately, the display regions are stored in a type named TotalDisplayRegions which is a pvector containing pointers to display regions.
Since I suck at C++ I used the help of freenode’s C++ channel, thank you excellent community, but to no avail.

I can see no comments or explicit code that would resort the display regions or render them the way they do. Nor am I skilled enough to see any bugs. I think we need to start a bug thread in some other forum, I’m getting nowhere with this problem.

I’m not aware of any bugs involving the sorting of DisplayRegions. They are sort in numeric order, from lowest to highest. I can’t imagine why setting a particular numeric sort value has any special effect.

One thing that does have a real influence here is the clearing of the depth buffer. If you don’t clear the depth buffer for each DisplayRegion, you may not get the results you expect, and in fact it may appear that buffers are being drawn in a different order than they actually are. (For instance, it may be the case that your 3-d objects appear to be on top of your 2-d objects, even though the 3-d objects are actually being rendering before the 2-d objects are drawn. Or vice-versa.)

You should be sure to pass clearDepth = 1 to each makeCamera() call, or set up the depth clear yourself with a call like:

displayRegion.setClearDepthActive(1)

David

Hmm I ended up fixing this issue myself by using the following code from the “setuprender2d” method in ShowBase.py to setup the nodepaths that I attached my camera to using “makecamera2d”. After I did this, everthing seemed to sort as expected. I’ll also check out the clear depth thing as well to make sure that doesn’t bite me in the butt later on down the road though.

# Create a new node path to attach the camera rig to
nodepath = NodePath(name)
nodepath.setDepthTest(0)
nodepath.setDepthWrite(0)
nodepath.setMaterialOff(1)
nodepath.setTwoSided(1)
#Create a camera to view this card with
newCamera2d = base.makeCamera2d(base.win,depth)
aspectRatio = base.getAspectRatio(base.win)
#By default make the aspect ratio the same as the default camera's aspect ratio
newCamera2d.node().getLens().setAspectRatio(aspectRatio)
#Set the camera up to view this scene
newCamera2d.reparentTo(nodepath)