Cocos2dx源码记录(1) CCGLProgram

790 阅读6分钟

前言: 这个系列是我自己在看cocos2dx源码时记录的一些比较重要的数据结构跟方法中间可能穿插些opengl的知识. 每个介绍的类之间没有固定引用顺序,仅作为个人的记录,可能会有点乱(其实主要是为了怕记不住,这次看源码的目的是搞清楚 cocos的MVPMatrix的使用)

#1 CCGLProgram CCGLProgram 是 管理opengl 管线中 GLProgram 和其相关的 着色器, 顶点属性, 统一变量等等的类, 以下是其中几个比较关键的结构体

##1.1 VertextAttrib

VertexAtttrib结构体在数据存储上于 glGetActiveAttrib获取的结构时一致的 index : 指的是vertexShader顶点着色器中 attribute 属性 , 在shader中 可以用(layout=?)指定index size:属性对应类型存储的数量 例如color = {1.0, 1.0, 1.0}, size 为 3, type 为GL_FLOAT type: 指的是属性对应的存储类型 name: 在顶点着色器中属性的名字


/**VertexAttrib is a structure to encapsulate data got from glGetActiveAttrib.*/
 struct VertexAttrib
{
    /**Index of attribute, start from 0.*/
    GLuint index;
    /**Number of Data type in the attribute, could range from 0-4.*/
    GLint size;
    /**Data type of the attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.*/
    GLenum type;
    /**The string name in vertex shader.*/
    std::string name;
};

这个结构体主要被应用于一下opengl函数的设置

void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,const GLvoid * pointer);
//GLboolean normalized 属性主要用于标识传入的属性的各个分量是否需要归一化, stride是相同属性的两个数据间的偏移, pointer代表的是属性的首个在buffer里的偏移

##1.2 Uniform Uniform 主要用于存储 glGetActiveUnifom 和glGetUniformLocation 的数据

/**Uniform is a structure to encapsulate data got from glGetActiveUniform and glGetUniformLocation.*/
struct Uniform
{
    /**The place where the uniform placed, starts from 0.*/
    GLint location;
    /**Number of data type in attribute.*/
    GLint size;
    /**Data type of the attribute.*/
    GLenum type;
    /**String of the uniform name.*/
    std::string name;
};

uniform 统一变量是在一个glprogram 通用的 统一变量空间可以被顶点着色器个片段着色器同时引用 location : 统一变量在glprogram里的位置 ,这个可用的统一变量数是有上限的 size: 相应统一变量的分量数量 type:相应统一变量的数据类型 name:相应统一变量的名字 结构体内容可被用于一下opengl函数

void glUniform*(GLint location,  GLsizei count,  const GLfloat *value)
//count:指明要更改的元素个数。如果目标uniform变量不是一个数组,那么这个值应该设为1;如果是数组,则应该设置为>=1。
//value:指定一个具有count个数值的数组指针,用来更新指定的uniform变量。

##1.3 VertexIndex 预定义的顶点属性的对应的index, 占坑

/**Enum the preallocated vertex attribute. */
    enum
    {
        /**Index 0 will be used as Position.*/
        VERTEX_ATTRIB_POSITION,
        /**Index 1 will be used as Color.*/
        VERTEX_ATTRIB_COLOR,
        /**Index 2 will be used as Tex coord unit 0.*/
        VERTEX_ATTRIB_TEX_COORD,
        /**Index 3 will be used as Tex coord unit 1.*/
        VERTEX_ATTRIB_TEX_COORD1,
        /**Index 4 will be used as Tex coord unit 2.*/
        VERTEX_ATTRIB_TEX_COORD2,
        /**Index 5 will be used as Tex coord unit 3.*/
        VERTEX_ATTRIB_TEX_COORD3,
        /**Index 6 will be used as Normal.*/
        VERTEX_ATTRIB_NORMAL,
        /**Index 7 will be used as Blend weight for hardware skin.*/
        VERTEX_ATTRIB_BLEND_WEIGHT,
        /**Index 8 will be used as Blend index.*/
        VERTEX_ATTRIB_BLEND_INDEX,
        /**Index 9 will be used as tangent.*/
        VERTEX_ATTRIB_TANGENT,
        /**Index 10 will be used as Binormal.*/
        VERTEX_ATTRIB_BINORMAL,
        VERTEX_ATTRIB_MAX,

        // backward compatibility
        VERTEX_ATTRIB_TEX_COORDS = VERTEX_ATTRIB_TEX_COORD,
    };

