1
votes

I'm writing a FFGL video effect plugin (using this shadertoy port). I want to store a previously rendered frame to use in a future calculation. Specifically I am trying to make the equivalent of a video delay.

Is it possible to write to an external buffer from a fragment shader and then use that stored value at a later time (say, 30 frames later)?

1
Of course. Render to texture and then use the texture as input. – Nico Schertler

1 Answers

1
votes

you create a FBO, and bind it. whatever you render next goes onto it. so if you're using a shader, that still applies like on the default FBO.

here's some code to help you out

import java.nio.ByteBuffer;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL30.*;

public class FBO {
    public int fbo,tex,depth;

    public void delete() {glDeleteTextures(tex);glDeleteRenderbuffers(depth);glDeleteFramebuffers(fbo);}
    public void bindTexture() {glBindTexture(GL_TEXTURE_2D,tex);}
    public void bind() {glBindFramebuffer(GL_FRAMEBUFFER,fbo);}
    public static void unbind() {glBindFramebuffer(GL_FRAMEBUFFER,0);}

    public FBO(){ // create the fbo
        glBindTexture(GL_TEXTURE_2D,tex=glGenTextures()); // create texture, set correct filters
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);

        glBindRenderbuffer(GL_RENDERBUFFER,depth=glGenRenderbuffers()); // create buffer for depth

        glBindFramebuffer(GL_FRAMEBUFFER,fbo=glGenFramebuffers()); // create framebuffer
        glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,tex,0); // attach texture
        glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,depth); // attach depth
        unbind(); // incase not using immediately
    }

    public void resize(int w,int h) {
        glBindTexture(GL_TEXTURE_2D,tex); // update texture size
        glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,(ByteBuffer)null);
        glBindRenderbuffer(GL_RENDERBUFFER,depth); // update depth size
        glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,w,h);
    }

    public void render() {
//      glColor4f(1,1,1,1); // you may want to do these customly
//      glDisable(GL_BLEND);

        glBindTexture(GL_TEXTURE_2D, tex);
        Tess.begin();
        Tess.vertex(    0, height, 0, 0, 0);
        Tess.vertex(width, height, 0, 1, 0);
        Tess.vertex(width,      0, 0, 1, 1);
        Tess.vertex(    0,      0, 0, 0, 1);
        Tess.draw();
        // Tess btw, just manually handles verts and tex coords
        // that could be pure pipeline, or by vbo / vao / interleaved vbo
        // width / height are just the 2d size. could render for post processing
    }
}