• 通过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;
    " : "precision mediump float;
    "),
    #endif
            "uniform mat4 CC_PMatrix;
    "
            "uniform mat4 CC_MVMatrix;
    "
            "uniform mat4 CC_MVPMatrix;
    "
            "uniform vec4 CC_Time;
    "
            "uniform vec4 CC_SinTime;
    "
            "uniform vec4 CC_CosTime;
    "
            "uniform vec4 CC_Random01;
    "
            "//CC INCLUDES END
    
    ",
            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:
    %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内容为:

    "                                                   
    
    attribute vec4 a_position;                          
    
    attribute vec2 a_texCoord;                          
    
    attribute vec4 a_color;                             
    
                                                        
    
    #ifdef GL_ES                                        
    
    varying lowp vec4 v_fragmentColor;                  
    
    varying mediump vec2 v_texCoord;                    
    
    #else                                               
    
    varying vec4 v_fragmentColor;                       
    
    varying vec2 v_texCoord;                            
    
    #endif                                              
    
                                                        
    
    void main()                                         
    
    {                                                   
    
        gl_Position = CC_MVPMatrix * a_position;        
    
        v_fragmentColor = a_color;                      
    
        v_texCoord = a_texCoord;                        
    
    }                                                   
    
    ";


    ccShader_PositionTextureColor_frag.h内容为:

    "                                           
    
    #ifdef GL_ES                                
    
    precision lowp float;                       
    
    #endif                                      
    
                                                
    
    varying vec4 v_fragmentColor;               
    
    varying vec2 v_texCoord;                    
    
    uniform sampler2D CC_Texture0;              
    
                                                
    
    void main()                                 
    
    {                                           
    
        gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);            
    
    }                                           
    
    ";


  • 相关阅读:
    isequal 和startswith 使用
    UVa10340
    UVa1368
    UVa455
    UVa1225
    UVa1586
    UVa 1585
    UVa10082
    UVa272
    NYOJ1
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3228715.html
Copyright © 2020-2023  润新知