微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Cocos2d-x 2.0 渲染到纹理深入分析

现在我们将重新认识一下RenderTexture。在TestCpp中它做为独立的演示场景存在,名称为RenderTextureTest。我们先来看一下最重要的类CCRenderTexture。它是用于管理渲染目标纹理的类,与纹理不同的是,它必须是属于

打开CCRenderTexture.h:


  1. //图像格式枚举,可以保存为JPG和PNG两种格式
  2. typedefenumeImageFormat
  3. {
  4. kCCImageFormatJPEG=0,
  5. kCCImageFormatPNG=1,
  6. }tCCImageFormat;
  7. //由结点派生
  8. classCC_DLLCCRenderTexture:publicCCNode
  9. //精灵成员变量及存取接口
  10. CC_PROPERTY(CCSprite*,m_pSprite,Sprite)
  11. public:
  12. //构造
  13. CCRenderTexture();
  14. //析构
  15. virtual~CCRenderTexture();
  16. //创建一个渲染目标纹理。参数指定大小,像素格式和深度模板缓冲格式。内部调用create实现。
  17. CC_DEPRECATED_ATTRIBUTEstaticCCRenderTexture*renderTextureWithWidthAndHeight(intw,inth,CCTexture2DPixelFormateFormat,gluintuDepthStencilFormat);
  18. //创建一个渲染目标纹理。参数指定大小,像素格式。内部调用create实现。
  19. //创建一个渲染目标纹理。参数指定大小.。内部调用create实现。
  20. inth);
  21. //第一个函数的create实现。
  22. staticCCRenderTexture*create(gluintuDepthStencilFormat);
  23. //第二个函数的create实现。
  24. //第三个函数的create实现。
  25. inth);
  26. //初始化,参数为大小和像素格式。
  27. boolinitWithWidthAndHeight(//初始化,参数为大小和像素格式,深度模板缓冲格式。
  28. //开始渲染到当前目标纹理。
  29. voidbegin();
  30. //清空颜色缓冲的值为指定值。
  31. voidbeginWithClear(floatr,87); background-color:inherit">floatg,87); background-color:inherit">floatb,87); background-color:inherit">floata);
  32. //清空颜色缓冲和深度的值为指定值。
  33. floata,87); background-color:inherit">floatdepthValue);
  34. //清空颜色缓冲和深度,模版值缓冲的值为指定值。
  35. floatdepthValue,87); background-color:inherit">intstencilValue);
  36. //LUA中调用的结束函数
  37. inlinevoidendToLua(){end();};
  38. //结束渲染到当前目标纹理。
  39. voidend();
  40. //清空目标纹理的颜色为指定色
  41. voidclear(floata);
  42. //清空目标纹理的深度值
  43. voidclearDepth(floatdepthValue);
  44. //清空目标纹理的模板缓冲值
  45. voidclearStencil(intstencilValue);
  46. //由目标纹理的数据产生出CCImage实例。
  47. CCImage*newCCImage();
  48. //保存目标纹理到相应图片文件
  49. boolsavetoFile(constchar*szFilePath);
  50. //保存目标纹理到相应图片文件,指定图像格式。
  51. char*name,tCCImageFormatformat);
  52. //监听消息,保存目标纹理。
  53. voidlistenToBackground(CCObject*obj);
  54. protected:
  55. //FBO对象,即帧缓冲区,一帧中像素数据保存的缓冲区域。可参看http://www.cnblogs.com/aokman/archive/2010/11/14/1876987.html
  56. gluintm_uFBO;
  57. //深度缓冲。
  58. gluintm_uDepthRenderBufffer;
  59. //保存旧的FBO对象。
  60. GLintm_nOldFBO;
  61. //使用的纹理。
  62. CCTexture2D*m_pTexture;
  63. //用于保存当前纹理数据的可变纹理对象。
  64. CCImage*m_pUITextureImage;
  65. //像素格式
  66. GLenumm_ePixelFormat;
  67. };

然后是CPP:

