通过cocos2d-x的CCGLProgram和CCShaderCache的实现来分析OpenGL ES中的Shader编程

在OpenGL ES中,Shader是着色器,包括两种:顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)。每个program对象有且仅有一个Vertex Shader对象和一个Fragment Shader对象连接到它。 

 


Shader和Program编程步骤:

1. 创建Shader
      1)编写Vertex Shader和Fragment Shader源码。

      2)创建两个shader 实例:GLuint   glCreateShader(GLenum type);

      3)给Shader实例指定源码。 glShaderSource

      4)在线编译shaer源码 void   glCompileShader(GLuint shader)


2. 创建Program

      1)创建program  GLuint   glCreateProgram(void)

      2)绑定shader到program 。 void   glAttachShader(GLuint program, GLuint shader)。每个program必须绑定一个Vertex Shader 和一个Fragment Shader。

      3)链接program 。 void   glLinkProgram(GLuint program)

      4)使用porgram 。 void   glUseProgram(GLuint program)


在cocos2d-x中使用两个类CCGLProgram和CCShaderCache来完成这些操作,其中CCGLProgram类是基本类,封装了对OpenGL ES接口的调用,而CCShaderCache通过CCGLProgram来完成对shaders的缓存和管理。

 

bool CCGLProgram::initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray)

{

    m_uProgram = glCreateProgram(); //创建一个Program,id为m_uProgram

    CHECK_GL_ERROR_DEBUG();



    m_uVertShader = m_uFragShader = 0;



    if (vShaderByteArray)

    {

        //创建顶点着色器并编译,id为m_uVertShader,vShaderByteArray是顶点着色器的源码    

        if (!compileShader(&m_uVertShader, GL_VERTEX_SHADER, vShaderByteArray))

        {

            CCLOG("cocos2d: ERROR: Failed to compile vertex shader");

        }

    }



    // Create and compile fragment shader

    if (fShaderByteArray)

    {

        //创建片元着色器并编译,id为m_uFragShader,fShaderByteArray是片元着色器的源码。    

        if (!compileShader(&m_uFragShader, GL_FRAGMENT_SHADER, fShaderByteArray))

        {

            CCLOG("cocos2d: ERROR: Failed to compile fragment shader");

        }

    }



    if (m_uVertShader)

    {

        //绑定顶点着色器

        glAttachShader(m_uProgram, m_uVertShader);

    }

    CHECK_GL_ERROR_DEBUG();



    if (m_uFragShader)

    {

        //绑定片元着色器    

        glAttachShader(m_uProgram, m_uFragShader);

    }

    m_pHashForUniforms = NULL;

    

    CHECK_GL_ERROR_DEBUG();



    return true;

}



bool CCGLProgram::compileShader(GLuint * shader, GLenum type, const GLchar* source)

{

    GLint status;

 

    if (!source)

    {

        return false;

    }

    

    const GLchar *sources[] = {

#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)

        (type == GL_VERTEX_SHADER ? "precision highp float;\n" : "precision mediump float;\n"),

#endif

        "uniform mat4 CC_PMatrix;\n"

        "uniform mat4 CC_MVMatrix;\n"

        "uniform mat4 CC_MVPMatrix;\n"

        "uniform vec4 CC_Time;\n"

        "uniform vec4 CC_SinTime;\n"

        "uniform vec4 CC_CosTime;\n"

        "uniform vec4 CC_Random01;\n"

        "//CC INCLUDES END\n\n",

        source,

    };



    *shader = glCreateShader(type); //创建shader

    glShaderSource(*shader, sizeof(sources)/sizeof(*sources), sources, NULL);  //指定源码

    glCompileShader(*shader); //编译shader



    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status); //获得shader编译的结果



    if (! status)  //编译失败打印log

    {

        GLsizei length;

        glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length);

        GLchar* src = (GLchar *)malloc(sizeof(GLchar) * length);

        

        glGetShaderSource(*shader, length, NULL, src);

        CCLOG("cocos2d: ERROR: Failed to compile shader:\n%s", src);

        

        if (type == GL_VERTEX_SHADER)

        {

            CCLOG("cocos2d: %s", vertexShaderLog());

        }

        else

        {

            CCLOG("cocos2d: %s", fragmentShaderLog());

        }

        free(src);



        abort();

    }

    return (status == GL_TRUE);

}



 

下面是初始化Shader的过程,通过CCShaderCache::loadDefaultShaders来完成。

 

void CCShaderCache::loadDefaultShaders()

{

    // Position Texture Color shader

    CCGLProgram *p = new CCGLProgram(); //创建CCGLProgram对象来操作OpenGL的shader

    loadDefaultShader(p, kCCShaderType_PositionTextureColor); //完成该CCGLProgram对象的初始化,如shaders的创建,编译和绑定

                                                              //此处创建的是顶点纹理颜色的program.



    m_pPrograms->setObject(p, kCCShader_PositionTextureColor); //存入字典,key为kCCShader_PositionTextureColor

    p->release();



    // Position Texture Color alpha test

    p = new CCGLProgram();

    loadDefaultShader(p, kCCShaderType_PositionTextureColorAlphaTest);



    m_pPrograms->setObject(p, kCCShader_PositionTextureColorAlphaTest);

    p->release();



    //

    // Position, Color shader

    //

    p = new CCGLProgram();

    loadDefaultShader(p, kCCShaderType_PositionColor);  //此处创建的是顶点颜色的program.



    m_pPrograms->setObject(p, kCCShader_PositionColor);

    p->release();



    //

    // Position Texture shader

    //

    p = new CCGLProgram();

    loadDefaultShader(p, kCCShaderType_PositionTexture);  //此处创建的是顶点纹理的program.



    m_pPrograms->setObject(p, kCCShader_PositionTexture);

    p->release();



    //

    // Position, Texture attribs, 1 Color as uniform shader

    //

    p = new CCGLProgram();

    loadDefaultShader(p, kCCShaderType_PositionTexture_uColor);



    m_pPrograms->setObject(p ,kCCShader_PositionTexture_uColor);

    p->release();



    //

    // Position Texture A8 Color shader

    //

    p = new CCGLProgram();

    loadDefaultShader(p, kCCShaderType_PositionTextureA8Color);

    

    m_pPrograms->setObject(p, kCCShader_PositionTextureA8Color);

    p->release();



    //

    // Position and 1 color passed as a uniform (to simulate glColor4ub )

    //

    p = new CCGLProgram();

    loadDefaultShader(p, kCCShaderType_Position_uColor);

    

    m_pPrograms->setObject(p, kCCShader_Position_uColor);

    p->release();

    

    //

    // Position, Legth(TexCoords, Color (used by Draw Node basically )

    //

    p = new CCGLProgram();

    loadDefaultShader(p, kCCShaderType_PositionLengthTexureColor);

    

    m_pPrograms->setObject(p, kCCShader_PositionLengthTexureColor);

    p->release();

}



