【cocos2dx】之RenderTexture实现截图

      大家好,我是Lampard

      今天与大家探讨一下cocos中实现截图所使用到的类RenderTexture

(一)使用RenderTexture实现截图功能

      cocos实现截图可以通过两种方式。第一种就是今天将要介绍的使用renderTexture类去实现,第二种是利用cocos2dx在3.2版本之后给我们提供的utils:captureScreen()实现截图。两种方式互有优劣,前者就好像你去到了一个超市,看见呈现在屏幕上琳琅满目的商品,你可以挑选任意商品绘制到你的图片上,但如果这个商品比较复杂(如3d的精灵)那么你可能就得不到想要的效果,需要花更多的功夫。而第二种使用起来就比较简单,就像小孩子才需要做选择,大人全都要。它能对屏幕直接进行截图,其实现原理有点手机截图,我不管你是怎么实现的,它直接把屏幕上的像素点记录下来再生成一个image保存,所以3d精灵对于第二种方式来说也不过是像素点而已,能够绘制出来,但它无法只画出你想要的内容

      我们可以用上文的方法实现截图功能,首先创建一个renderTexture画布,设置画布的大小。然后调用begin函数去记录期间渲染的对象(调用endToLua结束之前),最后输出到磁盘中

(二)解读RenderTexture源码

create方法

我们通过查阅源码去了解上述方法的是如何实现截图的。在RenderTexture中,重载了好三个create方法,分别是:

  • create(int w, int h) -- 只传入宽高
  • create(int w, int h, Texture2D::PixelFormat eFormat) -- 传入宽高和客户端的像素格式
  • create(int w ,int h, Texture2D::PixelFormat eFormat, GLuint uDepthStencilFormat) -- 传入宽高,客户端的像素格式和深度模板缓冲格式

      我们是只传入了宽高,所以执行的是这一个函数。首先实例化了一个RenderTexture对象,然后调用了对象的initWithWidthAndHeight方法对画布进行一个初始化,最后把这个生成的对象加入自动回收池中,对于我们没有传入的客户端的像素格式和深度模板缓冲格式默认使用了RGBA8888和0

像素格式和深度模板缓冲格式是什么

      首先讲一下像素格式,像素格式常见的有4个通道,分别是:R红色通道,G绿色通道,B蓝色通道,A透明度通道。引擎默认是使用RGBA8888的格式,也就是每一个通道用8个位去记录值,所以一个像素就是需要32个位,也就是4个字节,如果一张1024*1024的图片就需要4M的空间去存储。所以常见的优化方式是把RGBA8888的像素格式修改成RGBA4444,对于精度要求没有那么高但是又需要透明通道的图片来说,能节省一半的空间。如果不需要透明通道,可以使用RGB565和RGB888等等,以下是官网像素格式的文档

然后说一下什么是深度模板缓冲,它其实是包含了两个东西,分别是深度缓冲和模板缓冲

深度缓冲区

      深度缓冲区(或 z 缓冲区)存储像素的深度信息,以控制渲染哪些多边形区域。简单来说,就是当同一场景中,出现位置重叠的像素,那么GPU需要知道该显示哪一个像素信息,这时就可以通过深度缓存区中的值来比较,若比缓存区中的值小(更上层),颜色缓冲中记录下当前像素的信息,否则则不对此颜色进行记录

模板缓冲区

      模板缓冲区用于遮罩图像中的像素,以产生特殊效果。特殊效果包括合成、贴纸、溶解、淡化、滑动、轮廓描绘和剪影,以及双面模板等。模板测试发生在透明度测试(alpha test)之后,深度测试(depth test)之前。如果模板测试通过,则相应的像素点更新,否则不更新

      像上图中图一是颜色缓冲区,图二是模板缓冲区,图三就是最后最后渲染出的结果。cocos中深度模板缓冲格式给我们提供了三个选择

  • RB_FMT_D24S8:24 位深度缓冲和 8 位模板缓冲
  • RB_FMT_S8:只申请 8 位模板缓冲
  • RB_FMT_D16:只申请 16 位深度缓冲

initWithWidthAndHeight方法

  initWithWidthAndHeight方法主要是根据我们传入的宽高,客户端像素格式,深度模板格式对renderTexture对象进行一个初始化。若成功则返回true,不成功则返回false。它主要分以下几个步骤进行初始化

开辟空间传给纹理对象

      根据是否支持宽高纹理的像素为非2的n次方来调整设定的宽高,然后根据最终的宽高申请内存,大小为powW * powH * 4

      把申请得来的内存用0来填充,然后生成一个texture2D的纹理对象,并把内存块,内存长度,宽高等信息传递给纹理对象使其进行初始化