copy
    CCRenderTexture::CCRenderTexture()
  1. :m_pSprite(NULL)
  2. ,m_uFBO(0)
  3. {
  4. //设置监听EVENT_COME_TO_BACKGROUND事件,如果响应调用CCRenderTexture::listenToBackground函数
  5. CCNotificationCenter::sharednotificationCenter()->addobserver(this,
  6. callfuncO_selector(CCRenderTexture::listenToBackground),0); background-color:inherit">EVENT_COME_TO_BACKGROUND,0); background-color:inherit">NULL);
  7. }
  8. CCRenderTexture::~CCRenderTexture()
  9. //释放FBO
  10. glDeleteFramebuffers(1,&m_uFBO);
  11. //释放深度缓冲
  12. if(m_uDepthRenderBufffer)
  13. glDeleteRenderbuffers(1,&m_uDepthRenderBufffer);
  14. //释放
  15. CC_SAFE_DELETE(m_pUITextureImage);
  16. //移除监听响应函数
  17. CCNotificationCenter::sharednotificationCenter()->removeObserver(}
  18. voidCCRenderTexture::listenToBackground(cocos2d::CCObject*obj)
  19. //如果使用可变纹理。
  20. #ifCC_ENABLE_CACHE_TEXTURE_DATA
  21. //释放上一个m_pUITextureImage
  22. //产生当前渲染目标的CCImage
  23. m_pUITextureImage=newCCImage();
  24. //如果成功则将纹理m_pTexture中数据填充到可变纹理。
  25. if(m_pUITextureImage)
  26. constCCSize&s=m_pTexture->getContentSizeInPixels();
  27. VolatileTexture::addDataTexture(m_pTexture,m_pUITextureImage->getData(),kTexture2DPixelFormat_RGBA8888,s);
  28. else
  29. cclOG("CacherendertextureFailed!");
  30. #endif
  31. //取得精灵成员
  32. CCSprite*CCRenderTexture::getSprite()
  33. returnm_pSprite;
  34. //设置精灵成员。
  35. voidCCRenderTexture::setSprite(CCSprite*var)
  36. m_pSprite=var;
  37. CCRenderTexture*CCRenderTexture::renderTextureWithWidthAndHeight(returnCCRenderTexture::create(w,h,eFormat);
  38. //上面的create实现。
  39. CCRenderTexture*CCRenderTexture::create(//创建一个渲染目标纹理。
  40. CCRenderTexture*pRet=newCCRenderTexture();
  41. //调用相应的初始化函数
  42. if(pRet&&pRet->initWithWidthAndHeight(w,eFormat))
  43. //成功后交由内存管理器进行管理。
  44. pRet->autorelease();
  45. returnpRet;
  46. //不成功则释放置空返回NULL。
  47. CC_SAFE_DELETE(pRet);
  48. returnNULL;
  49. gluintuDepthStencilFormat)
  50. //上面的create实现。
  51. gluintuDepthStencilFormat)
  52. //创建一个渲染目标纹理。
  53. newCCRenderTexture();
  54. //调用相应的初始化函数
  55. CC_SAFE_DELETE(pRet);
  56. returnNULL;
  57. //创建一个渲染目标纹理。参数指定大小。内部调用create实现。
  58. inth)
  59. inth)
  60. pRet->autorelease();
  61. returnpRet;
  62. //初始化,参数为大小和像素格式格式。
  63. boolCCRenderTexture::initWithWidthAndHeight(returninitWithWidthAndHeight(w,0);
  64. //有效性判断。
  65. CCAssert(m_ePixelFormat!=kCCTexture2DPixelFormat_A8,"onlyRGBandRGBAformatsarevalidforarendertexture");
  66. //
  67. boolbRet=false;
  68. //使用do–while结构来保证出错及时中断退出
  69. do
  70. //宽高要乘以缩放值。
  71. w*=(int)CC_CONTENT_SCALE_FACTOR();
  72. h*=(int)CC_CONTENT_SCALE_FACTOR();
  73. //保存当前的FBO对象。
  74. glGetIntegerv(GL_FRAMEBUFFER_BINDING,&m_nOldFBO);
  75. //创建临时变量保存纹理的真实大小。
  76. unsignedintpowW=0;
  77. intpowH=0;
  78. //看是否支持纹理的非2幂次方,做相应的处理。
  79. if(CCConfiguration::sharedConfiguration()->supportsNPOT()){
  80. //如果支持就用w,h做为纹理大小。
  81. powW=w;
  82. powH=h;
  83. }else{
  84. //如果不支持要转换为2的幂次方大小。
  85. powW=ccNextpot(w);
  86. powH=ccNextpot(h);
  87. //为像素申请内存。每像素4字节。
  88. void*data=malloc((int)(powW*powH*4));
  89. //内存申请失败则中断退出
  90. CC_BREAK_IF(!data);
  91. //清空内存为0。
  92. memset(data,(//保存像素格式。
  93. m_ePixelFormat=eFormat;
  94. //创建一个新的纹理。
  95. m_pTexture=newCCTexture2D();
  96. //由上面的像素数据和大小,像素格式信息填充纹理。
  97. if(m_pTexture){
  98. m_pTexture->initWithData(data,(CCTexture2DPixelFormat)m_ePixelFormat,powW,powH,CCSizeMake((float)w,(float)h));
  99. free(data);
  100. else{
  101. free(data);//ScopeGuard(asimulatedFinallyclause)wouldbemoreelegant.
  102. break;
  103. //取得当前的FBO对象。
  104. GLintoldRBO;
  105. glGetIntegerv(GL_RENDERBUFFER_BINDING,&oldRBO);
  106. //创建新的FBO并绑定。
  107. glGenFramebuffers(1,0); background-color:inherit">glBindFramebuffer(GL_FRAMEBUFFER,m_uFBO);
  108. //设置将帧缓冲区颜色数据输出到纹理。
  109. glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,m_pTexture->getName(),0);
  110. //如果有使用深度缓冲。
  111. if(m_uDepthRenderBufffer!=0)
  112. //创建一个渲染目标深度缓冲区并绑定。
  113. glGenRenderbuffers(1,&m_uDepthRenderBufffer);
  114. glBindRenderbuffer(GL_RENDERBUFFER,m_uDepthRenderBufffer);
  115. //设置当前渲染目标缓冲氏的像素格式和大小。
  116. glrenderbufferStorage(GL_RENDERBUFFER,uDepthStencilFormat,(GLsizei)powW,(GLsizei)powH);
  117. //设置将帧缓冲区深度数据输出到这个新创建的深度缓冲区。
  118. glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,0); background-color:inherit">//如果深度缓冲格式是24位深度,8位模版缓冲,则设置将帧缓冲区的模版数据输出到这个新创建的深度缓冲区中。
  119. if(uDepthStencilFormat==CC_GL_DEPTH24_STENCIL8)
  120. //检查上面操作是否正常执行。
  121. CCAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER)==GL_FRAMEBUFFER_COMPLETE,255); background-color:inherit">"Couldnotattachtexturetoframebuffer");
  122. //设置纹理不使用抗距齿模糊。
  123. m_pTexture->setAliasTexParameters();
  124. //由纹理创建精灵成员。
  125. m_pSprite=CCSprite::createWithTexture(m_pTexture);
  126. //释放纹理。
  127. m_pTexture->release();
  128. //精灵设置Y镜像并放入到当前结点下。
  129. m_pSprite->setScaleY(-1);
  130. this->addChild(m_pSprite);
  131. //设置ALPHA混合方案。
  132. ccBlendFunctBlendFunc={GL_ONE,GL_ONE_MINUS_SRC_ALPHA};
  133. m_pSprite->setBlendFunc(tBlendFunc);
  134. //还原所用的
  135. bRet=true;
  136. while(0);
  137. returnbRet;
  138. //开始渲染到当前目标纹理。
  139. voidCCRenderTexture::begin()
  140. //保存当前矩阵
  141. kmGLPushmatrix();
  142. //取得纹理的大小。
  143. constCCSize&texSize=m_pTexture->getContentSizeInPixels();
  144. //取得设备的窗口大小,计算出视口和投影矩阵
  145. CCDirector*director=CCDirector::sharedDirector();
  146. CCSizesize=director->getWinSizeInPixels();
  147. floatwidthRatio=size.width/texSize.width;
  148. floatheightRatio=size.height/texSize.height;
  149. glViewport(0,(GLsizei)texSize.width,(GLsizei)texSize.height);
  150. kmMat4orthoMatrix;
  151. kmMat4OrthographicProjection(&orthoMatrix,87); background-color:inherit">float)-1.0/widthRatio,87); background-color:inherit">float)1.0/widthRatio,0); background-color:inherit">(float)-1.0/heightRatio,87); background-color:inherit">float)1.0/heightRatio,-1,1);
  152. kmGLMultMatrix(&orthoMatrix);
  153. //取得当前的FBO
  154. //清空颜色缓冲。
  155. voidCCRenderTexture::beginWithClear(floata)
  156. //开始渲染到目标纹理。
  157. this->begin();
  158. //临时变量,用于保存当前帧的色彩缓冲的清空值数据。
  159. GLfloatclearColor[4];
  160. glGetFloatv(GL_COLOR_CLEAR_VALUE,clearColor);
  161. //按指定清空值数值清空色彩缓冲区。
  162. glClearColor(r,g,b,a);
  163. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  164. //恢复色彩缓冲的清空值数据。
  165. glClearColor(clearColor[0],clearColor[1],clearColor[2],clearColor[3]);
  166. //清空颜色缓冲和深度缓冲的值为指定值。
  167. floatdepthValue)
  168. //开始渲染到目标纹理。
  169. this->begin();
  170. //临时变量,用于保存当前帧的各缓冲的清空值数据。
  171. GLfloatclearColor[4];
  172. GLfloatdepthClearValue;
  173. glGetFloatv(GL_DEPTH_CLEAR_VALUE,&depthClearValue);
  174. //按指定清空值数值清空各绘冲区。
  175. glClearDepth(depthValue);
  176. //恢复各缓冲的清空值数据。
  177. glClearDepth(depthClearValue);
  178. intstencilValue)
  179. //临时变量,用于保存当前帧的各缓冲的清空值数据。
  180. GLfloatdepthClearValue;
  181. intstencilClearValue;
  182. glGetIntegerv(GL_STENCIL_CLEAR_VALUE,&stencilClearValue);
  183. glClearStencil(stencilValue);
  184. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  185. //恢复各缓冲的清空值数据。
  186. glClearDepth(depthClearValue);
  187. glClearStencil(stencilClearValue);
  188. voidCCRenderTexture::end()
  189. //还原旧的FBO
  190. //恢复矩阵
  191. kmGLPopMatrix();
  192. //取得设备。
  193. CCDirector*director=CCDirector::sharedDirector();
  194. //取得窗口大小。
  195. //还原视口及投影矩阵。
  196. if(director->getProjection()==kCCDirectorProjection3D&&CC_CONTENT_SCALE_FACTOR()!=1)
  197. glViewport((GLsizei)(-size.width/2),(GLsizei)(-size.height/2),(GLsizei)(size.width*CC_CONTENT_SCALE_FACTOR()),(GLsizei)(size.height*CC_CONTENT_SCALE_FACTOR()));
  198. director->setProjection(director->getProjection());
  199. //清空目标纹理的颜色为指定色
  200. voidCCRenderTexture::clear(//开始渲染到目标纹理并清空目标纹理的颜色为指定色。
  201. this->beginWithClear(r,a);
  202. //结束渲染到目标纹理。
  203. this->end();
  204. //清空目标纹理的深度值为指定值。
  205. voidCCRenderTexture::clearDepth(floatdepthValue)
  206. //取得当前深度缓冲清空值。
  207. //设置新深度清空值并清空模板缓冲。
  208. glClear(GL_DEPTH_BUFFER_BIT);
  209. //还用深度缓冲清空值。
  210. //结束渲染到目标纹理。
  211. this->end();
  212. //清空目标纹理的模版缓冲值为指定色
  213. voidCCRenderTexture::clearStencil(intstencilValue)
  214. //取得当前模板缓冲清空值。
  215. //设置新模板清空值并清空模板缓冲。
  216. glClear(GL_STENCIL_BUFFER_BIT);
  217. //还原模板缓冲清空值。
  218. boolCCRenderTexture::savetoFile(char*szFilePath)
  219. //取得当前渲染目标纹理产生的CCImage。
  220. CCImage*pImage=newCCImage();
  221. if(pImage)
  222. {//保存到图片
  223. bRet=pImage->savetoFile(szFilePath,kCCImageFormatJPEG);
  224. //释放pImage
  225. CC_SAFE_DELETE(pImage);
  226. //保存目标纹理到相应图片文件,可以指定像素格式。
  227. char*fileName,tCCImageFormatformat)
  228. //只允许JPG和PNG格式
  229. CCAssert(format==kCCImageFormatJPEG||format==kCCImageFormatPNG,0); background-color:inherit">"theimagecanonlybesavedasJPGorpnGformat");
  230. //取得当前渲染目标纹理产生的CCImage。
  231. CCImage*pImage=newCCImage();
  232. if(pImage)
  233. //取得路径。
  234. std::stringfullpath=CCFileUtils::sharedFileUtils()->getWriteablePath()+fileName;
  235. bRet=pImage->savetoFile(fullpath.c_str(),true);
  236. //返回成败。
  237. returnbRet;
  238. //由目标纹理的数据产生出CCImage实例。/
  239. CCImage*CCRenderTexture::newCCImage()
  240. //有效性判断。
  241. CCAssert(m_ePixelFormat==kCCTexture2DPixelFormat_RGBA8888,255); background-color:inherit">"onlyRGBA8888canbesavedasimage");
  242. if(NULL==m_pTexture)
  243. //取得纹理的大小。
  244. //取得宽高。
  245. intnSavedBufferWidth=(int)s.width;
  246. intnSavedBufferHeight=(int)s.height;
  247. //定义临时指针变量。
  248. glubyte*pBuffer=NULL;
  249. glubyte*pTempData=NULL;
  250. CCImage*pImage=newCCImage();
  251. //do-while流程结构保证出错及时退出
  252. do
  253. //创建最终结果的像素数据数组的内存。
  254. CC_BREAK_IF(!(pBuffer=newglubyte[nSavedBufferWidth*nSavedBufferHeight*4]));
  255. //申请临时像素数据数组的内存。
  256. if(!(pTempData=newglubyte[nSavedBufferWidth*nSavedBufferHeight*4]))
  257. delete[]pBuffer;
  258. pBuffer=NULL;
  259. break;
  260. //设置像素按字节对齐。
  261. glPixelStorei(GL_PACK_ALIGNMENT,1);
  262. //将像素写入到pTempData中。
  263. glreadPixels(0,nSavedBufferWidth,nSavedBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE,pTempData);
  264. //将pTempData从下往上拷到pBuffer中,为什么呢?因为前面initWithWidthAndHeight中精灵成员设置了Y镜像,所以图像是上下反的。
  265. for(inti=0;i<nSavedBufferHeight;++i)
  266. memcpy(&pBuffer[i*nSavedBufferWidth*4],0); background-color:inherit">&pTempData[(nSavedBufferHeight-i-1)*nSavedBufferWidth*4],0); background-color:inherit">nSavedBufferWidth*4);
  267. //填充pImage
  268. pImage->initWithImageData(pBuffer,nSavedBufferWidth*nSavedBufferHeight*4,CCImage::kFmtRawData,8);
  269. //释放申请的内存
  270. CC_SAFE_DELETE_ARRAY(pBuffer);
  271. CC_SAFE_DELETE_ARRAY(pTempData);
  272. returnpImage;
  273. }

