• OpenGL-非实时渲染与实时混合使用(有图有真相)


     视频教程请关注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440

    一个朋友在问(我也曾经遇到过这样的事情),尤其是在地理信息上面,地图上的一些矢量数据,以及

    影像数据,在地图没有变化(比如,缩放,平移,编辑)都是不需要绘制的,只有需要绘制的时候,在去绘制

    背景,想必,这个道理大家一定都很明白,但是OpenGL每次在绘制的时候是必须都要进入渲染管线进行绘制

    于是很多人就在想,是否可以把一些不需要变化的数据绘制到图片上,需要绘制的时候在进行重新绘制,就像

    windows DC一样呢?在OpenGL早期的版本中是没有把数据绘制到图片上这个功能的,当然在创建OpenGL

    的时候有这个选项,本人亲身试验过,那个效率,那个差呀,OpenGL初始化代码如下所示:

    PIXELFORMATDESCRIPTOR pfd = 
            {
                sizeof(PIXELFORMATDESCRIPTOR), 
                1, 
                PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SUPPORT_DIRECTDRAW | PFD_SWAP_EXCHANGE,
                PFD_TYPE_RGBA, 
                32, 
                8, 
                0,
                8,
                8,
                8,
                0,
                0, 
                0,
                32, 
                8,
                8,
                8, 
                8,
                24,
                8, 
                0, 
                PFD_MAIN_PLANE, 
                0,
                0, 
                0,
                0
            };

    红色的部分就是绘制到图片的选项。

      这种方案是不可取的,且不说他的效率问题,也满足不了目前的需求,在OpenGL1.1版本中,我们可以操作颜色缓冲区,或者

    叫帧缓冲区,在OpenGL中,至少存在两个缓冲区(当我们选择双缓冲绘制的时候),我们可以把数据绘制到缓冲区以后,在将

    缓冲区的数据直接的生成到纹理上,这样在把纹理绘制到背景中,这样,就可以有选择的去更新背景,而不是实时的去绘制背景

    数据,流程如下图所示:

    代码如下所示:

            glClearColor(1, 1, 1, 1);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
            glPushAttrib(GL_COLOR_BUFFER_BIT | GL_PIXEL_MODE_BIT); // for GL_DRAW_BUFFER and GL_READ_BUFFER
            glDrawBuffer(GL_BACK);
            glReadBuffer(GL_BACK);
    
            //! 绘制数据到GL_BACK缓冲区
            //! 绘制完成,将缓冲区内容cpopy到纹理
    
            glBindTexture(GL_TEXTURE_2D, textureId);
            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
            glBindTexture(GL_TEXTURE_2D, 0);
            glPopAttrib(); // GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
    
            //! 其他实时绘制内容

    当然,这个方式比较老土,但能实现我们想要的功能,而且效率也不赖。在新的OpenGL版本中实现这个过程有很多方式

    例如比较流行的就是FBO( Fram buffer object),帧缓冲区对象,其实就是我们上面的过程,所不同的是:上面我们用到

    的缓冲区是OpenGL给我们创建的,我们没有办法干预创建的过程,而后者则可以干预这个过程,我们可以自己去创建帧

    缓冲区,并使用它,当然这个需要更高的OpenGL版本,你需要做更多的事情。

    下面是创建Frame Buffer Object 的代码:

            glGenFramebuffersEXT(1, &targetId._FBOID);
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, targetId._FBOID);
    
            glGenRenderbuffersEXT(1, &targetId._RBOID);
            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, targetId._RBOID);
            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
    
            //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0);
    
            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, targetId._RBOID);
    
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    创建了以后,为了把数据绘制到上面,我们还需要给他绑定一个纹理,这个过程就像我们创建一个内存DC一样,如果没有和图片绑定

    绘制是没有任何意义的;

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, targetId._FBOID);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId._texture, 0);

    绑定纹理以后,以后的绘制,则是将数据绘制到纹理上了;代码中可以这样使用:

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, targetId->_FBOID);
    glBegin()
    ...
    glEnd()
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    在一种方式就是PBuffer:像素缓冲区,过程和这个相似。每一种方式都有自己的优点与缺点,在不同的场合用不同的方式

    做到最大化利用就对了。

    后续会专门对离屏渲染做专门的例程。感谢大家阅读,本人能力有限,错误,误导之处请指教。

  • 相关阅读:
    Nginx+uWsgi+Django+Python+MongoDB+mySQL服务器搭建
    Scott Guthrie's Blog on ASP.NET
    NPOI 读写excel
    用C#开发了一个Android 浏览器APP
    Windows 8 应用开发技术资源
    微软发布Sample Browser for Windows 8版:5000示例代码,"触手可及"
    依赖注入
    DIY 一套正版、免费、强大的 Visual Studio 2012 IDE
    基于JQuery EasyUI、Web Api的 ASP.NET MVC 代码生成插件
    深度剖析Byteart Retail案例:AOP 异常处理与缓存
  • 原文地址:https://www.cnblogs.com/zhanglitong/p/3241938.html
Copyright © 2020-2023  润新知