• 在使用 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(kCCVertexAttribFlag_Position);


    上一些代码来看一看吧(一个专门用来往 RenderTexture 上面画东西的单例类):

    ItemRender.h

    //
    //  ItemRender.h
    //  DreamStack
    //
    //  Created by Bruce Yang on 12-12-26.
    //  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
    //
    
    #ifndef DreamStack_ItemRender_h
    #define DreamStack_ItemRender_h
    
    #include "cocos2d.h"
    #include "Box2D.h"
    
    USING_NS_CC;
    
    class ItemRender {
    public:
        void drawSolidPolygon(const b2Vec2* vertices, int32 vertexCount);
        
        void drawSolidCircle(const b2Vec2& center, float32 radius);
        
        static ItemRender* sharedInstance();
        
    private:
        // 采用 cocos2d 缓存的 shader 对象~
        void setupCachedShader();
        
        // 采用由自己亲手创建的 shader 对象~
        void setupMyShader();
        
        ItemRender();
        ~ItemRender();
        
        static ItemRender* m_pItemRender;
    	CCGLProgram* m_pGLProgram;
    	GLint m_iColorLocation;
    };
    
    #endif
    

    ItemRender.cpp

    //
    //  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 mark
    
    ItemRender* 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 做更深入细致的探索,敬请关注~


  • 相关阅读:
    10进制转换为二十六进制字符串A-Z
    解决Missing artifact jdk.tools:jdk.tools:jar:1.8报错
    JAVA中AES对称加密和解密以及与Python兼容
    Nginx配置客户端SSL双向认证
    (备忘)最全的正则表达式
    (备忘)Python字符串、元组、列表、字典互相转换的方法
    (备忘)Nodepad++常用快捷键
    (备忘)正则表达式全部符号解释
    (备忘)Window7下安装Python2.6及Django1.4
    (备忘)Java Map 遍历
  • 原文地址:https://www.cnblogs.com/java20130723/p/3212070.html
Copyright © 2020-2023  润新知