把这个纹理绑定到帧缓冲

      当把一个纹理附加到帧缓冲的时候,所有的渲染指令将会写入到这个纹理中,就想它是一个普通的颜色/深度或模板缓冲一样。使用纹理的优点是,所有渲染操作的结果将会被储存在一个纹理图像中。

创建帧缓冲对象用到了两个方法。glGenFramebuffers需要传入两个参数,第一个是要创建的帧缓存的数目,第二个是指向存储一个或者多个ID的变量或数组的指针。它返回未使用的FBO的ID。glBindFramebuffer第一个参数target是GL_FRAMEBUFFER,第二个参数是FBO的ID号从而生成FBO对象并把FBO对象绑定在上面,一旦FBO被绑定,之后的所有的OpenGL操作都会对当前所绑定的FBO造成影响最后是帧缓冲绑定的颜色缓存到纹理中

如果使用了深度缓冲,再创建一个深度渲染缓冲对象

      深度缓冲与帧缓冲类似,同样需要生成渲染缓冲对象然后绑定到GL_RENDERBUFFER中去。并且需要把这个渲染缓冲对象绑定在帧缓冲对象的GL_DEPTH_ATTACHMENT深度关联点中,如果还有模板缓冲则把这个渲染缓冲对象绑定在帧缓冲对象的GL_STENCIL_ATTACHMENT模板关联点中

把纹理数据作为参数,生成sprite绘制到屏幕帧缓冲中

      最后生成一个sprite,会过程中绘制的内容呈现在屏幕上,并把帧缓冲还原成最初的状态

帧缓冲是什么

      这个时候就会有朋友提问了,提了好几次帧缓冲,又得把深度模板的关联点绑定到上面去,那帧缓冲是什么东西呢?臣妾也不会啊,这只能去官网找点文档看了

帧缓冲是用来存储渲染数据的地方,可以理解为显存。几何数据(顶点坐标、纹理坐标等)和纹理经过一系列渲染管道最终计算出屏幕上的所有像素点,它们需要一个地方来存放,这个地方就是帧缓冲。帧缓冲中的数据会被显示器读取来刷新显示。一个完整的帧缓冲需要有以下的条件

  • 附加至少一个缓冲(颜色、深度或模板缓冲)。
  • 至少有一个颜色附件(Attachment)。
  • 所有的附件都必须是完整的(保留了内存)。
  • 每个缓冲都应该有相同的样本数。

      当把一个纹理附加到帧缓冲的时候,所有的渲染指令将会写入到这个纹理中,就想它是一个普通的颜色/深度或模板缓冲一样。使用纹理的优点是,所有渲染操作的结果将会被储存在一个纹理图像中,我们之后可以在着色器中很方便地使用它。

      简而言之,颜色,深度,模板都只是其一个属性,当最终的结果出来之后就会存放在帧缓冲中,而使用纹理就可以把这次渲染的结果保存下来

begin方法

      begin方法首先是创建一个渲染队列组,用于记录之后之后截图所使用到的渲染指令,这样后续元素的RenderCommand将会被添加到_groupCommand中,从而实现分组绘制

  • cocos中的Renderer维护着一个RenderQueue数组,每隔RenderQuque记录了一组RenderCommand,每个RenderCommand通常由其globalOrder属性决定绘制顺序。
  • Renderer同时维护着一个RenderQueue的Id组成的栈,每个元素的绘制命令通过AddCommand发送到Renderer,Renderer会将其放置到Id栈中最后一个元素对应的RenderQueue上。
  • 一个GroupCommand在初始化的时候会创建一个新的RenderQueue并添加到Renderer的Id栈上,这样后续元素的RenderCommand将会被添加到新的RenderQueue,从而实现分组绘制,直到该GroupCommand绘制完毕将其从Id栈移除,从此不会影响后续的绘制命令。
  • 当所有的UI元素被遍历之后,Renderer会从RenderQueue数组的第一个RenderQueue开始绘制,如果某个RenderCommand的类型是GroupCommand,则找到该GroupCommand记录的RenderQueue开始绘制,从而实现了分组绘制。

      调整完正投影和可视窗口视口之后,然后在onBegin函数上再次使用glBindFramebuffer,指定渲染到渲染缓存,而不是渲染到屏幕上

visit&end方法

      上述步骤做完之后就可以把想要截图的对象重新“画”一次了,在cocos中我们可以调用其visit方法,visit方法中首先它根据localZOrder使用sortAllChildren()来对子节点进行排序,然后遍历将按照localZOrder从小到大调用draw方法,而draw方法则把它们押入到上文的渲染队列_groupCommand中去,然后每一帧再统一的把渲染队列中的节点按照GlobalZOrder的顺序进行渲染操作

end方法中则是对帧缓冲和视图矩阵进行还原,然后把_groupCommand从渲染队列数组中pop出来,使之后的渲染指令能正常渲染在屏幕上