这个渲染目标纹理的核心功能类解析完之后,我们就没有什么还不可以理解的了。现在我们来打开RenderTextureTest.h:

copy
    //演示用的层,做为基类使用
  1. classRenderTextureTest:publiccclayer
  2. //加载当前层时的处理
  3. virtualvoidonEnter();
  4. //取得标题
  5. virtualstd::stringtitle();
  6. //取得副标题
  7. virtualstd::stringsubtitle();
  8. //重新启动当前演示
  9. voidrestartCallback(CCObject*pSender);
  10. //下一个演示
  11. voidnextCallback(CCObject*pSender);
  12. //上一个演示
  13. voidbackCallback(CCObject*pSender);
  14. 对应CPP:

    copy
    //场景索引
  1. staticintsceneIdx=-1;
  2. //最大的演示层数量,四个
  3. #defineMAX_LAYER4
  4. //创建相应的演示层
  5. cclayer*createTestCase(intnIndex)
  6. //根据索引创建相应的演示层实例。
  7. switch(nIndex)
  8. case0:returnnewRenderTextureSave();
  9. case1:newRenderTextureIssue937();
  10. case2:newRenderTextureZbuffer();
  11. case3:newRenderTextureTestDepthStencil();
  12. //下一个演示实例
  13. cclayer*nextTestCase()
  14. sceneIdx++;
  15. sceneIdx=sceneIdx%MAX_LAYER;
  16. cclayer*pLayer=createTestCase(sceneIdx);
  17. pLayer->autorelease();
  18. returnpLayer;
  19. //上一个演示实例
  20. cclayer*backTestCase()
  21. sceneIdx--;
  22. inttotal=MAX_LAYER;
  23. if(sceneIdx<0)
  24. sceneIdx+=total;
  25. cclayer*pLayer=createTestCase(sceneIdx);
  26. pLayer->autorelease();
  27. returnpLayer;
  28. //重新运行当前的演示实例。
  29. cclayer*restartTestCase()
  30. //加载当前层时的处理。
  31. voidRenderTextureTest::onEnter()
  32. //先调用基类的相应函数
  33. cclayer::onEnter();
  34. //取得屏幕大小
  35. CCSizes=CCDirector::sharedDirector()->getWinSize();
  36. //创建相应的文字标签
  37. cclabelTTF*label=cclabelTTF::create(title().c_str(),255); background-color:inherit">"Arial",26);
  38. //将文字标签放到当前层下。
  39. addChild(label,1);
  40. //将文字标签放置在屏幕中央上部。
  41. label->setPosition(ccp(s.width/2,s.height-50));
  42. std::stringstrSubtitle=subtitle();
  43. if(!strSubtitle.empty())
  44. //如果副标题文字有效,创建相应的文字标签显示标题
  45. cclabelTTF*l=cclabelTTF::create(strSubtitle.c_str(),255); background-color:inherit">"Thonburi",16);
  46. //将副标题放入当前层下并放在主标题之下位置。
  47. addChild(l,0); background-color:inherit">l->setPosition(ccp(s.width/2,s.height-80));
  48. //创建用于控制动画演示的菜单
  49. //用于点击返回上一个动画演示的菜单项。
  50. CcmenuItemImage*item1=CcmenuItemImage::create("Images/b1.png","Images/b2.png",//用于点击重新运行当前动画演示的菜单项。
  51. CcmenuItemImage*item2=CcmenuItemImage::create("Images/r1.png",255); background-color:inherit">"Images/r2.png",menu_selector(RenderTextureTest::restartCallback));
  52. //用于点击重新运行下一个动画演示的菜单项。
  53. CcmenuItemImage*item3=CcmenuItemImage::create("Images/f1.png",255); background-color:inherit">"Images/f2.png",menu_selector(RenderTextureTest::nextCallback));
  54. //由上面三个菜单项创建菜单
  55. Ccmenu*menu=Ccmenu::create(item1,item2,item3,NULL);
  56. //设置菜单和各菜单项的位置。
  57. menu->setPosition(CCPointZero);
  58. item1->setPosition(ccp(s.width/2-item2->getContentSize().width*2,item2->getContentSize().height/2));
  59. item2->setPosition(ccp(s.width/2,item2->getContentSize().height/2));
  60. item3->setPosition(ccp(s.width/2+item2->getContentSize().width*2,0); background-color:inherit">//将菜单放入到当前层下。
  61. addChild(menu,0); background-color:inherit">//响应重启当前演示的函数
  62. voidRenderTextureTest::restartCallback(CCObject*pSender)
  63. //创建一个新的场景,创建一个新的当前演示层并放入到这个场景中。
  64. CCScene*s=newRenderTextureScene();
  65. s->addChild(restartTestCase());
  66. //运行创建的场景。
  67. CCDirector::sharedDirector()->replaceScene(s);
  68. s->release();
  69. //响应进行下一个演示的函数
  70. voidRenderTextureTest::nextCallback(CCObject*pSender)
  71. //创建一个新的场景,创建下一个演示层并放入到这个场景中。
  72. newRenderTextureScene();
  73. s->addChild(nextTestCase());
  74. //运行创建的场景。
  75. //响应进行上一个演示的函数
  76. voidRenderTextureTest::backCallback(CCObject*pSender)
  77. //创建一个新的场景,创建上一个演示层并放入到这个场景中。
  78. s->addChild(backTestCase());
  79. std::stringRenderTextureTest::title()
  80. return"Notitle";
  81. //取得副标题
  82. std::stringRenderTextureTest::subtitle()
  83. "";
  84. 一个演示:保存渲染目标纹理。

    说明:在屏幕上触屏移动,可以不断的使用随机顶点色的火球点图片精灵来做为刷子绘制线条。点击右边的“Clear”可以将屏幕清为随机色。而这些图像都是输出到纹理的。点击“SaveImage”可以保存这个纹理为PNG或JPG。

    截图


    代码:

    copy

    //由上面的类派生出的类,可以将目标纹理保存成为图片
  1. classRenderTextureSave:publicRenderTextureTest
  2. RenderTextureSave();
  3. ~RenderTextureSave();
  4. //取得标题
  5. //响应触屏时移动事件
  6. voidcctouchesMoved(CCSet*touches,CCEvent*event);
  7. //清除图片图像
  8. voidclearImage(CCObject*pSender);
  9. //保存纹理到图片
  10. voidsaveImage(CCObject*pSender);
  11. private:
  12. //目标纹理
  13. CCRenderTexture*m_pTarget;
  14. //代表刷子的精灵
  15. CCSprite*m_pBrush;
  16. 对应CPP:

    copy

    //构选
  1. RenderTextureSave::RenderTextureSave()
  2. //取得屏幕大小
  3. CCSizes=CCDirector::sharedDirector()->getWinSize();
  4. //创建一个目标纹理,用于把场景渲染到其中。
  5. m_pTarget=CCRenderTexture::create(s.width,s.height,kCCTexture2DPixelFormat_RGBA8888);
  6. //占用它,对其引用计数器加一。
  7. m_pTarget->retain();
  8. //设置目标纹理的位置放在屏幕中央。
  9. m_pTarget->setPosition(ccp(s.width/2,s.height/2));
  10. //将目标纹理放入到当前层下。
  11. this->addChild(m_pTarget,-1);
  12. //创建一个刷子的精灵,载入的是火球的图片
  13. m_pBrush=CCSprite::create("Images/fire.png");
  14. m_pBrush->retain();
  15. //设置精灵为红色
  16. m_pBrush->setColor(ccRED);
  17. //设置透明度为20%
  18. m_pBrush->setopacity(20);
  19. //设置当前层响应触屏事件。
  20. this->setTouchEnabled(//创建一个菜单文字的字体,大小为16。
  21. CcmenuItemFont::setFontSize(16);
  22. //创建两个菜单文字,分别为“保存图像”和“清空图像”。
  23. CcmenuItem*item1=CcmenuItemFont::create("SaveImage",menu_selector(RenderTextureSave::saveImage));
  24. CcmenuItem*item2=CcmenuItemFont::create("Clear",menu_selector(RenderTextureSave::clearImage));
  25. //由这两个菜单项创建菜单,并放入当前层下。
  26. this->addChild(menu);
  27. //设置菜单项按纵向排列。
  28. menu->alignItemsvertically();
  29. //设置菜单的位置。
  30. menu->setPosition(ccp(s.width-80,s.height-30));
  31. stringRenderTextureSave::title()
  32. "Touchthescreen";
  33. stringRenderTextureSave::subtitle()
  34. "Press'SaveImage'tocreateansnapshotoftherendertexture";
  35. //清除图片图像。
  36. voidRenderTextureSave::clearImage(cocos2d::CCObject*pSender)
  37. //对目标纹理调用clear即可以将其清空为相应的颜色。
  38. //这里对,R,G,B,A的色彩分量做了0~1间的随机,产生出随机的色彩。
  39. m_pTarget->clear(CCRANDOM_0_1(),CCRANDOM_0_1(),CCRANDOM_0_1());
  40. //保存图像。
  41. voidRenderTextureSave::saveImage(cocos2d::CCObject*pSender)
  42. //创建一个计数器,用来统计保存的次数
  43. intcounter=0;
  44. //要保存文件名称
  45. charpng[20];
  46. sprintf(png,255); background-color:inherit">"image-%d.png",counter);
  47. charjpg[20];
  48. sprintf(jpg,255); background-color:inherit">"image-%d.jpg",0); background-color:inherit">//对目标纹理调用savetoFile将纹理上的图像保存为PNG和JPG两种格式的图片
  49. m_pTarget->savetoFile(png,kCCImageFormatPNG);
  50. m_pTarget->savetoFile(jpg,0); background-color:inherit">//取得纹理对应的CCImage实例指针
  51. CCImage*pImage=m_pTarget->newCCImage();
  52. //将PNG图片和CCImage实例中的信息加载到纹理管理器中。
  53. CCTexture2D*tex=CCTextureCache::sharedTextureCache()->addUIImage(pImage,png);
  54. //删除pImage
  55. CC_SAFE_DELETE(pImage);
  56. //由纹理tex创建精灵sprite。
  57. CCSprite*sprite=CCSprite::createWithTexture(tex);
  58. //设置缩放值为原来0.3倍
  59. sprite->setScale(0.3f);
  60. //将精灵放到当前层下。
  61. addChild(sprite);
  62. //设置精灵位置。
  63. sprite->setPosition(ccp(40,40));
  64. sprite->setRotation(counter*3);
  65. //打印日志
  66. "Imagesaved%sand%s",png,jpg);
  67. //计数器加一
  68. counter++;
  69. RenderTextureSave::~RenderTextureSave()
  70. //对占用的目标纹得和刷子精灵的引用计数减一。
  71. m_pBrush->release();
  72. m_pTarget->release();
  73. //纹理管理器释放不用的纹理。
  74. CCTextureCache::sharedTextureCache()->removeUnusedTextures();
  75. //响应触屏时移动事件
  76. voidRenderTextureSave::cctouchesMoved(CCSet*touches,CCEvent*event)
  77. //取得触点
  78. CCTouch*touch=(CCTouch*)touches->anyObject();
  79. //取得触点的当前位置。
  80. CCPointstart=touch->getLocation();
  81. //取得触点的上一个位置。
  82. CCPointend=touch->getPrevIoUsLocation();
  83. //开始渲染到目标纹理
  84. m_pTarget->begin();
  85. //取得当前位置和上一个位置的距离。
  86. floatdistance=ccpdistance(start,end);
  87. //如果距离大于1像素。
  88. if(distance>1)
  89. intd=(int)distance;
  90. //则在上一个位置和当前位置间连一条线,每个像素渲染一下刷子精灵。
  91. inti=0;i<d;i++)
  92. //计算X和Y方向的偏移。
  93. floatdifx=end.x-start.x;
  94. floatdify=end.y-start.y;
  95. //通过偏移计算斜率。
  96. floatdelta=(float)i/distance;
  97. //通过直线公式计数出连像上第i个位置的像素位置设置给精灵。
  98. m_pBrush->setPosition(ccp(start.x+(difx*delta),start.y+(dify*delta)));
  99. //设置一个随机的旋转值给精灵。
  100. m_pBrush->setRotation(rand()%360);
  101. //在给一个限定范围的随机缩放大小给精灵。
  102. floatr=(float)(rand()%50/50.f)+0.25f;
  103. m_pBrush->setScale(r);
  104. /*m_pBrush->setColor(ccc3(CCRANDOM_0_1()*127+128,255));*/
  105. //UseCCRANDOM_0_1()willcauseerrorwhenloadinglibtests.soonandroid,Idon'tkNowwhy.
  106. //设置一个随机的颜色给精灵。
  107. m_pBrush->setColor(ccc3(rand()%127+128,255));
  108. //Callvisittodrawthebrush,don'tcalldraw..
  109. //将精灵绘制出来。
  110. m_pBrush->visit();
  111. //结束渲染到纹理,则由精灵构成的连线图像就被渲染到纹理中了。
  112. m_pTarget->end();
  113. 第二个演示:渲染小球到目标纹理。

    说明:将纵向排列的两个小球的精灵渲染到目标纹理上,在场景中左边一列显示两个小球,右边一列显示目标纹理。

    代码:

    copy

      //由上面的类派生出的类,。
    1. classRenderTextureIssue937:RenderTextureIssue937();
    2. //取得副标题
    3. copy
        RenderTextureIssue937::RenderTextureIssue937()
      1. //创建一个色层做为背景放入到当前层下。
      2. cclayerColor*background=cclayerColor::create(ccc4(200,200,255));
      3. addChild(background);
      4. //创建第一个精灵
      5. CCSprite*spr_premulti=CCSprite::create(spr_premulti->setPosition(ccp(16,48));
      6. //创建第二个精灵。
      7. CCSprite*spr_nonpremulti=CCSprite::create("Images/fire.png");
      8. spr_nonpremulti->setPosition(ccp(16,16));
      9. CCRenderTexture*rend=CCRenderTexture::create(32,64,0); background-color:inherit">//如果失败则返回
      10. if(NULL==rend)
      11. return;
      12. //开始渲染图像到目标纹理。
      13. rend->begin();
      14. //先渲染第一个精灵。
      15. spr_premulti->visit();
      16. //再渲染第二个精灵。
      17. spr_nonpremulti->visit();
      18. //结束渲染到纹理。
      19. rend->end();
      20. //取得屏幕大小。
      21. //设置第一个精灵的位置。
      22. spr_premulti->setPosition(ccp(s.width/2-16,s.height/2+16));
      23. //设置第二个精灵的位置。
      24. spr_nonpremulti->setPosition(ccp(s.width/2-16,s.height/2-16));
      25. //设置目标纹理的位置。
      26. rend->setPosition(ccp(s.width/2+16,s.height/2));
      27. //将上面三个结点都放到当前层之下。
      28. addChild(spr_nonpremulti);
      29. addChild(spr_premulti);
      30. addChild(rend);
      31. std::stringRenderTextureIssue937::title()
      32. "Testingissue#937";
      33. std::stringRenderTextureIssue937::subtitle()
      34. "Allimagesshouldbeequal...";
      35. 第三个演示:渲染不同Z值的精灵到目标纹理。

        说明:在屏幕上创建了一系列不同Z值的文字标签和精灵,当触屏按下松开后将屏幕画面绘制到目标纹理,创建一个精灵使用这个目标纹理并在屏幕上运行一个显示到渐隐的动画。

        截图


        代码:

        copy

          classRenderTextureZbuffer:RenderTextureZbuffer();
        1. //响应触屏的一些事件
        2. //按下并移动事件的响应
        3. //按下事件的响应
        4. voidcctouchesBegan(CCSet*touches,0); background-color:inherit">//抬起事件的响应
        5. voidcctouchesEnded(CCSet*touches,0); background-color:inherit">//取得标题
        6. virtualstd::stringtitle();
        7. virtualstd::stringsubtitle();
        8. //渲染屏幕快照
        9. voidrenderScreenShot();
        10. private:
        11. //使用的精灵批次优化处理结点。
        12. cocos2d::CCSpriteBatchNode*mgr;;
        13. //用到的若干精灵。
        14. cocos2d::CCSprite*sp1;
        15. cocos2d::CCSprite*sp2;
        16. cocos2d::CCSprite*sp3;
        17. cocos2d::CCSprite*sp4;
        18. cocos2d::CCSprite*sp5;
        19. cocos2d::CCSprite*sp6;
        20. cocos2d::CCSprite*sp7;
        21. cocos2d::CCSprite*sp8;
        22. cocos2d::CCSprite*sp9;
        23. copy
            RenderTextureZbuffer::RenderTextureZbuffer()
          1. //设置当前层响应触屏事悠扬。
          2. true);
          3. CCSizesize=CCDirector::sharedDirector()->getWinSize();
          4. //创建文字标签
          5. cclabelTTF*label=cclabelTTF::create("vertexZ=50",255); background-color:inherit">"MarkerFelt",64);
          6. //设置文字标签的位置并放入到当前层下。
          7. label->setPosition(ccp(size.width/2,size.height*0.25f));
          8. this->addChild(label);
          9. //创建第二个文字标签
          10. cclabelTTF*label2=cclabelTTF::create("vertexZ=0",64);
          11. //设置文字标签的位置并放入到当前层下。
          12. label2->setPosition(ccp(size.width/2,size.height*0.5f));
          13. this->addChild(label2);
          14. //创建第三个文字标签
          15. cclabelTTF*label3=cclabelTTF::create("vertexZ=-50",0); background-color:inherit">label3->setPosition(ccp(size.width/2,size.height*0.75f));
          16. this->addChild(label3);
          17. //分别对三个文字标签设置不同的顶点Z值。
          18. label->setVertexZ(50);
          19. label2->setVertexZ(0);
          20. label3->setVertexZ(-50);
          21. //由circle.plist
          22. CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("Images/bugs/circle.plist");
          23. //创建相应的精灵批次优化结点。
          24. mgr=CCSpriteBatchNode::create("Images/bugs/circle.png",9);
          25. this->addChild(mgr);
          26. //创建9个精灵
          27. sp1=CCSprite::createWithSpriteFrameName("circle.png");
          28. sp2=CCSprite::createWithSpriteFrameName("circle.png");
          29. sp3=CCSprite::createWithSpriteFrameName(sp4=CCSprite::createWithSpriteFrameName(sp5=CCSprite::createWithSpriteFrameName(sp6=CCSprite::createWithSpriteFrameName(sp7=CCSprite::createWithSpriteFrameName(sp8=CCSprite::createWithSpriteFrameName(sp9=CCSprite::createWithSpriteFrameName(//将其加入到批次优化结点中,给予不同的Z值。
          30. mgr->addChild(sp1,9);
          31. mgr->addChild(sp2,0); background-color:inherit">mgr->addChild(sp3,7);
          32. mgr->addChild(sp4,6);
          33. mgr->addChild(sp5,5);
          34. mgr->addChild(sp6,4);
          35. mgr->addChild(sp7,3);
          36. mgr->addChild(sp8,2);
          37. mgr->addChild(sp9,0); background-color:inherit">//对这九个精灵设置不同的顶点Z值。
          38. sp1->setVertexZ(400);
          39. sp2->setVertexZ(300);
          40. sp3->setVertexZ(200);
          41. sp4->setVertexZ(100);
          42. sp5->setVertexZ(0);
          43. sp6->setVertexZ(-100);
          44. sp7->setVertexZ(-200);
          45. sp8->setVertexZ(-300);
          46. sp9->setVertexZ(-400);
          47. //设置第九个放大2倍,顶点色为黄色。
          48. sp9->setScale(2);
          49. sp9->setColor(ccYELLOW);
          50. stringRenderTextureZbuffer::title()
          51. "TestingZBufferinRenderTexture";
          52. stringRenderTextureZbuffer::subtitle()
          53. "Touchscreen.Itshouldbegreen";
          54. voidRenderTextureZbuffer::cctouchesBegan(cocos2d::CCSet*touches,cocos2d::CCEvent*event)
          55. //遍历所有的触点。
          56. CCSetIteratoriter;
          57. CCTouch*touch;
          58. for(iter=touches->begin();iter!=touches->end();++iter)
          59. //将九个精灵放在触点位置。
          60. touch=(CCTouch*)(*iter);
          61. CCPointlocation=touch->getLocation();
          62. sp1->setPosition(location);
          63. sp2->setPosition(location);
          64. sp3->setPosition(location);
          65. sp4->setPosition(location);
          66. sp5->setPosition(location);
          67. sp6->setPosition(location);
          68. sp7->setPosition(location);
          69. sp8->setPosition(location);
          70. sp9->setPosition(location);
          71. //按下并移动事件的响应。
          72. voidRenderTextureZbuffer::cctouchesMoved(CCSet*touches,CCEvent*event)
          73. //遍历所有的触点。
          74. CCSetIteratoriter;
          75. CCTouch*touch;
          76. for(iter=touches->begin();iter!=touches->end();++iter)
          77. touch=(CCTouch*)(*iter);
          78. CCPointlocation=touch->getLocation();
          79. sp1->setPosition(location);
          80. sp2->setPosition(location);
          81. sp3->setPosition(location);
          82. sp4->setPosition(location);
          83. sp5->setPosition(location);
          84. sp6->setPosition(location);
          85. sp7->setPosition(location);
          86. sp8->setPosition(location);
          87. sp9->setPosition(location);
          88. //抬起事件的响应
          89. voidRenderTextureZbuffer::cctouchesEnded(CCSet*touches,153); font-size:14px; word-wrap:normal; border:none; background-color:inherit">this->renderScreenShot();
          90. //渲染屏幕快照
          91. voidRenderTextureZbuffer::renderScreenShot()
          92. //创建一个512,512大小的渲染目标纹理。
          93. CCRenderTexture*texture=CCRenderTexture::create(512,512);
          94. //如果无效直接返回。
          95. if(NULL==texture)
          96. return;
          97. //设置锚点为左下角。
          98. texture->setAnchorPoint(ccp(0,0));
          99. texture->begin();
          100. //将当前层渲染一遍。
          101. this->visit();
          102. texture->end();
          103. //创建一个精灵。
          104. CCSprite*sprite=CCSprite::createWithTexture(texture->getSprite()->getTexture());
          105. //设置精灵的位置,透明度,Y方向翻转。
          106. sprite->setPosition(ccp(256,256));
          107. sprite->setopacity(182);
          108. sprite->setFlipY(1);
          109. //将精灵放入到当前层的最前面。
          110. this->addChild(sprite,999999);
          111. //设置为绿色。
          112. sprite->setColor(ccGREEN);
          113. //让精灵运行一个动画序列,表现为渐渐消失。
          114. sprite->runAction(CCSequence::create(CCFadeto::create(2,0),0); background-color:inherit">CCHide::create(),0); background-color:inherit">NULL));
          115. 第四个演示:测试模版缓冲目标纹理。

            说明

            关于模版缓冲可以先看一下博文:

            http://www.cnblogs.com/aokman/archive/2010/12/13/1904723.html

            本例是开启模版测试,然后绘制球精灵,但只写A通过模版测试,对通过的像素位置设置模版值为1,之后向右上移动1/4大小球的位置,对模版值为0的区域设置通过来绘制球精灵,这样的效果约会有1/4缺失。

            注意:不幸的是,经测试所有版本似乎都无效,我不知道是不是哪里存在BUG,还是我的错误

            现实是这样的:


            代码的做法我用Photoshop做了一个结果图,本应是这样:


            copy
              //由上面的基类派生出的类,。
            1. classRenderTextureTestDepthStencil:RenderTextureTestDepthStencil();
            2. copy
                RenderTextureTestDepthStencil::RenderTextureTestDepthStencil()
              1. //创建一个精灵,设置其位置,10倍放大。
              2. CCSprite*sprite=CCSprite::create(sprite->setPosition(ccp(s.width*0.25f,0); background-color:inherit">sprite->setScale(10);
              3. //创建一个目标纹理,用于存储深度缓冲。
              4. CCRenderTexture*rend=CCRenderTexture::create(s.width,kCCTexture2DPixelFormat_RGBA4444,CC_GL_DEPTH24_STENCIL8);
              5. //设置模版缓冲的掩码值。
              6. glStencilMask(0xFF);
              7. //清空目标纹理的深度缓冲和模板缓冲为0。
              8. rend->beginWithClear(0,0); background-color:inherit">//开启模版测试。
              9. glEnable(GL_STENCIL_TEST);
              10. //设置绘制图像的像素部分总是可以通过模版测试
              11. glStencilFunc(GL_ALWAYS,1,0xFF);
              12. //设置更新操作为:
              13. //1,模板测试失败时保持当前的模板值不变。
              14. //2,模板测试通过,深度测试失败时保持当前的模板值不变。
              15. //3,模板测试通过,深度测试通过时将当前的模板值设置为参考值。
              16. glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
              17. //设置对颜色缓冲区的R,G,B,A位是否执行写入操作。这里只写A。
              18. glColorMask(0,0); background-color:inherit">//将精灵渲染一遍。
              19. sprite->visit();
              20. //设置精灵位置向右上偏移一些
              21. sprite->setPosition(ccpAdd(sprite->getPosition(),ccpMult(ccp(sprite->getContentSize().width*sprite->getScale(),sprite->getContentSize().height*sprite->getScale()),0.5)));
              22. //设置比较条件,如果像素参考值不等于模板值通过测试。
              23. glStencilFunc(GL_NOTEQUAL,0xFF);
              24. //设置对颜色缓冲区的R,G,B,A位执行写入操作。
              25. glColorMask(1,0); background-color:inherit">//精灵再渲染一遍。
              26. rend->end();
              27. //关闭模版缓冲测试。
              28. gldisable(GL_STENCIL_TEST);
              29. //设置目标纹理的位置。
              30. rend->setPosition(ccp(s.width*0.5f,s.height*0.5f));
              31. //将目标纹理放到当前层下。
              32. this->addChild(rend);
              33. //标题
              34. std::stringRenderTextureTestDepthStencil::title()
              35. "TestingdepthStencilattachment";
              36. std::stringRenderTextureTestDepthStencil::subtitle()
              37. "Circleshouldbemissing1/4ofitsregion";
              38. 上面这个例子如果真存在问题,希望Cocos2d-x开发组能有看到并做下修改。最后代码余下的就是场景了:

                copy
                  //演示用的场景
                1. classRenderTextureScene:publicTestScene
                2. //运行场景时的处理
                3. voidrunThistest();
                4. copy
                    //运行演示场景。
                  1. voidRenderTextureScene::runThistest()
                  2. //创建下一个演示层放入到当前的场景中。
                  3. cclayer*pLayer=nextTestCase();
                  4. addChild(pLayer);
                  5. //运行当前场景。
                  6. CCDirector::sharedDirector()->replaceScene(this);
                  7. 渲染到纹理,就是这么个东西了。很有用的技术,希望各位好好掌握。

                    原文地址:https://www.jb51.cc/cocos2dx/338273.html

                    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

                    相关推荐