1.离屏渲染使用场景:

1.游戏中的小地图;
2.画中画场景;
3.游戏中观战模式的多场景场合;
4.镜像场景——比如汽车游戏当中的倒车镜,采用的就是离屏渲染技术,在倒车镜上安装一个摄像机,把摄像机渲染的数据保存到FBO(Frame Buffer Object帧缓冲区),再从FBO提取生成纹理进行贴图到倒车镜;

2.与实时渲染的优缺点比较:

离屏渲染:
1.在变化的场景下,因为离屏渲染需要创建一个新的缓冲区,且需要多次切换上下文环境,所以代价很高;
2.在稳定的场景下,离屏渲染可以采用一张纹理进行渲染,所以性能较当前屏渲染有较大提升。
从上述对比可以看出,在稳定场景下使用离屏渲染的优势较大。
(此处优缺点对比来源于高德地图技术博客:离屏渲染在车载导航中的应用)

3.明确概念:

3.1 帧缓冲FBO(Frame Buffer Object);

在OpenGL渲染管线中,几何数据和纹理最终都是以2d像素绘制到屏幕上。最后一步的渲染目标在OpenGL渲染管线中被称为帧缓存(Frame Buffer Object即FBO)帧缓存是颜色缓存、深度缓存、模板缓存、累积缓存的集合。 默认情况下, OpenGL使用的帧缓存是由窗体系统创建和管理的。
下图展示了FBO和renderbuffer object与texture object之间的关系。从图中我们可以看出:多个renderbuffer object和texture object可以通过挂接点挂接到FBO上。需要主要的是FBO并没有实际存储数据的地方,它只是一个数据的壳,它只有挂接点,说白了就是两个缓冲区指针的集合

3.2 渲染缓冲RBO(Renderbuffer Object)
就像纹理图像一样,渲染缓冲区对象是实际的缓冲区,例如字节,整数,像素或其他的数组。但是,不能直接读取renderbuffer对象。这给它带来了一个额外的优势,那就是OpenGL可以进行一些内存优化,从而使其性能优于纹理,以便在屏幕外渲染到帧缓冲区。

3.3 FrameBuffer,RenderBuffer,Texture区别


**Color Attachment:**存储的是纹理图片颜色值,实质上纹理图片颜色值属于颜色附着点的一种
**Depth Attachment:**指向的是深度缓冲区和颜色缓冲区
**Stencil Attachment:**指向的是模版缓冲区
**RenderBuffer Objects :**渲染缓冲区对象,无论是纹理、图片、颜色、深度缓冲区、模版缓冲区都存在这个对象
FrameBuffer 上的附着点其实相当于内存地址,它并没有存储实质的内容,只是三个附着点或三个内存地址在FrameBuffer Objects例如color Attachment ,它仅仅是附着在FrameBuffer身上;
差异对比源自这里

3.4 FrameBuffer,RenderBuffer使用场景
Renderbuffer对象可以在屏幕外的渲染项目中使用,效率更高,但是重要的是要意识到何时使用renderbuffer对象以及何时使用纹理。一般规则是,如果永远不需要从特定缓冲区中采样数据,明智的做法是为该特定缓冲区使用renderbuffer对象。如果需要从特定的缓冲区(例如颜色或深度值)中采样数据,则应使用纹理附件。
(源自这里)

4.实现离屏渲染(亦同拷贝纹理)的两种思路

4.1 获取纹理再拷贝——将FBO的纹理拷贝到一张纹理当中;
实现效果:
左上角即为将FBO中颜色缓冲区的内容复制到纹理,进行再渲染的效果;

关键思路: 利用webgl的gl.copyTexSubImage2D()的函数,将FBO中颜色缓冲区的内容复制到纹理;

4.2 FBO拷贝——在webgl里面直接建立一个FBO,把绘制的结果直接存到FBO当中,然后在主的FBO中使用之前创建的FBO,实现离线渲染;
实现效果:

白色立方体为主FBO,白色立方体的贴图为自己创建FBO的动态纹理贴图,把自定义FBO的纹理贴到立方体上,再在主FBO上进行绘制。
思路如下:

参考上图:对FBO的几个缓冲区逐个进行RBO的填充依附;
1.自定义FBO的创建—对立方体进行木制纹理贴图;
新建帧缓冲区,对其的颜色缓冲区进行木制纹理贴图的填充,用模板缓冲区的深度缓冲区进行帧缓冲区深度缓冲区的链接,将绘制完成的帧缓冲对象以纹理的形式存放,以供下次主FBO中使用。
注意最后要取消几个缓冲区的绑定,使其恢复状态机,使用原生FBO;