(三)测试截图功能

      我们就利用上次做的demo,把登录按钮的功能修改成截图看看效果

以上是学习路上的一点思绪,欢迎大家评论指点~

点赞,关注!!!

【cocos2dx】之RenderTexture实现截图相关推荐

  1. CocosCreator 硬核 APP分享战绩、截图到微信

    前言 Creator2.0之后的版本,弃用了RenderTexture渲染树,导致很多功能不能用.别担心,去除一个东西,总会有另外一个东西来替代,所以重心就转移到了Camera身上. 提示:亲测实用有 ...

  2. cocos2dx 3.x 屏幕截图的两种方法及其优缺点

    第一种方法:用RenderTexture实现截图功能 在cocos2dx 3.2之前,引擎没有提供截图功能,我们可以用RenderTexture来实现截图功能,这个方法在cocos2dx 3.2之后也 ...

  3. 麒麟子Cocos Creator实用技巧四:打包原生App截图白屏解决方案

    大家在做棋牌App或者一些特定需求的时候,需要截取当前游戏屏幕内容保存. 我们一般是采用cc.RenderTexture来截图并保存到游戏的可写目录 有时候会遇上,截出来的图片是白屏,或者部分白屏. ...

  4. linux中安装mysql步骤,Linux中安装MySql 5.7.21的详细操作步骤

    python基础01 Hello World! 摘要:简单的Hello Word! python 命令行 如已经安装python,那么在linux命令行中输入 $python 将进入python.乱吼 ...

  5. EasyAR涂涂乐代码分析

    来说一下对EasyAR sdk中自带的unity Samples中的Coloring3D这个项目的理解(例子程序可以去官网下载 最后会列出所有用到网站的网址). 这个项目的效果就是我们常见的" ...

  6. cocos creater 游戏开发工具方法

    /*** 观察者方法** @export* @param {*} obj* @param {Function} callback* @param {*} pointer* @return {*} {P ...

  7. Cocos Creator截屏方法

    在 1.x 中,我们一般通过 cc.RenderTexture 来完成截图功能,但是这是属于旧版本渲染树中的一个功能,在Cocos Creator2.0去除渲染树后,截图功能的使用方式也完全不同了.简 ...

  8. Cocos2d-x 截图功能

    (1)Cocos2d-x 2.x Cocos2d-x 2.x没有提供截图功能,但是可以用CCRenderTexture来实现这个功能: void CTestLayer::SaveScreenShot( ...

  9. cocos2dx RenderTexture 用法

    renderTexture 能够将 可视元素绘制在一张texture里,随后我们就可以操作这张texture. renderTexture 最显著的一个功能就是截图 下面先说它的用法,这里我用的是lu ...

最新文章

  1. 再谈类别不平衡问题:调节权重与魔改Loss的综合分析
  2. Oracle数据库更新时间的SQL语句
  3. 打包(归档)和压缩(包含两者的区别)
  4. 一年3000家企业涌入,站上风口的男色经济难逃烧钱亏损
  5. 试图将驱动程序添加到存储区_云存储——终于等到你,还好没放弃
  6. jidnserror.wo.com.cn:8080错误解决方法
  7. python发音1001python发音-python——字符串问题总结
  8. iservice list方法_扩展IList对象,实现深拷贝扩展方法
  9. 【python】ssh密码字典攻击
  10. [架构之路-47]:目标系统 - 系统软件 - Linux OS硬件设备驱动 - CPU内存管理单元MMU、DMA与IO内存管理单元IOMMU
  11. jenkins下载插件慢解决方式
  12. win10任务栏透明+变窄+免安装
  13. 大数据Spark(一):框架概述
  14. 使用Python对比两个excel表格中的重复数据
  15. 【MySQL从入门到精通】【高级篇】(二十五)EXPLAIN中ref、rows、filtered、Extra字段的剖析
  16. FC/NES PPU 示例汇编程序 简易画图
  17. c#:使用网易邮箱账号发送电子邮件
  18. LocalDate 计算两个日期相差天数
  19. 95 后女孩从月入3000到月入10万
  20. 你知不知道,天空没有想象中蓝

热门文章

  1. linux-3.4.2 smsc911x 网卡移植
  2. 中首清算|软银集团科技股投资损失13亿美元
  3. 优秀的 Verilog/FPGA开源项目介绍(二)-RISC-V
  4. [备忘] 查看浏览器中flash swf的trace调试输出
  5. LED灯带蓝牙芯片控制解决方案
  6. R语言forestplot包绘制森林图
  7. 拿到了摩根斯坦利IT部门offer(2018 Morgan Stanley Technology Summer Analyst)
  8. 戴尔: 这一次都用了什么技术突破创新?
  9. Python画置信区间图
  10. Firefox下几个常用的插件