cocos渲染引擎分析(六)-----shader渲染流程之内置shader构建

单纯使用OPENGl写一个场景渲染时,可以很容易的看出OEPNGL整个渲染流程,cocos引擎将整个渲染流程进行了封装分类,各司其职。虽然很多人说cocos渲染底层是学生写的,不少问题,然而cocos这个小巧的引擎,确是一个很好的学习引擎渲染架构的方式,本篇主要讲,引擎底层怎么组织shader,读取模型,材质,创建生成渲染指令的过程进行剖析,本章记录内置shader的构建过程。

内置shader和材质构建:

    首先,程序创建scene后,会创建一个默认相机,相机创建过程中,会创建一个CameraBackgroundBrush,用于刷黑屏幕,代码如下:

Camera::Camera()
{
    _clearBrush = CameraBackgroundBrush::createDepthBrush(1.f);
    _clearBrush->retain();
}
CameraBackgroundBrush创建过程会调用下面的函数:
bool CameraBackgroundDepthBrush::init()
{
    //获取擦除相机的shader
    auto shader = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_CAMERA_CLEAR);
    //创建ProgramState,具体而言就是材质,shader的具体化
    _glProgramState = GLProgramState::getOrCreateWithGLProgram(shader);
    _glProgramState->retain();
    
     。。。。。。。
    //绘制矩形背景
    。。。。。。。。
    return true;
}

其中,程序CameraBackgroundBrush初始过程中会调用GLProgramCache::getInstance(),如果GLProgramCache( 内置shader的集合)不存在,就创建,并返回,单例模式,运行过程中只有一个。

GLProgramCache* GLProgramCache::getInstance()
{
    if (!_sharedGLProgramCache) {
        _sharedGLProgramCache = new (std::nothrow) GLProgramCache();
        if (!_sharedGLProgramCache->init())
        {
            CC_SAFE_DELETE(_sharedGLProgramCache);
        }
    }
    return _sharedGLProgramCache;
}

GLProgramCache的初始化函数如下:

bool GLProgramCache::init()
{
    loadDefaultGLPrograms();
}
void GLProgramCache::loadDefaultGLPrograms()
{
    //加载各种材质类型的shader
    GLProgram *p = new (std::nothrow) GLProgram();
    loadDefaultGLProgram(p, kShaderType_PositionTextureColor);
    _programs.emplace(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR, p);

    ............
    
    p = new (std::nothrow) GLProgram();
    loadDefaultGLProgram(p, kShaderType_3DPositionNormalTex);
    _programs.emplace(GLProgram::SHADER_3D_POSITION_NORMAL_TEXTURE, p);
}


GLProgram指可以附加着色器对象的对象,具体而言可以理解为一个材质对象,用于的顶点着色器和面片着色器shader的编译,链接和顶点属性,uniform参数获取,后面使用时,使用GLProgram类向shader中传递顶点变量和Uniform变量。下面以kShaderType_3DPositionNormalTex(3D法线纹理材质)为例,记录GLProgram的创建过程:

void GLProgramCache::loadDefaultGLProgram(GLProgram *p, int type)
{
    case kShaderType_3DPositionNormalTex://根据特定类别调用特定的加载特定的.ver和.frag文件
            {
                std::string def = getShaderMacrosForLight();
                p->initWithByteArrays((def +         
                std::string(cc3D_PositionNormalTex_vert)).c_str(), (def + 
                std::string(cc3D_ColorNormalTex_frag)).c_str());
            }

}
//GLProgram的创建过程如下
bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray, const std::string& compileTimeHeaders, const std::string& compileTimeDefines)
{
    _program = glCreateProgram();//创建一个空program
    //预定义开关,用于编译shader时,静态编译部分shader(#if #else),不同if和else 
    std::string replacedDefines = "";
    useRealTimeBRDF = replaceDefines(compileTimeDefines, replacedDefines);
    _vertShader = _fragShader = 0;
    //创建顶点着色器
    if (vShaderByteArray)
        if (!compileShader(&_vertShader, GL_VERTEX_SHADER, vShaderByteArray..))
           return false;
    // 创建面片着色器
    if (fShaderByteArray)
        if (!compileShader(&_fragShader, GL_FRAGMENT_SHADER ...))
            return false;
   //绑定顶点着色器到当前program
    if (_vertShader)
        glAttachShader(_program, _vertShader);
    if (_fragShader)
        glAttachShader(_program, _fragShader);
    //清空Uniform变量
    clearHashUniforms();
    return true;
}

至此,完成了所有内置shader编译连接,使用时,不同材质使用不同的GLProgram,然后传递属性参数。

猜你喜欢

转载自blog.csdn.net/wang371372/article/details/88837710
今日推荐