【问题标题】:How can I store the previously rendered from from an OpenGL Fragment Shader for later use?如何存储以前从 OpenGL 片段着色器渲染的内容以供以后使用?
【发布时间】:2018-02-03 21:34:45
【问题描述】:

我正在编写一个 FFGL 视频效果插件(使用 this shadertoy 端口)。我想存储以前渲染的帧以用于将来的计算。具体来说,我正在尝试制作相当于视频延迟的效果。

是否可以从片段着色器写入外部缓冲区,然后在稍后(例如,30 帧之后)使用该存储值?

【问题讨论】:

  • 当然。渲染到纹理,然后使用纹理作为输入。

标签: opengl glsl fragment-shader framebuffer


【解决方案1】:

您创建一个 FBO,并绑定它。你接下来渲染的任何东西都会出现在它上面。因此,如果您使用着色器,它仍然适用于默认 FBO。

这里有一些代码可以帮助你

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
    }
}

【讨论】:

  • 太棒了!谢谢!跟进问题。如果我想让纹理只填充每个 n 帧,有没有办法让着色器知道它自上次写入纹理以来已经过了多少帧?即我正在处理的效果需要参数化延迟值(以帧或时间为单位)。效果将在着色器的每个通道中使用存储的纹理,但只会在 n 帧后设置着色器。
  • 听起来您只想将 fps 渲染限制为 fbo。对吗?
  • 如果你只想每n帧绘制一次,你可以简单地做,n++; n%=10(或其他);如果(n == 0)绘制。我认为您实际上不能只告诉 opengl 这样做。你必须用你的实际语言来管理它。
猜你喜欢
  • 2016-11-05
  • 2017-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 2019-05-20
  • 1970-01-01
相关资源
最近更新 更多