Copying the Previous Frame's Output

In short, I’m trying to find a way to access and apply the texture produced by a FilterManager stage, without that texture then changing with the next frame.

Let me explain:

In my current project, rendering is a two-step process, handled by FilterManager: First, the scene is rendered into a texture, and then, second, that texture is placed on a full-screen quad which applies a shader to it, producing the final render.

So far, so good! All of this works.

Here, for reference, is the basic setup code:

        manager = FilterManager(self.win, self.cam)
        self.colourTex = Texture()
        self.colourTex.setWrapU(SamplerState.WM_clamp)
        self.colourTex.setWrapV(SamplerState.WM_clamp)
        depthTex = Texture()
        depthTex.setWrapU(SamplerState.WM_clamp)
        depthTex.setWrapV(SamplerState.WM_clamp)
        auxiliaryTex = Texture()
        auxiliaryTex.setWrapU(SamplerState.WM_clamp)
        auxiliaryTex.setWrapV(SamplerState.WM_clamp)
        self.postProcessQuad = manager.renderSceneInto(colortex = self.colourTex, depthtex = depthTex, auxtex = auxiliaryTex)
        inker = Common.getShader("inker")
        self.postProcessQuad.setShader(inker)
        # And shader-inputs are then applied in the subsequent code

Now, I have a class for which I want to implement a particular effect, one for which I want to take the most recent frame (either before or after the post-process shader), and apply it to a quad–but in this case, without it updating in subsequent frames.

And this is where I’m stuck.

I can easily enough just apply the colour-texture into which the first stage renders to my new quad–but then the texture naturally updates with each new frame.

I’ve tried calling “makeCopy()” on said colour-texture and using the return-value–but that seems to result in blackness.

I’ve also tried to implement the suggestion mentioned in this post, but I’m not clear on how to do that with FilterManager. My best guess was the following method:

def swapOutColourTex(self):
        tex = self.colourTex

        self.colourTex = Texture()
        self.colourTex.setWrapU(SamplerState.WM_clamp)
        self.colourTex.setWrapV(SamplerState.WM_clamp)

        self.postProcessQuad.setTexture(self.colourTex)

        return tex

With the returned texture being applied to my quad. But to no avail.

I also tried modifying the above method to instead call “renderSceneInto” anew, passing it the new colour-texture, once again to no avail.

So… How might this be done? Without copying the texture all the way back into RAM, that is. Or is it feasible at all when using FilterManager…?

make_copy() only copies the CPU data, so that doesn’t help you here.

The usual way to do this is called “ping-ponging”: you have two versions of the same texture, A and B. On frame 1, A is the input to the shader, and B is the output. On the next frame, you swap them around, so that B is the input and A is the output. Etc.

I think it might also be possible to do this with RTM_copy_texture instead of RTM_copy_ram, since it renders to an internal buffer and copies to a texture only at the end of rendering that scene. I’ve never tried it, but if someone could put together a simple sample in which it should work I’d be happy to look at what would be required to make it work.

Ah, fair enough! And thank you for so clarifying!

Hmm… How then does one swap out the textures?

As shown above, I’ve tried a version of that, with a method that creates a new texture, uses it to replace the old, and then returns that old texture. Said old texture is then applied to the geometry that has the relevant shader.

(In my case I don’t want to swap the textures every frame; in short, for a teleportation effect I’m “taking a screenshot” in order to make use of the pre-teleportation view.)

To be clear, I take it that this would involve abandoning FilterManager?

Erm, good questions. Swapping out the texture would also require calling addRenderTexture on the buffer to change the output texture, not just the input texture to the quad. Either method might require modifying FilterManager.

You should feel free to put in a feature request on GitHub with a clear use case and we might add a method or argument to accomplish this one way or another.

Hmm, fair enough, and thank you for the explanation!

I think that for now I’ll look for other effects to apply to my teleportation, then!