void CCShaderCache::loadDefaultShader(CCGLProgram *p, int type)

{

    switch (type) {

        case kCCShaderType_PositionTextureColor:

            //shaders的创建,编译和绑定,不同的program的顶点着色源码和片元着色源码不同。

            p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColor_frag);

            

            //绑定属性名称和索引,属性名称在shader源码中已经定义。

            p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);

            p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);

            p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);

            

            break;

        case kCCShaderType_PositionTextureColorAlphaTest:

            p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColorAlphaTest_frag);

            

            p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);

            p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);

            p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);



            break;

        case kCCShaderType_PositionColor:  

            p->initWithVertexShaderByteArray(ccPositionColor_vert ,ccPositionColor_frag);

            

            p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);

            p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);



            break;

        case kCCShaderType_PositionTexture:

            p->initWithVertexShaderByteArray(ccPositionTexture_vert ,ccPositionTexture_frag);

            

            p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);

            p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);



            break;

        case kCCShaderType_PositionTexture_uColor:

            p->initWithVertexShaderByteArray(ccPositionTexture_uColor_vert, ccPositionTexture_uColor_frag);

            

            p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);

            p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);



            break;

        case kCCShaderType_PositionTextureA8Color:

            p->initWithVertexShaderByteArray(ccPositionTextureA8Color_vert, ccPositionTextureA8Color_frag);

            

            p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);

            p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);

            p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);



            break;

        case kCCShaderType_Position_uColor:

            p->initWithVertexShaderByteArray(ccPosition_uColor_vert, ccPosition_uColor_frag);    

            

            p->addAttribute("aVertex", kCCVertexAttrib_Position);    

            

            break;

        case kCCShaderType_PositionLengthTexureColor:

            p->initWithVertexShaderByteArray(ccPositionColorLengthTexture_vert, ccPositionColorLengthTexture_frag);

            

            p->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);

            p->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);

            p->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);

            

            break;

        default:

            CCLOG("cocos2d: %s:%d, error shader type", __FUNCTION__, __LINE__);

            return;

    }

    

    p->link(); //调用glLinkProgram链接

    p->updateUniforms();

    

    CHECK_GL_ERROR_DEBUG();

}



上面创建的几种类型的program说明如下:

enum {    

    kCCShaderType_PositionTextureColor, //顶点格式为位置+纹理UV+材质色  

    kCCShaderType_PositionTextureColorAlphaTest, //顶点格式为顶点格式为位置+纹理UV+材质色+用于AlphaTest的ALPHA值  

  

    kCCShaderType_PositionColor, // 顶点格式为位置+材质色  

  

    kCCShaderType_PositionTexture, //顶点格式为位置+纹理UV   

  

    kCCShaderType_PositionTexture_uColor, //顶点格式为位置+纹理UV+材质色  

  

    kCCShaderType_PositionTextureA8Color, //顶点格式为位置+纹理UV+灰度  

  

    kCCShaderType_Position_uColor, //顶点格式为位置+材质色   

      

    kCCShaderType_MAX,  //枚举结束值  

}; 


以类型为kCCShaderType_PositionTextureColor的program为例,它的顶点着色源码和片元着色源码分别为ccShader_PositionTextureColor_vert.h和
ccShader_PositionTextureColor_frag.h。

 


ccShader_PositionTextureColor_vert.h内容为:

 

"                                                   \n\

attribute vec4 a_position;                          \n\

attribute vec2 a_texCoord;                          \n\

attribute vec4 a_color;                             \n\

                                                    \n\

#ifdef GL_ES                                        \n\

varying lowp vec4 v_fragmentColor;                  \n\

varying mediump vec2 v_texCoord;                    \n\

#else                                               \n\

varying vec4 v_fragmentColor;                       \n\

varying vec2 v_texCoord;                            \n\

#endif                                              \n\

                                                    \n\

void main()                                         \n\

{                                                   \n\

    gl_Position = CC_MVPMatrix * a_position;        \n\

    v_fragmentColor = a_color;                      \n\

    v_texCoord = a_texCoord;                        \n\

}                                                   \n\

";


ccShader_PositionTextureColor_frag.h内容为:

 

 

"                                           \n\

#ifdef GL_ES                                \n\

precision lowp float;                       \n\

#endif                                      \n\

                                            \n\

varying vec4 v_fragmentColor;               \n\

varying vec2 v_texCoord;                    \n\

uniform sampler2D CC_Texture0;              \n\

                                            \n\

void main()                                 \n\

{                                           \n\

    gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);            \n\

}                                           \n\

";


 

 

 

你可能感兴趣的:(cocos2d-x)