-->

渲染OpenGL场景在固定管线图纸使用FBO来纹理渲染OpenGL场景在固定管线图纸使用FBO来纹理

2019-05-12 13:35发布

问题

我工作的开源游戏TORCS( http://torcs.sourceforge.net/ )。 游戏的绘图管线仍在使用OpenGL 1.3的固定功能管道(FFP)。

我尝试呈现游戏场景的FBO(帧缓冲区对象)的纹理,以做渲染的纹理一些后期处理。 我使用OpenGL 3.3。 在我的机器。

目前我已经设置了与在附纹理FBO GL_COLOR_ATTACHMENT0&1 (为了具有两个连续帧中的着色器可读2),并在附接的渲染GL_DEPTH_ATTACHMENT

结合FBO后执行游戏的渲染功能。 当我后来取消绑定FBO,并进行验证通过着色器程序的窗口写回纹理缓冲现场是不完整的。 更具体地讲,只有汽车的轮廓呈现,所以是轮胎和一些烟雾skidmarks。 这表明东西呈现给FBO的质感,但不是万能的 。 在别人没有纹理(树木,房屋,草等)呈现在FBO的质感。 这表明,我的纹理设置是不正确的,但不幸的是我的OpenGL的知识是有限的,这就是为什么我希望对你有所帮助。

值得一提的另一件事是,如果我离开了线glActiveTexture(GL_TEXTURE0); 绘图发生那么一个纹理将显示之前(即会被写入到FBO和写回窗口系统的帧缓冲,而不是车的轮廓。

代码

下面的代码显示的FBO(来自的初始化 https://en.wikibooks.org/wiki/OpenGL_Programming/Post-Processing ):

int screen_width = 640; 
int screen_height = 480;
/* Texture A*/
glGenTextures(1, &fbo_texture);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);

/* Texture B*/
//glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &fbo_texture_a);
glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);

/* Depth buffer */
glGenRenderbuffers(1, &rbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width, screen_height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

/* Framebuffer to link everything together */
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fbo_texture_a, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
    fprintf(stderr, "glCheckFramebufferStatus: error 0x%x", status);
    return 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

/* Compile and link shaders */
...

下面的代码显示了绘制发生: 编辑 :如果use_fbo=false那么一切都将被渲染直接作为前屏幕。 只有我所做的修改将在括号内。

if (use_fbo) 
{
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glPushAttrib(GL_VIEWPORT_BIT);
    glViewport(0,0,grWinw, grWinh);

    if (fbo_a) // drawing to fbo_texture_a
    {               
        glDrawBuffer(GL_COLOR_ATTACHMENT1);
        glActiveTexture(GL_TEXTURE0+11);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
    }
    else
    {
        glDrawBuffer(GL_COLOR_ATTACHMENT0);
        glActiveTexture(GL_TEXTURE0+12);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, fbo_texture);
    }
    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
}

glClearColor(0.7f, 0.1f, 0.1f, 1.0f); //clear with red to see what is drawn to the fbo
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

grScreens[0]->update(s, grFps);//THIS IS WHERE THE DRAWING HAPPENS unchanged from original drawing in TORCS

if (use_fbo) 
{
    glPopAttrib();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glEnable(GL_TEXTURE_2D);
    glDrawBuffer(GL_BACK);

    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glUseProgram(program_postproc);

    if (fbo_a) // drawn to fbo_texture_a
    {
        glUniform1i(uniform_fbo_texture, 11);        
        glUniform1i(uniform_fbo_texture_a, 12);        
        fbo_a=!fbo_a;
    }
    else
    {
        glUniform1i(uniform_fbo_texture, 12);        
        glUniform1i(uniform_fbo_texture_a, 11);        
        fbo_a=!fbo_a;
    }

    glEnableVertexAttribArray(attribute_v_coord_postproc);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_fbo_vertices);
    glVertexAttribPointer(
            attribute_v_coord_postproc, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glDisableVertexAttribArray(attribute_v_coord_postproc);
    glUseProgram(0); 
}

我希望我提供足够的信息让你帮我这。 任何建议表示赞赏。

编辑:我检查了一遍我的shader代码和FBO实现(用简图简化它只是一个附色等)和它的所有工作。 我觉得麻烦的是固定管线绘图和我实现FBO的混合...

编辑:这里有什么用use_fbo发生两个图像=真与假的(注:红色是明显的颜色FBO绑定后,看看有什么被渲染到FBO:从阴影没有开,撬痕)

我也试图以可视化的深度缓冲(改实施深度纹理附件),即使我线性化,没有信息。 我想深度不正确写入FBO无论是。

Answer 1:

当我和我的工作的发动机相比你的代码我看到这些分歧,试图逐一:

  1. 纹理格式

    您正在使用:

     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 

    因此合并所有到:

     GL_COLOR_ATTACHMENT0: GL_RGBA,GL_RGBA,GL_UNSIGNED_BYTE GL_COLOR_ATTACHMENT1: GL_RGBA,GL_RGBA,GL_UNSIGNED_BYTE 

    我在用:

     GL_COLOR_ATTACHMENT0 : GL_RGBA , GL_RGBA8 , GL_UNSIGNED_BYTE GL_DEPTH_ATTACHMENT : GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT16, GL_UNSIGNED_BYTE GL_STENCIL_ATTACHMENT: GL_STENCIL_INDEX , GL_STENCIL_INDEX8 , GL_UNSIGNED_BYTE 

    你需要改变纹理的内部像素格式指定位宽。 如果我没记错的很好,当我编写这(几年前),它不与刚工作GL_RGBA,GL_RGBA

  2. 深度目标

    我使用的depthstencil纹理方法一样color attachment我不使用任何RenderBuffer调用。 这并不意味着你的代码是错误的,但我的测试和作品。

  3. 纹理大小

    这是最有可能不再有效,因为大多数GFX显卡支持矩形纹理延伸,但OpenGL纹理应该是2分辨率的力量。 所以对于初学者尝试512x512 ,而不是你的640x480 ,并更改回来时,你的代码工作(只是要确定...)。

在情况下,它可以帮助这里是我的C ++ FBO class从矿山引擎采取了这样几件事你要比较的(因为它使用纹理和东西从发动机将不能单独工作):

//------------------------------------------------------------------------------
//--- Open GL FBO object ver 2.31 ----------------------------------------------
//------------------------------------------------------------------------------
#ifndef _OpenGL_FBO_h
#define _OpenGL_FBO_h
//------------------------------------------------------------------------------
class OpenGL_FBO
    {
public:
    GLuint fbo;
    int xs,ys;
    struct _dst
        {
        GLint txr;      // texture id
        GLenum dst;     // GL_DEPTH_COMPONENT, GL_COLOR_ATTACHMENT0, ...
        _dst()          { txr=-1; dst=GL_COLOR_ATTACHMENT0; }
        _dst(_dst& a)   { *this=a; }
        ~_dst()         {}
        _dst* operator = (const _dst *a) { *this=*a; return this; }
        //_dst* operator = (const _dst &a) { ...copy... return this; }
        };
    List<_dst> dst;

    OpenGL_FBO() { fbo=0xFFFFFFFF; xs=1; ys=1; dst.reset(); }
    OpenGL_FBO(OpenGL_FBO& a)   { fbo=0xFFFFFFFF; dst.reset(); *this=a; }
    ~OpenGL_FBO() { if (fbo!=0xFFFFFFFF) glDeleteFramebuffers(1,&fbo); }
    OpenGL_FBO* operator = (const OpenGL_FBO *a) { *this=*a; return this; }
    //OpenGL_FBO* operator = (const OpenGL_FBO &a) { ...copy... return this; }

    void resize(OpenGLscreen &scr,int _xs=-1,int _ys=-1)
        {
        int i;
        _dst *d;
        if (_xs<=0) _xs=scr.xs;
        if (_ys<=0) _ys=scr.ys;
//      for (xs=1;xs<_xs;xs<<=1);
//      for (ys=1;ys<_ys;ys<<=1);
        xs=_xs; ys=_ys; // ****

        if (fbo==0xFFFFFFFF) glGenFramebuffers(1,&fbo);
        glBindFramebuffer(GL_FRAMEBUFFER,fbo);
        for (d=dst.dat,i=0;i<dst.num;i++,d++)
            {
            scr.txrs.bind(d->txr);
            scr.txrs.resize(d->txr,xs,ys,1);
//          glFramebufferTexture2D(GL_FRAMEBUFFER,t->dst,GL_TEXTURE_2D,scr.txrs.names[d->txr],0);
            glFramebufferTexture(GL_FRAMEBUFFER,d->dst,scr.txrs.names[d->txr],0);
//          glCheckFramebufferStatus(GL_FRAMEBUFFER);
            }
        scr.txrs.unbind();
        glBindFramebuffer(GL_FRAMEBUFFER,0);
        }
    int add(OpenGLscreen &scr,int _dest=GL_COLOR_ATTACHMENT0)   // add txr to fbo
        {
        _dst d;
        OpenGL_TXR tmp;
        // colro atachments
        tmp.pixelformat =GL_RGBA;
        tmp.pixeliformat=GL_RGBA8;
        tmp.pixeltype=GL_UNSIGNED_BYTE;
        tmp.mag=GL_NEAREST;
        tmp.min=GL_NEAREST;
        if (_dest==GL_DEPTH_ATTACHMENT)
            {
            tmp.pixelformat =GL_DEPTH_COMPONENT;
            tmp.pixeliformat=GL_DEPTH_COMPONENT16;
//          tmp.pixeltype=GL_FLOAT;
            tmp.pixeltype=GL_UNSIGNED_BYTE;
            }
        if (_dest==GL_STENCIL_ATTACHMENT)
            {
            tmp.pixelformat =GL_STENCIL_INDEX;
            tmp.pixeliformat=GL_STENCIL_INDEX8;
            tmp.pixeltype=GL_UNSIGNED_BYTE;
            }
        tmp.xs=xs;
        tmp.ys=ys;
        tmp.zs=1;
        tmp._mipmap=0;
        tmp.txrtype=GL_TEXTURE_2D;
        d.txr=scr.txrs.add(tmp);
        d.dst=_dest;
        dst.add(d);
        return d.txr;
        }
    void bind(OpenGLscreen &scr)    // init fbo >> txr
        {
        // init and resize
        if (fbo==0xFFFFFFFF) glGenFramebuffers(1,&fbo);
        glBindFramebuffer(GL_FRAMEBUFFER,fbo);
        glViewport(0,0,xs,ys);
        scr.cls();
        }
    void unbind(OpenGLscreen &scr)
        {
        glBindFramebuffer(GL_FRAMEBUFFER,0);
        glViewport(scr.x0,scr.y0,scr.xs,scr.ys);
        }
    };
//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------
//--- end. ---------------------------------------------------------------------
//------------------------------------------------------------------------------

哪里:


OpenGLscreen scr是我的渲染引擎
scr.cls()是刚刚glClear和东西向初始化帧
scr.x0,y0,xs,ys是目标窗口的视
scr.txrs质感系统类(处理所有的纹理)喜欢add新的纹理加载/保存自/至文件,CPU / GPU以及更多的转换。

我也用我的动态列表模板,以便:


List<double> xxx; 是相同的double xxx[];
xxx.add(5); 增加了5到列表的末尾
xxx[7]访问数组元素(安全的)
xxx.dat[7]访问数组元素(不安全但快速直达)
xxx.num是阵列的实际使用的大小
xxx.reset()清除阵列和设置xxx.num=0
xxx.allocate(100)用于预分配空间100的项目

典型的用法是:

// [globals and init]
OpenGLScreen scr; // can ignore this
OpenGL_FBO fbo;
scr.init(window_handle); // init OpenGL stuff can ignore this
fbo.add(scr,GL_COLOR_ATTACHMENT0);
fbo.add(scr,GL_DEPTH_ATTACHMENT);
fbo.resize(scr,512,512);

// [render loop]
fbo.bind(scr);
// here render
fbo.unbind(scr);
// here you can use the textures fbo.dst[].txr

看看这里具体的例子:

  • 渲染充满复杂的多边形与大量使用OpenGL的顶点

粗为那些你被卡住旧的英特尔高清显卡不认为这将到期的司机工作的bug。 看到这个缓慢的解决方法:

  • OpenGL的规模单像素线


文章来源: Render OpenGL scene to texture using FBO in fixed function pipeline drawing