首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

在使用 CCRenderTexture、shader 绘制几何图元时需要注意的一些细节有关问题

2013-01-06 
在使用 CCRenderTexture、shader 绘制几何图元时需要注意的一些细节问题一直对 cocos2d 的 opengl 混合机制

在使用 CCRenderTexture、shader 绘制几何图元时需要注意的一些细节问题

一直对 cocos2d 的 opengl 混合机制不太明晰,昨日纠查 bug 的时候连带着注意了一下,

CCNode 中包含了一个 m_glServerState 的成员,这个东西是与 混合开启与否相关联的,

混合默认是开启的。

CCLayerColor、CCSprite 等类型里面包含了一个 m_blendFunc 成员,这个东西是与采用怎么样的混合方式相关联的。

在 CCProtocols.h 的 CCBlendProtocol 的 @brief 注释里面可以看到,

默认是采用 {GL_ONE, GL_ONE_MINUS_SRC_ALPHA} 或 

{GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA} 的混合方式,选择哪种与 premultiplied alpha 相关。


当一个场景被绘制的时候,会根据子节点的 z 值来决定绘制的先后顺序,

在具体绘制某个可视子节点的时候,会根据该节点的 m_blendFunc 成员来决定用什么样的方式混合。

cocos2d 只是对 opengles 简化使用的一种封装!这里存在一个问题:

在 CCRenderTexture 上面绘制东西的时候,绘制几何图元 或 拿 sprite 对象执行 visit 动作的时候,

如果不调用  glBlendFunc 来指定混合方式的话,就会沿用绘制上一个 sprite 的混合方式。

显然这就让此次操作的结果带有不确定性,因为谁也没办法预料之前绘制的最后一个 sprite 采用的是何种混合方式。

(这里说的有点儿夸张了,实际上很多数情况下都不会对 sprite 的 blendFunc 做设置)

最稳妥的方式就是:在 CCRenderTexture 上面绘制的东西的时候即时设置一下混合方式,消除不确定性

代码:ccGLBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);

需求多变,但是记住默认的混合参数是没有害处的,默认的为 {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}。


另外一个问题就是,该采用何种的 shader?

毫无疑问,我在刚接触 shader 的时候也是碰了一鼻子灰,

经过一连串开发的磨砺,我才逐渐得以一窥全貌

(不敢托大,这里的全貌指的是有了一个大体的正确认识,gles1都还未能摸透就被迫迁移到2,这令我亚历山大)

cocos2d 缓存了一些常用的 shader,分别是用于一些特别的绘制情形。


打个比方来说,现在有一个需求,要绘制 50 个相同颜色的点,

要达到最高的性能,可以用 kCCShader_Position_uColor 这个枚举值所代表的 shader 来画,

这个 uColor 的 u 表示 uniform,具有 “统一” 的意思,

也就是说,不管花多少个点,都只能采用同一种颜色。


但如果我要绘制五十个不同颜色的点呢?

这确实是个问题,很显然已经超出上面那个缓存的 shader 对象所掌管的能力范围了。

不过这依然不是一个难题,用 kCCShader_PositionColor 从缓存里面拿相应的 shader 就能满足需求了~

具体方式是传入一个长度为 50 的颜色数组,再传入一个长度为 50 的位置数组,然后绘制。


挺能的啊,再出个难题!那五光十色的材质是怎么贴出来的呢?

答案也是  shader,而且是具备贴材质能力的 shader,

具体是那种我就不指明了,自己去摸索吧~

(提示:请于之前提及过的两个枚举值的定义处寻找答案)


又扩展了一些知识,当然这些知识是与主体有所关联的,

因为在 CCRenderTexture 上面绘制东西的时候也有关于 shader 方面的东西要注意,

与混合方式差不多的意思,不过这里的是 shader 是否启用 vertexArrayAttribute

没做仔细测试,不清楚 cocos2d  缓存的 kCCShader_Position_uColor 是否默认就启用了 Position 的 vertexArrayAttribute

同上,为了消除不确定因素,这里最好也是使用一下下面的代码:

ccGLEnableVertexAttribs//// ItemRender.cpp// DreamStack//// Created by Bruce Yang on 12-12-26.// Copyright (c) 2012年 __MyCompanyName__. All rights reserved.//#include "ItemRender.h"/** * p~ */void ItemRender::drawSolidPolygon(const b2Vec2* vertices, int32 vertexCount) { m_pGLProgram->use();m_pGLProgram->setUniformForModelViewProjectionMatrix(); ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position); ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glUniform4f( m_iColorLocation, 1.f, 1.f, 1.f, 1.f); glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount); CHECK_GL_ERROR_DEBUG();}void ItemRender::drawSolidCircle(const b2Vec2& center, float32 radius) { m_pGLProgram->use();m_pGLProgram->setUniformForModelViewProjectionMatrix(); ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position); ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); const float32 t_fSegsCount = 32.f;int t_iVertsCount = 32;const float32 t_fIncrement = 2.f * b2_pi / t_fSegsCount;float32 theta = 0.f; GLfloat glVertices[t_iVertsCount * 2];for (int32 i = 0; i < t_fSegsCount; ++ i) {b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));glVertices[i * 2] = v.x;glVertices[i * 2 + 1] = v.y;theta += t_fIncrement;} glUniform4f( m_iColorLocation, 1.f, 1.f, 1.f, 1.f);glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, glVertices);glDrawArrays(GL_TRIANGLE_FAN, 0, t_iVertsCount); CHECK_GL_ERROR_DEBUG();}#pragma markItemRender* ItemRender::sharedInstance() { if (!m_pItemRender) { m_pItemRender = new ItemRender(); } return m_pItemRender;}void ItemRender::setupCachedShader() { m_pGLProgram = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_Position_uColor); m_iColorLocation = glGetUniformLocation(m_pGLProgram->getProgram(), "u_color");}void ItemRender::setupMyShader() { m_pGLProgram = NULL; m_iColorLocation = (GLint)0;}ItemRender::ItemRender() { this->setupCachedShader();}ItemRender::~ItemRender() { }ItemRender* ItemRender::m_pItemRender = 0;

还有就是,带 ccGL- 前缀的方法都是 cocos2d 封装的一层带缓存作用的方法。

其内部机制也非常简单,就是判断一下当前要改变到的值和老值是否相同,不同的话才去修改该值。

后续还会对 cocos2d-x 2.x,opengles 2.0 做更深入细致的探索,敬请关注~


热点排行