当前位置:网站首页>基于QT的OpenGL教程学习13 -帧缓冲

基于QT的OpenGL教程学习13 -帧缓冲

2021-01-23 16:23:03 小王爷_2019

教程:

帧缓冲

这一节中介绍了一个重要的概念,帧缓冲,可以用于实现一些比较酷炫的效果;

但是我觉得单单看这个教程可能并不能更好的理解,因此我自己在网上搜索了其他资料,其中:

Opengl帧缓存对象这一篇讲的就更加仔细一些,而且还在文章中贴了英文原文章,感兴趣的小伙伴可以看看;

在后续实现代码的过程中遇到了一个小问题,如果有看我前面文章的小伙伴可能注意到,我尽量使用的是QT自己封装后的类来实现这些功能,但是这次却遇到了一个小问题,下面简单说一下;

教程中,应用FBO的方式是将一个自己生成的空白纹理实例attach到FBO实例上,这样绑定FBO并执行完渲染命令后会将内容渲染到我们attach的这个空白纹理对象上,这个时候我们再去按照常规路径去渲染这张纹理;但是如果使用Qt中的QOpenGLFrameBufferObject来实现FBO的话,你会发现没办法自己创建一个纹理实例attach到QOpenGLFrameBufferObject的实例上。但是QOpenGLFrameBufferObject提供了texture()方法帮助大家获取渲染生成的纹理;

那么只要我们直接去渲染这个纹理就可以了;但是texture() 返回的是一个textureid并不是QOpenGLTexture的实例,所以我们无法像之前那样纯用QT封装的纹理来绘制,只能用原生函数和QT封装对象函数混合的方式来渲染;

这个问题我去翻阅了QT的官方论坛,有人给出的解释是,QOpenGLTexture 出现的比QOpenGLFrameBufferObject 晚,所以没有办法直接获取QOpenGLTexture类型的纹理,不知道QT6 中是不是修正了这个问题;

下面简单贴一下渲染部分的代码,其他的源码可以去git中查看:

void MyGLWidget::paintGL()
{

    bool result = fbo->bind();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable( GL_CULL_FACE);
    switch (curdepthfunc) {
    case DEPTHFUNC::LESS:
    {
        glDepthFunc(GL_LESS);
        break;
    }
    case DEPTHFUNC::ALWAYS:
    {
        glDepthFunc(GL_ALWAYS);
        qDebug()<<"always";
        break;
    }
    case DEPTHFUNC::NEVER:
    {
        glDepthFunc(GL_NEVER);
        qDebug()<<"never";
        break;
    }
    case DEPTHFUNC::EQUAL:
    {
        glDepthFunc(GL_EQUAL);
        break;
    }
    case DEPTHFUNC::LEQUAL:
    {
        glDepthFunc(GL_LEQUAL);
        break;
    }
    case DEPTHFUNC::GREATER:
    {
        glDepthFunc(GL_GREATER);
        break;
    }
    case DEPTHFUNC::NOTEQUAL:
    {
        glDepthFunc(GL_NOTEQUAL);
        break;
    }
    case DEPTHFUNC::GEQUAL:
    {
        glDepthFunc(GEQUAL);
        break;
    }

    }
    plane->Render();
    glEnable( GL_CULL_FACE);
    QVector<Shape*>::iterator i;
    for(i=cubevec.begin();i!=cubevec.end();++i)
    {
        (*i)->Render();
    }

    //排序
    std::map<float,QVector3D> sorted;
    for(int j=0;j<windows.size();j++)
    {
        QVector3D disvec=m_camera->Position-windows[j];
        float distance=disvec.lengthSquared();
        sorted[distance] = windows[j];

    }
     glDisable(GL_CULL_FACE);
    int count=0;
    for(std::map<float,QVector3D>::reverse_iterator  it=sorted.rbegin();it!=sorted.rend();++it)
    {
        grassvec[count]->SetTranslateVec(it->second);
        grassvec[count]->Render();
        count++;
    }

    if(result)
    {
        GLuint textureid=fbo->texture();
        fbo->release();
      //   QImage img= fbo->toImage();
      //   img.save("rendertotexture.jpg");
        m_program->bind();
        {
         // bind textures on corresponding texture units
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureid);
        glUniform1i(m_program->uniformLocation("screenTexture"), 0);
        QMatrix4x4 view=m_camera->GetViewMatrix();
        m_program->setUniformValue("view", view);

        QMatrix4x4 projection;
        projection.perspective(m_camera->Zoom, 1.0f * this->width() /this->height(), 0.1f, 100.0f);
        m_program->setUniformValue("projection", projection);

        QOpenGLVertexArrayObject::Binder vaoBind(m_vao);
        glDrawArrays(GL_TRIANGLES, 0, 6);


        }
       m_program->release();

    }
    glEnable(GL_DEPTH_TEST);
}

在以上代码中,我们可以看到,首先绑定FBO,然后去执行我们之前文章中写过的渲染操作,此时,渲染结果并不是渲染到屏幕上,而是渲染到我们创建的FBO中,如果这个时候使用:

QImage img= fbo->toImage();
img.save("rendertotexture.jpg");

我们可以得到一张当前渲染好的图像;

然后我们准备将FBO中存储的渲染结果渲染到我们的屏幕上,这个时候,首先要记得

  fbo->release();

这样我们再次执行渲染操作的时候,才会渲染到我们的屏幕上;

FBO部分基本用法就是这样了,教程中还给我们提供了一些实现后处理的方式;也就是针对我们获取到的纹理,我们可以在着色器中实现对这个纹理的一些图像处理操作;这部分内容就不详细贴了,我觉得应该单独开一个分支去介绍利用着色器实现图像处理;

源码:

提交信息:FBO

尽管我的文章阅读量挺低的,但是我还是想继续下去,一方面算是做笔记,opengl断断续续用了很久了,但是因为涉及到概念比较多,一旦中间断一段时间,再捡起来有些概念又要再回忆一遍,自己在其他地方记录的笔记,时间一久就变得特别杂乱,现在记录上博客中,感觉清晰很多,而且也是希望能有人有时间看到我代码中的问题的话,能告诉我一下;

到这个FBO这部分,我突然想起另外一个教程,GLSL相关的,有时间把那个也写一下;顺便下次更新之前,把已经有的代码整理一下,现在这个实验工程中已经有大量的重复代码了,再不整理我自己都看不下去了;(*/ω\*)

版权声明
本文为[小王爷_2019]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/2009228/blog/4921634