Background Image

A function to set a background image on your scene. Not sure how well this would work with anti aliasing or if this is even the best way of doing this but it works well enough for my purpose. If there’s a better way please point it out. Snippet in the public domain.

from pandac.PandaModules import Texture, TextureStage, CardMaker

def backgroundImage(image):
        bgTexture = loader.loadTexture(image) # Load the background texture
        
        # Make a texture stage for the screen contents and set it to a decal overlay mode
        screenStage = TextureStage('screen')
        screenStage.setMode(TextureStage.MDecal)
        
        # Make a textre for the screen and a buffer to pipe the screen content into
        screenTexture = Texture()
        buffer = base.win.makeTextureBuffer("screen buffer", base.win.getXSize(), base.win.getYSize(), self.screenTexture, True)
        bufferCam = base.makeCamera(self.buffer, lens=base.cam.node().getLens())
        
        # Create a card in render2d to cover up render. Multitexture the card with the BG texture and the screen content texture
        cm = CardMaker('screencard')
        cm.setFrameFullscreenQuad()
        cm.setHasUvs(True)
        screenCard = render2d.attachNewNode(cm.generate())
        screenCard.setTexture(bgTexture)
        screenCard.setTexture(screenStage, screenTexture)

Hmm, I wouldn’t use texture buffers for that. You’re rendering the main camera into a buffer, copying the texture to your RAM, then sending it to the GPU again? Sounds like it can be done MUCH faster.
What about doing it the other way around: render the background texture only, and putting its display region behind that of the main camera.
Here’s something that works:

b=OnscreenImage(parent=render2d, image="yourimage.png")
base.cam.node().getDisplayRegion(0).setSort(20)

(this disables you to use render2d for stuff that you actually want in front of the scene. Just create a secondary render2d for this, then. (look in ShowBase to see how it sets up a render2d.))

An alternative way, using the main camera, would be to place a card in front of the camera, and tell by using depth sorting to render it first. You might need to set automatic texture coordinates to MEyePosition for this.

This may be a noobish question, but I’m new in these seas.
I’m using the (sooo much thanks) method mentiones for a background image. It’s exactly what I was looking for and solves that problem on my game.
The thing is, I also need to put some graphics on top, some buttons and text. And I don’t know how to create (and reparent and whatnot) another render2d so I can place that stuff on top of all.
Can someone enlighten me on this

I appreciate any help.

We already have render2d and render2dp, which are two different 2-d scene graphs. You could use base.render2dp as your background scene graph, with:

base.cam2dp.node().getDisplayRegion(0).setSort(-20)

Or, you can use rdb’s second proposal, which is to parent the background image directly to the main 3-d camera, so you don’t need to muck around with render2d.

David

Great!!!, thanks for the quick response!

Just a little (around the hedge) question:
the render2dp is just an alternative (a second-in-line) of the original render2d or it is meant for an especific purpose?
It’s just for knowledge. I find it quite useful to have TWO render2d inside a scene, nevertheless sounds a little suspicious that there’s actually two. Quite a grateful coincidicence, but I suspect it’s actually there for a reason.

Also, as I first stated, I’m a complete noob in this 2d handling, can you orient me a little about that methos mentioned? I mean, how do I parent the image to the render (3-d camera)? with a card, I suppose. But then, how do I set the order to be the last thing in the render frame?

I really appreciate your answers.
And I’m amazed of the quickness of them.
Thanks a lot.

-Roger

render2dp was created to solve a problem similar to such as you describe. (Actually, it was the opposite problem: someone wanted a second 2-d display to appear on top of the original 2-d display. But it amounts to the same thing.) It’s not used by Panda itself, so you’re free to take it and use it for whatever purpose you like.

Right, for the 3-D solution you would parent a card to the camera, and position it at the appropriate distance to fill the screen (where that distance depends on your camera’s field of view). Panda provides some methods to change the render order, in particular card.setBin(‘background’, 0) to render it the first thing in the frame–see How to Control Render Order for more. You’d probably also want to turn off the depth write with card.setDepthWrite(False).

David

When displaying a background and a foregrond I simply turn on depth testing. It is disabled by default for render2d but if you enable it, you can simply but the background at the far end of the viewing frustrum by setting the y-value of the node.

The above is very helpful… Can anyone supply an example code snippet that implements it? (to give noobs a leg up)

Thanks,
Lars

Thank’s a lot!

I had the same need and I solved it using the OnscreenImage technic with render2dp, my code below:

def loadBackground(imagepath):
        ''' Load a background image behind the models '''

        # We use a special trick of Panda3D: by default we have two 2D renderers: render2d and render2dp, the two being equivalent. We can then use render2d for front rendering (like modelName), and render2dp for background rendering.
        self.background = OnscreenImage(parent=render2dp, image=imagepath) # Load an image object
        base.cam2dp.node().getDisplayRegion(0).setSort(-20) # Force the rendering to render the background image first (so that it will be put to the bottom of the scene since other models will be necessarily drawn on top)

I used this way over the rendering of a plane in the 3D render because my images can be of different sizes and I didn’t want to have to do tedious maths calculations to correctly place my background images each time I loaded one (plus it was less efficient since this method required to call a few more functions).

Also another thread I’ve found interesting but did not yet use: loadImageAsPlane(), a replacement for OnscreenImage:
[loadImageAsPlane())