function createFOB(width,height) {//新建帧缓冲对象var obj         =   webgl.createFramebuffer();//对帧缓冲对象进行绑定webgl.bindFramebuffer(webgl.FRAMEBUFFER, obj);//新建渲染缓冲区对象var depthObj    =   webgl.createRenderbuffer();//对渲染缓冲对象进行绑定webgl.bindRenderbuffer(webgl.RENDERBUFFER, depthObj);//创建并初始化渲染缓冲区对象的数据存储。webgl.renderbufferStorage(webgl.RENDERBUFFER, webgl.DEPTH_COMPONENT16, width, height);//渲染缓冲区对象作为帧缓冲区的深度缓冲区对象webgl.framebufferRenderbuffer(webgl.FRAMEBUFFER, webgl.DEPTH_ATTACHMENT, webgl.RENDERBUFFER, depthObj);//新建纹理对象textureDynamic = createDynamicTexture(width, height);//纹理对象作为帧缓冲区的颜色缓冲区对象webgl.framebufferTexture2D(webgl.FRAMEBUFFER, webgl.COLOR_ATTACHMENT0, webgl.TEXTURE_2D, textureDynamic, 0);//将绑定好的帧缓冲区,纹理,渲染缓冲区都取消绑定//恢复状态机,使用原生的FBOwebgl.bindRenderbuffer(webgl.RENDERBUFFER, null);webgl.bindFramebuffer(webgl.FRAMEBUFFER, null);webgl.bindTexture(webgl.TEXTURE_2D, null);return obj;}

2.使用自己创建的FBO,webgl.bindFramebuffer(webgl.FRAMEBUFFER, fbo);,接下来所有OpenGL绘制的数据将会保存至自己创建的FBO中;在此FBO中我主要进行“创建一个旋转立方体,对立方体进行木制纹理贴图”;

function renderToFBO() {//这里使用创建的FBO,接下来所有OpenGL绘制的数据将会保存至自己创建的FBOwebgl.bindFramebuffer(webgl.FRAMEBUFFER, fbo);webgl.viewport(0, 0, texWidth, texHeigh);//! 设置重绘背景的颜色webgl.clearColor(1.0, 1.0, 1.0, 1.0);//! 执行绘制,即将背景清空成制定的颜色(clearColor)webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);webgl.enable(webgl.DEPTH_TEST);//! 指定绘制所使用的顶点数据 从 该缓冲区中获取webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);var mvp = mat4.create();var matTrans = mat4.create();var matRot = mat4.create();var matScale = mat4.create();var matModel = mat4.create();var matAll = mat4.create();mat4.identity(matTrans);mat4.identity(matRot);mat4.identity(matModel);mat4.identity(matScale);mat4.identity(matAll);webgl.activeTexture(webgl.TEXTURE0);//将给定的textureHandle绑定到目标,即0号纹理;此为木制纹理webgl.bindTexture(webgl.TEXTURE_2D, textureHandle);//给片元着色器传递纹理webgl.uniform1i(uniformTexture, 0);mat4.translate(matTrans, [varTransX, 0.0, varTransZ]);mat4.rotate(matRot, degToRad(varRot), [1.0, 1.0, 1.0]);mat4.multiply(matTrans, matRot, matModel);mat4.scale(matScale, [varScale, 1, 1], matScale);mat4.multiply(matModel, matScale, matAll);mat4.multiply(projectMat, matAll, mvp);webgl.uniformMatrix4fv(uniformProj, false, mvp);webgl.enableVertexAttribArray(v3PositionIndex);webgl.enableVertexAttribArray(attrColor);webgl.enableVertexAttribArray(attrUV);webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 4 * 9, 0);webgl.vertexAttribPointer(attrUV, 2, webgl.FLOAT, false, 4 * 9, 4 * 3);webgl.vertexAttribPointer(attrColor, 4, webgl.FLOAT, false, 4 * 9, 4 * 5);webgl.drawArrays(webgl.TRIANGLES, 0, 36);}

3.切换到OpenGL的主FBO(即原生FBO)中webgl.bindFramebuffer(webgl.FRAMEBUFFER, null);,用之前自己创建的FBO生成的纹理贴图textureDynamic进行白色立方体的贴图(总体概括为使用之前创建的FBO);

            //切换成OpenGL自己创建的FBO,即主FBOwebgl.bindFramebuffer(webgl.FRAMEBUFFER, null);webgl.viewport(0, 0, texWidth, texHeigh);//! 设置重绘背景的颜色webgl.clearColor(0.0, 0.0, 0.0, 1.0);//! 执行绘制,即将背景清空成制定的颜色(clearColor)webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);webgl.enable(webgl.DEPTH_TEST);//! 指定绘制所使用的顶点数据 从 该缓冲区中获取webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);var mvp = mat4.create();var matTrans = mat4.create();var matRot = mat4.create();var matScale = mat4.create();var matModel = mat4.create();var matAll = mat4.create();varRot += 1;mat4.identity(matTrans);mat4.identity(matRot);mat4.identity(matModel);mat4.identity(matScale);mat4.identity(matAll);webgl.activeTexture(webgl.TEXTURE0);//textureDynamic 已经把FBO的内容绘制到这个纹理上了//把自定义FBO的纹理贴到立方体上,再在主FBO上进行绘制webgl.bindTexture(webgl.TEXTURE_2D, textureDynamic);webgl.uniform1i(uniformTexture, 0);mat4.translate(matTrans, [varTransX, 0.0, varTransZ]);mat4.rotate(matRot, degToRad(varRot), [1.0, 1.0, 1.0]);mat4.multiply(matTrans, matRot, matModel);mat4.scale(matScale, [varScale, 1, 1], matScale);mat4.multiply(matModel, matScale, matAll);mat4.multiply(projectMat, matAll, mvp);webgl.uniformMatrix4fv(uniformProj, false, mvp);webgl.enableVertexAttribArray(v3PositionIndex);webgl.enableVertexAttribArray(attrColor);webgl.enableVertexAttribArray(attrUV);webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 4 * 9, 0);webgl.vertexAttribPointer(attrUV, 2, webgl.FLOAT, false, 4 * 9, 4 * 3);webgl.vertexAttribPointer(attrColor, 4, webgl.FLOAT, false, 4 * 9, 4 * 5);webgl.drawArrays(webgl.TRIANGLES, 0, 36);

WebGL—实现使用FBO离屏渲染(亦同拷贝纹理)off-screen rendering的两种方式相关推荐

  1. OpenGL.ES在Android上的简单实践:23-水印录制(FBO离屏渲染,解决透明冲突,画中画)

    OpenGL.ES在Android上的简单实践:23-水印录制(FBO离屏录制,解决透明冲突) 1.水印签名罢工了? 不知道大家有没注意到,之前我们使用MediaCodec录制的视频,水印签名那部分区 ...

  2. html实现ipad投屏到显示器,iPad投屏的两种方式

    iPad投屏至少有两种方式,一种是AirPlay,这种方式相当于笔记本连接投影仪的方式,以投影仪或电视作为第二显示器,具体操作就是从iPad底部向上划,然后找AirPlay,如果此时显示设备,如智能投 ...

  3. Vue渲染组件的两种方式

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  4. Android中界面实现全屏显示的两种方式

    在开发android的应用当中,我们会遇到将一些界面设置为全屏显示的格式,有两种实现的方法.其一是在Java代码中实现,其二是在配置文件中实现. 1. 在Java代码中设置 super.onCreat ...

  5. vue点击网页全屏_vue-cli点击实现全屏功能(两种方式)

    项目中有点击按钮实现全屏功能 方式一:js实现全屏 代码如下: 全屏 export default { name: "index", data(){ return{ fullscr ...

  6. vue项目中实现录屏两种方式rrweb和RecordRTC

    rrweb原理 rrweb 是一个实现web页面录制和回放的基础库 ,它可以将⻚⾯中的 DOM 以及⽤户操作保存为可序列化的数据,以实现远程回放. RecordRTC原理 1.rrweb 安装npm ...

  7. Jinja2渲染的两种方式

    1.直接渲染字符串 if __name__ == '__main__':# 这种方式虽然简单,但是没有任何环境,不能应对复杂的业务.template = Template("开始:{{my_ ...

  8. Google浏览器全屏打开指定网页(两种方式)

    第一种 kiosk 方式 在桌面右键创建快捷方式,目标地址(Google浏览器安装地址要根据实际情况做修改): "C:\Users\Administrator\AppData\Local\G ...

  9. python+selenium web浏览器全屏长截图的两种方式

    1.此方法只适用于能够无头方式运行的浏览器,比如:chrome def get_image(url,pic_name):# chromedriver的路径chromedriver = r"D ...

最新文章

  1. 使用W3C XML Schema
  2. Python-语句执行
  3. Java 进阶 ——2019 计划要读的书
  4. 电气笔记:线路、主变、母线保护讲解
  5. java 屏蔽地域性访问_javaweb利用filter拦截未授权请求
  6. 利用 apache ab 测试服务器性能
  7. 2d游戏地图编辑器_从零开始的unity(3)——2d背景的制作和使用
  8. 关于移动端点击事件的问题
  9. SQL Server中的查询优化技术:数据库设计和体系结构
  10. vmWare中安装centos7
  11. 8.Nginx 例子
  12. 黑马程序员python入门学习笔记
  13. Android Toast的时长
  14. c语言实现 三角函数,关于数学:快速实现C ++三角函数
  15. 韩国历史最悠久的银行推出全国区块链贷款平台
  16. word无法验证服务器,Office提示“无法验证此应用程序的许可证”时怎么处理?...
  17. 双非硕士阿里大数据开发面经(已拿offer)(建议收藏)
  18. 字节跳动后端面经(18)
  19. 熬夜整理两万字Python知识点
  20. unity shader景深效果

热门文章

  1. 一小段Python代码,破解加密zip文件的密码
  2. 使用HTML和CSS的明信片动画效果
  3. 一张图搞清楚防抖和节流的区别
  4. 安卓最新系统_三星S9+升级最新系统ONE UI体验,安卓9.0带来哪些惊喜?
  5. 彻底卸载vscode Linux,ubuntu如何卸载vscode_编程开发工具
  6. 十三.landa表达式
  7. 什么是旅行?为什么要去旅行!
  8. iPhone XS 能否经受的起寒冬的考验
  9. ChatGPT 之父警告 AI 将灭绝人类,他却说这是杞人忧天​
  10. 揭秘了!双十一手机真的优惠吗?我爬取了京东近3000部手机,深度分析!