在之前的章节,所有的物体都是中规中矩的显示的,只考虑了光照对物体的影响,那假设想要显示特殊的效果该怎么操作呢?例如马赛克风、将所有的物体都显示为黑白色,就像上世纪80年代的灰白电视一样,又或者说将整个场景渲染到一张泛黄的纸上以体现出年代感……

当然是修改着色器,事实上,很多地方都是这么做的,不过有些情况下,场景中的物体和对应的着色器都不少,若是想要整个场景(视口)体现出某个效果,就需要借助别的方法了

一、帧缓冲

为了解决这个问题,来学习帧缓冲吧,当有了目的之后才能更好的去理解和掌握。这一章相对之前要复杂一些,但是用一句简单的话来表达这个过程就是:想办法把当前的场景作为一张纹理存起来,然后再去全屏渲染这张“纹理”,在这种情况下,我们只需要给这张“纹理”编写一个独一无二的着色器就可以了

到目前为止,已经了解并使用了几种不同类型的屏幕缓冲:用于写入颜色值的颜色缓冲,用于写入深度信息的深度缓冲,以及允许我们基于一些条件丢弃指定片段的模板缓冲,这几种缓冲结合起来叫做帧缓冲(Framebuffer),它被储存于内存中

我们目前所做的渲染操作都是是在默认的帧缓冲之上进行的,当你创建了你的窗口的时候默认帧缓冲就被创建和配置好了(GLFW为我们做了这件事)

是的,GLFW已经为我们把这份代码写了,只不过我们是要自己再“客制化”一个想要的结果,OpenGL给了我们自己定义帧缓冲的自由,我们可以选择性的定义自己的颜色缓冲、深度和模板缓冲

和VBO、EBO一样,也可以用同样的方法创建和绑定一个FBO(帧缓冲)变量:

GLuint FBO;
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);

绑定的目标有以下3种,一般都是第一种:

  • GL_FRAMEBUFFER:绑定到目标后,接下来所有的读、写帧缓冲的操作都会影响到当前绑定的帧缓冲
  • GL_READ_FRAMEBUFFER:允许读取操作
  • GL_DRAW_FRAMEBUFFER:允许进行渲染、清空和其他的写入操作

构建一个完整的帧缓冲必须满足以下条件:如果不满足条件,则属于无效构建

  • 必须往里面加入至少一个附件(颜色、深度、模板缓冲)
  • 必须要有至少一个为颜色附件
  • 所有的附件都应该已经存储在内存中的
  • 每个缓冲都应该有同样数目的样本

样本是什么暂时不管,后面会有讲到,总而言之,因为帧缓冲的构建需要条件,所以我们在后面需要用 glCheckFramebufferStatus 函数来检查是否真的满足所有的条件,如果返回的值是 GL_FRAMEBUFFER_COMPLETE 就说明创建成功了

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;

二、离屏渲染

再回到帧缓冲区,这确实是一个很重要的概念,它在 OpenGL基础1:最简单的OpenGL例子 这一章中就被第一次提到了,里面介绍了 glfwSwapBuffers(window) 这一个函数

现在的显示器都是液晶显示器,而在以前主流的显示器都是显像管显示器(CRT)。不知道你还记不记得小学时的电脑课,那种大屁股显示器就是了,对于CRT显示器,显示的原理是这样的:要显示的图像经过CRT电子枪以极快的速度一行一行的扫描,扫描出来就呈现了一帧画面,随后电子枪又会回到初始位置循环扫描,形成了我们看到的图片或视频

而不管是CRT,还是液晶,它们都是从缓冲区中读取数据,其中缓冲区的数据就是通过 CPU 和 GPU 的计算给予的,如果在一帧时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变,这也是界面卡顿的原因

如果理解了双缓冲区,那么像理解离屏渲染就容易一些,对于双缓冲区,需要另外的缓冲区是为了一个用于显示的同时,另一个用于后台绘制,并且相互切换,这样我们就感觉不到绘制的这一过程。而对于离屏渲染,需要另外的缓冲区是为了二次处理,拿这次缓冲区的数据来为真正要显示的图像服务,当然啦,这个缓冲区大部分情况下由我们自己创建

在OpenGL中,GPU有2种渲染方式:

  • On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作
  • Off-Screen Rendering:离屏渲染,在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作

其实,离屏渲染是比较耗得,不止需要创建新的缓冲区,而且还需要多次切换上下文环境,先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,为了将离屏缓冲区的渲染结果显示到屏幕上还需要将上下文环境从离屏切换到当前屏幕,除了接下来我们手动创建FBO,以下几种情况也会触发离屏渲染:

  • shouldRasterize(光栅化)
  • masks(遮罩)
  • shadows(阴影)
  • edge antialiasing(抗锯齿)
  • group opacity(不透明)

可能有几个没有了解过,这些有机会的话都在后面讲,毕竟这也才开始理解离屏渲染

回到上面的帧缓冲代码,通过glBindFramebuffer方法,就相当于切换了当时的缓冲区,后续所有渲染操作将渲染到当前绑定的帧缓冲的附加缓冲中(即离屏渲染),如果当前激活的帧缓冲不是默认的帧缓冲,渲染命令对窗口的视频输出就不会产生任何影响,因此后面若是要渲染到主窗口,就必须要通过 glBindFramebuffer(GL_FRAMEBUFFER, 0) 来使默认帧缓冲被激活

当我们做完所有帧缓冲操作后,不要忘记删除帧缓冲对象:

glDeleteFramebuffers(1, &fbo);

好了,现在回到最初的目的:

