【Cocos2d-x】截屏实现的两种方法RenderTexture和glReadPixel,实现和原理详细分析
来源:互联网 发布:caffe安装windows 编辑:程序博客网 时间:2024/06/07 06:41
很多游戏都有截屏的需求,比如截屏后与好友分享截图,或者为了减少渲染内容,在打开某个UI界面时隐藏后面的所有渲染,用截屏代替。
截屏是一个比较老的话题了,一般用RenderTexture可以解决,其实我再拿出来说是因为想讨论另一种方法:glReadPixels。
以下分析两种截屏方法:
1. RenderTexture
2. glReadPixels
1. RenderTexture
实现代码如下:(测试用的是Cocos2d-x 3.3)
Sprite* utilScreenshot::createScreenshotSprite(){Size visibleSize = Director::getInstance()->getVisibleSize();RenderTexture* renderTexture = RenderTexture::create(visibleSize.width, visibleSize.height);renderTexture->begin();Director::getInstance()->getRunningScene()->visit();renderTexture->end();Texture2D* texture = renderTexture->getSprite()->getTexture();Sprite* sprScreenshot = Sprite::createWithTexture(texture);sprScreenshot->setFlippedY(true);return sprScreenshot;}
调用代码如下:
Sprite* sprScreenshot = utilScreenshot::createScreenshotSprite();sprScreenshot->setPosition(visibleSize / 2);this->addChild(sprScreenshot, 1);
原理:把当前场景进行一次渲染,但这次渲染不是渲染到屏幕上,而是渲染到RenderTexture维护的一张纹理上,然后再用这张纹理生成Sprite。
注意那句setFlippedY(2.x版本叫做setFlipY),因为OpenGL的纹理数据是从下到上保存的,但渲染却是从上到下渲染的,所以生成的纹理是上下颠倒的,需要翻转一下。
2. glReadPixels
之前我一直都是用上面那种方法进行截图的实现,后来看了一些OpenGL的书,认识一个函数glReadPixels,这个函数可以直接读取帧缓冲区的像素数据。
实现代码如下:
Sprite* utilScreenshot::createScreenshotSprite(){GLView* glview = Director::getInstance()->getOpenGLView();Size frameSize = glview->getFrameSize();const int dataLength = frameSize.width * frameSize.height * 4;char* pixelData = new char[dataLength];glReadPixels(0, 0, frameSize.width, frameSize.height, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);Texture2D* texture = new Texture2D();texture->initWithData(pixelData, dataLength, Texture2D::PixelFormat::RGBA8888, frameSize.width, frameSize.height, frameSize);Sprite* sprScreenshot = Sprite::createWithTexture(texture);sprScreenshot->setScaleX(1 / glview->getScaleX());sprScreenshot->setScaleY(1 / glview->getScaleY());sprScreenshot->setFlippedY(true);CC_SAFE_RELEASE(texture);delete[] pixelData;return sprScreenshot;}原理:直接读取帧缓冲区的像素数据,把读取出来的数据生成一张纹理,再用纹理生成Sprite。
注意:同样需要setFlippedY,原因同上。另外一点,由于用这种方式生成出来的texture的宽高为屏幕的实际宽高(而不是setDesginResolutionSize的宽高),所以需要setScaleX,setScaleY转换为design的宽高。
效率比较:RenderTexture需要把整个场景渲染一次(就是说要把以CCScene为根节点的节点树进行一次遍历,访问每个节点的visit和draw函数),而glReadPixels是直接获取显卡的数据,效率应该要比前者快。
对了还有一个问题,无论是RenderTexture还是glReadPixels的方法,如果把截图叠在场景上,会发现有那么一点点的偏差,这是为什么呢?其实这是由于透视投影中近大远小的原因,图片的四周离摄像机较远,投影之后会比中间小,所以生成出来的图片并不是原图片。在Cocos2d-x中,Director::setProjection默认设成了透视投影,如果是2D游戏,只需调用一下
Director::getInstance()->setProjection(Director::Projection::_2D);这句会把投影方式设成正交投影,即可解决问题。
由于本人水平有限,文章叙述如有不当,欢迎吐槽。
- 【Cocos2d-x】截屏实现的两种方法RenderTexture和glReadPixel,实现和原理详细分析
- OpenG利用glreadPixel实现截屏功能
- RenderTexture截屏原理
- HashMap遍历方法和实现原理分析
- Android ListView实现不同item的方法和原理分析
- Android ListView实现不同item的方法和原理分析
- 通过cocos2d-x的CCGLProgram和CCShaderCache的实现来分析OpenGL ES中的Shader编程
- 通过cocos2d-x的CCGLProgram和CCShaderCache的实现来分析OpenGL
- Cocos2d-x学习(十四):用cocos2d-x实现MoonWarriors(暂停和恢复的实现)
- Cocos2d-x 用cocos2d-x实现MoonWarriors(暂停和恢复的实现)
- Cocos2d-x学习(十四):用cocos2d-x实现MoonWarriors(暂停和恢复的实现)
- Java中x+=y和x=x+y两种实现的区别
- Cocos2d-x 自定义实现下拉列表框(两种实现方法)
- MFC工具条和状态栏,内部实现原理详细分析
- Cocos2d-x 3.x RenderTexture渲染纹理源码分析
- Cocos2d-x 3.x RenderTexture渲染纹理源码分析
- 线程的两种实现方法 和 进程的两种实现方法 。
- cocos2d-x Action实现原理
- 特定条件下结构风险最小化等价于最大后验概率估计得证明
- 在thinkphp3.2基础上封装上传图片接口
- 注解机制 androidannotations 让编程更随性,更轻松(一)
- 第六周项目一--深复制体验
- HDU 1016 Prime Ring Problem
- 【Cocos2d-x】截屏实现的两种方法RenderTexture和glReadPixel,实现和原理详细分析
- mcc函数实现matlab的m文件转化为c,c++文件。
- scanf()函数探究
- 设计模式之代理模式学习------强制代理-----------《设计模式之禅》学习笔记
- jdbc 数据库连接验证 工具
- Http中的GET和POST方法的区别
- 02-SQLlite3之alter:在已有的表中添加、修改或删除列
- Canvas之太阳系
- 移动端重构