Render To Texture - just once

Hi there,

I’m trying to render an actor to a texture to use it in the gui. Im using the code from the Manual:

self.offscreenBuffer = base.win.makeTextureBuffer("OffscreenBuffer", int(self.bufferResolution[0]), int(self.bufferResolution[1]))
self.offscreenBuffer.setSort(-100)
self.offscreenRenderTarget = self.offscreenBuffer.getTexture()
self.offscreenCamera = base.makeCamera(self.offscreenBuffer)

# set up camera
self.offscreenCamera.node().setScene(actor)
self.offscreenCamera.reparentTo(actor)

This works, however, I don’t want to render each frame into the texture, just once, to get a static texture of the actor and use it afterwards.

I tried (immediately after the code above)

taskMgr.step()
base.graphicsEngine.extractTextureData(self.offscreenRenderTarget, base.win.getGsg())
self.card.setTexture(self.offscreenRenderTarget)
            
base.graphicsEngine.removeWindow(self.offscreenBuffer)
self.offscreenBuffer = None
self.offscreenCamera.removeNode()

This seams to work, but “taskMgr.step()” sometimes shortly causes the screen to flicker once. Apart from that, it feels wrong to execute a whole frame just to do a small render pass.

Is there an easier way to execute just the one render pass that will render the actor into the texture so I can clean up immediately afterwards?

Thanks in advance,
Johannes

Yes, call base.graphicsEngine.renderFrame(). You might need to call it twice.

Hi,

I’ve tried that, but it results in the same flickering as taskMgr.step(). According to the API, renderFrame() renders the next frame in ALL registered windows.
I’d like to only execute the render to texture pass without refreshing the main frame buffer. Is there no way to do that?

Hmm, what about calling setActive(0) on the windows or cameras you don’t want to render.

I’m pretty sure there’s a way to make a buffer just render once, I’ve come across it before while doing buffer stuff but I can’t for the life of me find where I saw this. I’m pretty sure drwr knows though, I think I came across it when he pointed it out in a forum topic.

Edit:
I think I found it, you need to set the oneShot flag to true like so:

self.offscreenBuffer.setOneShot(True)

From the API ref of GraphicsOutput:

Yep, that is correct. Calling setOneShot() will ensure that the buffer only gets rendered to the texture once, and then it will hold that frame.

The documentation is a little bit misleading, though, because you are still responsible for calling removeWindow() on your buffer later, when you are done with the texture. Otherwise the buffer will not get cleaned up and will leak memory. But you can’t call it before you are done with the texture, because it may invalidate the texture when you call it (depending on the render mode Panda selected to perform render-to-texture).

David

Thanks, this seems to do the trick.
I’m calling removeWindow() (and clean up some other stuff like the camera) later using taskMgr.doMethodLater(), I hope this is the right way to do it.

Sounds perfect.

David