想办法把当前的场景作为一张纹理存起来,然后再去全屏渲染这张“纹理”,在这种情况下,我们只需要给这张“纹理”编写一个独一无二的着色器就可以了

在此,目的就变成了:定义一个帧缓冲并且启用,然后走之前正常的渲染逻辑,这个时候,本应该在屏幕中展示的图象就被渲染到了自己定义的帧缓冲中,接下来,我们再想办法将帧缓冲中的数据转变为纹理,并且对这张纹理在默认帧缓冲中进行渲染显示

OpenGL基础33:帧缓冲(上)之离屏渲染相关推荐

  1. OpenGL学习脚印: 帧缓冲对象(Frame Buffer Object)

    写在前面 一直以来,我们在使用OpenGL渲染时,最终的目的地是默认的帧缓冲区,实际上OpenGL也允许我们创建自定义的帧缓冲区.使用自定义的帧缓冲区,可以实现镜面,离屏渲染,以及很酷的后处理效果.本 ...

  2. OpenGL基础知识梳理——Windows上搭建opengles运行环境

    1.概念介绍 1)OpenGLES 官方介绍:https://www.khronos.org/opengles/ OpenGLES(OpenGL for embeded systems)是用于嵌入式设 ...

  3. OpenGL 图形库的使用(二十五)—— 高级OpenGL之帧缓冲Framebuffers

    https://www.jianshu.com/p/d7066d6a02cc OpenGL 图形库的使用(二十五)-- 高级OpenGL之帧缓冲Framebuffers  刀客传奇 关注 0.2 20 ...

  4. OpenGL基础34:帧缓冲(中)之附件

    在之前的章节,所有的物体都是中规中矩的显示的,只考虑了光照对物体的影响,那假设想要显示特殊的效果该怎么操作呢?例如马赛克风.将所有的物体都显示为黑白色,就像上世纪80年代的灰白电视一样,又或者说将整个 ...

  5. OpenGL 帧缓冲Framebuffers

    OpenGL帧缓冲Framebuffers 帧缓冲Framebuffers简介 创建一个帧缓冲 纹理附件 渲染缓冲对象附件 渲染到纹理 后期处理 反相 灰度 核效果 模糊 边缘检测 帧缓冲Frameb ...

  6. OpenGL基础50:HDR

    一.HDR与LDR 由于显示器只能显示值为0.0到1.0间的颜色,因此当数据存储在帧缓冲(Framebuffer)中时,亮度和颜色的值也是默认被限制在0.0到1.0之间的,这个颜色范围即是LDR(Lo ...

  7. OpenGL基础43:抗锯齿

    一.走样与反走样 走样(Aliasing)就是锯齿化,反走样(Anti-aliasing)就是抗锯齿 只要玩过游戏,那么都应该对抗锯齿不陌生,不少游戏也都有关于抗锯齿的设置 如上图,放大的部分能很明显 ...

  8. OpenGL基础54:点光源阴影

    前置: OpenGL基础53:阴影映射(下) 一.万象阴影贴图 之前成功实现了平行光阴影,生成阴影贴图时使用的矩阵是正交矩阵,若是想要实现点光源的阴影效果,那么理论上只需要修改投影矩阵为透视矩阵就好了 ...

  9. OpenGL基础35:帧缓冲(下)之简单图像处理

    在之前的章节,所有的物体都是中规中矩的显示的,只考虑了光照对物体的影响,那假设想要显示特殊的效果该怎么操作呢?例如马赛克风.将所有的物体都显示为黑白色,就像上世纪80年代的灰白电视一样,又或者说将整个 ...

最新文章

  1. 【并发编程】Atomic与CAS
  2. 安装Axis2的eclipse插件后,未出现界面
  3. MVC、MVP、MVVM,我到底该怎么选?
  4. 海量数据库的查询优化及分页算法方案 1
  5. sqlite to mysql_SqliteToMysql
  6. 使用jenkins进行项目的自动构建部署
  7. Redis背后的故事
  8. PowerShell_9_零基础自学课程_9_高级主题:静态类和类的操作
  9. 【转】C#Socket编程详解(一)TCP与UDP简介
  10. AutoCAD VBA天圆地方的放样展开图
  11. erlang安装_消息中间件(八)- RabbitMQ - 安装
  12. jQuery高级部分笔记
  13. ubuntu下安装 memecache
  14. 罗振宇2021跨年演讲1:长大以后有多少责任和烦恼?
  15. PannerNode
  16. 趣学Python之弹球游戏第三阶段--上下反弹
  17. Struts2之result的配置
  18. Python3内置模块2-logging(转)
  19. 博途plc连接电脑_PLC编程中如何连接电脑将程序写入PLC
  20. 何宾 单片机原理及应用_单片机原理及应用课后答案讲解

热门文章

  1. 什么是python基础教程-最好的Python入门教程是?
  2. python编程是啥-学了Python编程之后,同是新手的他们做了什么?
  3. python爬虫实例100例-Python爬虫 实例
  4. python不会英语不会数学怎么自学-学习Python数学英语基础重要吗?
  5. 零基础适合学python吗-学Python需要什么基础知识?零基础可以学Python吗?
  6. 一张图学会python3高清图-用一张很丑的图学习Python数据可视化基础--热力图
  7. 学python要什么基础-学Python首先要学什么?
  8. python基础代码大全-Python字典及基本操作(超级详细)
  9. 手机网络游戏SDK集成指南
  10. 万能倍投计算器工具_一周总结上证A股市盈率14.83倍,这是机会还是风险呢?