##1.4 UniformIndex 预定义的统一变量的对应的index, 占坑. 这里代码用到的枚举名字大家如果有学过opengl的话应该会非常熟悉

 enum
    {
        /**Ambient color.*/
        UNIFORM_AMBIENT_COLOR,
        /**Projection matrix.*/
        UNIFORM_P_MATRIX,
        /**Model view matrix.*/
        UNIFORM_MV_MATRIX,
        /**Model view projection matrix.*/
        UNIFORM_MVP_MATRIX,
        /**Normal matrix.*/
        UNIFORM_NORMAL_MATRIX,
        /**Time.*/
        UNIFORM_TIME,
        /**sin(Time).*/
        UNIFORM_SIN_TIME,
        /**cos(Time).*/
        UNIFORM_COS_TIME,
        /**Random number.*/
        UNIFORM_RANDOM01,
        /** @{
        * Sampler 0-3, used for texture.
        */
        UNIFORM_SAMPLER0,
        UNIFORM_SAMPLER1,
        UNIFORM_SAMPLER2,
        UNIFORM_SAMPLER3,
        /**@}*/
        UNIFORM_MAX,
    };

##1.4built in shader 内建的shader 字符串

  /**
    @name Built Shader types
    @{
    */
    /** ETC1 ALPHA supports for 2d */
    static const char* SHADER_NAME_ETC1AS_POSITION_TEXTURE_COLOR;
    static const char* SHADER_NAME_ETC1AS_POSITION_TEXTURE_COLOR_NO_MVP;

    static const char* SHADER_NAME_ETC1AS_POSITION_TEXTURE_GRAY;
    static const char* SHADER_NAME_ETC1AS_POSITION_TEXTURE_GRAY_NO_MVP;

    /**Built in shader for 2d. Support Position, Texture and Color vertex attribute.*/
    static const char* SHADER_NAME_POSITION_TEXTURE_COLOR;
    /**Built in shader for 2d. Support Position, Texture and Color vertex attribute, but without multiply vertex by MVP matrix.*/
    static const char* SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP;
    /**Built in shader for 2d. Support Position, Texture vertex attribute, but include alpha test.*/

  //省略一大堆
    /**
     Built in shader for camera clear
     */
    static const char* SHADER_CAMERA_CLEAR;
    /**
    end of built shader types.
    @}
    */

##1.5 built in uniform 内建的 uniform 默认名

  /**
    @name Built uniform names
    @{
    */
    /**Ambient Color uniform.*/
    static const char* UNIFORM_NAME_AMBIENT_COLOR;
    /**Projection Matrix uniform.*/
    static const char* UNIFORM_NAME_P_MATRIX;
    /**Model view matrix uniform.*/
    static const char* UNIFORM_NAME_MV_MATRIX;
    /**Model view projection uniform.*/
    static const char* UNIFORM_NAME_MVP_MATRIX;
    /**Normal matrix uniform.*/
    static const char* UNIFORM_NAME_NORMAL_MATRIX;
    /**Time uniform.*/
    static const char* UNIFORM_NAME_TIME;
    /**Sin time uniform.*/
    static const char* UNIFORM_NAME_SIN_TIME;
    /**Cos time uniform.*/
    static const char* UNIFORM_NAME_COS_TIME;
    /**Random number uniform.*/
    static const char* UNIFORM_NAME_RANDOM01;
    /**
    @{ Sampler uniform 0-3, used for textures.
    */
    static const char* UNIFORM_NAME_SAMPLER0;
    static const char* UNIFORM_NAME_SAMPLER1;
    static const char* UNIFORM_NAME_SAMPLER2;
    static const char* UNIFORM_NAME_SAMPLER3;
    /**
    @}
    */
    /**Alpha test value uniform.*/
    static const char* UNIFORM_NAME_ALPHA_TEST_VALUE;
    /**
    end of Built uniform names
    @}
    */

1.6 built in attribute names

默认的内建属性名字

/**
        @name Built Attribute names
        @{
    */
    /**Attribute color.*/
    static const char* ATTRIBUTE_NAME_COLOR;
    /**Attribute position.*/
    static const char* ATTRIBUTE_NAME_POSITION;
    /**@{ Attribute Texcoord 0-3.*/
    static const char* ATTRIBUTE_NAME_TEX_COORD;
    static const char* ATTRIBUTE_NAME_TEX_COORD1;
    static const char* ATTRIBUTE_NAME_TEX_COORD2;
    static const char* ATTRIBUTE_NAME_TEX_COORD3;
    /**@}*/
    /**Attribute normal.*/
    static const char* ATTRIBUTE_NAME_NORMAL;
    /**Attribute blend weight.*/
    static const char* ATTRIBUTE_NAME_BLEND_WEIGHT;
    /**Attribute blend index.*/
    static const char* ATTRIBUTE_NAME_BLEND_INDEX;
    /**Attribute blend tangent.*/
    static const char* ATTRIBUTE_NAME_TANGENT;
    /**Attribute blend binormal.*/
    static const char* ATTRIBUTE_NAME_BINORMAL;
    /**
    end of Built Attribute names
    @}
    */

1.7 一些渲染流程管线方法的包装函数

挑选几个可以展示流程的 1.创建glprogram 省略了代码里如何使用内建shader名创建byteArray的过程

bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray, const std::string& compileTimeDefines)
{
    _program = glCreateProgram();
    CHECK_GL_ERROR_DEBUG();

    // convert defines here. If we do it in "compileShader" we will do it twice.
    // a cache for the defines could be useful, but seems like overkill at this point
    std::string replacedDefines = "";
    replaceDefines(compileTimeDefines, replacedDefines);

    _vertShader = _fragShader = 0;

    if (vShaderByteArray)
    {
        if (!compileShader(&_vertShader, GL_VERTEX_SHADER, vShaderByteArray, replacedDefines))
        {
            CCLOG("cocos2d: ERROR: Failed to compile vertex shader");
            return false;
       }
    }

    // Create and compile fragment shader
    if (fShaderByteArray)
    {
        if (!compileShader(&_fragShader, GL_FRAGMENT_SHADER, fShaderByteArray, replacedDefines))
        {
            CCLOG("cocos2d: ERROR: Failed to compile fragment shader");
            return false;
        }
    }

    if (_vertShader)
    {
        glAttachShader(_program, _vertShader);
    }
    CHECK_GL_ERROR_DEBUG();

    if (_fragShader)
    {
        glAttachShader(_program, _fragShader);
    }

    _hashForUniforms.clear();

    CHECK_GL_ERROR_DEBUG();

    return true;
}

2.链接

void GLProgram::link()

// 内部调用了
//void GLProgram::bindPredefinedVertexAttribs()
//绑定默认的顶点属性
//关键还是这个gl函数
//glBindAttribLocation(_program, attribute_locations[i].location, attribute_locations[i].attributeName);

3.使用

void GLProgram::use();
//内部实际调用 glUseProgram()
//很奇怪为什么没有dettachshader, 其实链接完就可以释放点shader在cpu端的内存了

4.更新 这里只找到对uniform统一变量的, MVPMatrix主要就是用uniform传入渲染管线的 网上的说法是cocos管理了一个变换矩阵的堆栈,用于管理和保存需要使用的矩阵数据

void GLProgram::updateUniforms()

5.其他类似删除释放glprogram , shader内存的包装方法都在源码中很容易找到

#3GLProgramCache 管理所有的GLProgram生死存亡的类

class CC_DLL GLProgramCache : public Ref
{
public:
    /**
    Constructor.
     * @js ctor
     */
    GLProgramCache();
    /**
    Destructor.
     * @js NA
     * @lua NA
     */
    ~GLProgramCache();

    /** returns the shared instance */
    /** 怀念的OC风格,现在都没人写OC了吗, 就想知道swift以后会直接兼容C++吗*/
    static GLProgramCache* getInstance();

    /** purges the cache. It releases the retained instance. */
    static void destroyInstance();

    /** @deprecated Use getInstance() instead */
    CC_DEPRECATED_ATTRIBUTE static GLProgramCache* sharedShaderCache();

    /** @deprecated Use destroyInstance() instead */
    CC_DEPRECATED_ATTRIBUTE static void purgeSharedShaderCache();

    /** loads the default shaders */
    void loadDefaultGLPrograms();
    CC_DEPRECATED_ATTRIBUTE void loadDefaultShaders() { loadDefaultGLPrograms(); }

    /** reload the default shaders */
    void reloadDefaultGLPrograms();
    CC_DEPRECATED_ATTRIBUTE void reloadDefaultShaders() { reloadDefaultGLPrograms(); }

    /** returns a GL program for a given key 
     */
    /*使用 对应的char* 变量作为索引 */
    //例子:GLProgram *p = getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR);
    GLProgram * getGLProgram(const std::string &key);
    CC_DEPRECATED_ATTRIBUTE GLProgram * getProgram(const std::string &key) { return getGLProgram(key); }
    CC_DEPRECATED_ATTRIBUTE GLProgram * programForKey(const std::string &key){ return getGLProgram(key); }

    /** adds a GLProgram to the cache for a given name */
    void addGLProgram(GLProgram* program, const std::string &key);
    CC_DEPRECATED_ATTRIBUTE void addProgram(GLProgram* program, const std::string &key) { addGLProgram(program, key); }
    
    /** reload default programs these are relative to light */
    void reloadDefaultGLProgramsRelativeToLights();

private:
    /**
    @{
        Init and load predefined shaders.
    */
    bool init();
    void loadDefaultGLProgram(GLProgram *program, int type);
    /**
    @}
    */

    /**Get macro define for lights in current openGL driver.*/
    /*获取宏定义的light GLSL方法*/
    std::string getShaderMacrosForLight() const;

    /**Predefined shaders.*/
    std::unordered_map<std::string, GLProgram*> _programs;
};

PS:第一次写可能像是直接贴代码, 实际也的确如此, 对渲染管线的流程也只是只言片语,不成逻辑,是在抱歉....如果对opengl有兴趣的话可以点击https://learnopengl.com/这里有全套的教程,简单易学.ios 开发可以github上搜索GPUImage项目作为学习opengles2.0的参考