美文网首页
(四)着色器和程序

(四)着色器和程序

作者: YongtaoHuang | 来源:发表于2019-10-10 23:08 被阅读0次

    上一篇:(三)EGL简介:https://www.jianshu.com/p/bb6a13c6066f
    下一篇:(五)OpenGL ES着色语言:https://www.jianshu.com/p/5712ec080cc2

    渲染一个三角形需要以下3部分:
    1、顶点着色器对象
    2、片元着色器对象
    3、一个程序对象

    着色器和程序

    需要创建两个基本对象才能用着色器进行渲染:着色器对象程序对象
    着色器对象可视为C语言的编译器。
    程序对象可视为C语言的链接程序。
    再OpenGL ES中,每个程序对象必须链接一个顶点着色器和一个着色器对象。而程序对象被链接为用于渲染的最后“可执行程序”。

    创建和编译一个着色器

    主要函数有:

    // 创建着色器对象
    GLuint glCreateShader(GLenum type)
    // 删除着色器
    void glDeleteShader(GLuint shader)
    // 加载着色器源码
    void glShaderSource(GLuint shader, GLsizei count,
        const GLchar* const *string,
        const GLint *length)
    // 编译着色器
    void glCompileShader(GLuint shader)
    

    加载着色器源码:

    GLuint LoadShader ( GLenum type, const char *shaderSrc ) {
        GLuint shader;
        GLint compiled;
        // 创建着色器对象
        shader = glCreateShader ( type );
        if ( shader == 0 ) {
            return 0;
        }
        // 加载着色器源码
        glShaderSource ( shader, 1, &shaderSrc, NULL );
        // 编译着色器
        glCompileShader ( shader );
        // 确认编译状态
        glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
        if ( !compiled ) {
            // 编译失败时检索编译消息
            GLint infoLen = 0;
            glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
            if ( infoLen > 1 ) {
                char* infoLog = malloc ( sizeof ( char ) * infoLen );
                // 检索信息日志
                glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
                esLogMessage(“Error compiling shader:\n%s\n”, infoLog);
                free ( infoLog );
            }
            // 删除着色器
            glDeleteShader ( shader );
            return 0;
        }
        return shader;
    }
    

    创建和链接程序

    主要函数有:

    // 创建一个程序对象
    GLuint glCreateProgram()
    // 删除一个程序对象
    Void glDeleteProgram(GLuint program)
    // 连接一个着色器
    void glAttachShader(GLuint program, GLuint shader)
    // 链接到程序
    void glLinkProgram(GLuint program)
    // 使用这个程序对象
    void glUseProgram(GLuint program)
    

    创建程序、连接着色器并链接程序

    // 创建一个程序对象
    programObject = glCreateProgram ( );
    if ( programObject == 0 ) {
        return 0;
    }
    // 连接一个顶点着色器
    glAttachShader ( programObject, vertexShader );
    // 连接一个片元着色器
    glAttachShader ( programObject, fragmentShader );
    // 链接到程序
    glLinkProgram ( programObject );
    // 检查链接状态
    glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
    if ( !linked ) {
        // 编译失败时检索编译消息
        GLint infoLen = 0;
        glGetProgramiv( programObject, GL_INFO_LOG_LENGTH, &infoLen);
        if ( infoLen > 1 ) {
            char* infoLog = malloc ( sizeof ( char ) * infoLen );
            // 检索信息日志
            glGetProgramInfoLog ( programObject, infoLen, NULL,
            infoLog );
            esLogMessage ( “Error linking program:\n%s\n”, infoLog );
            free ( infoLog );
        }
        // 删除一个程序对象
        glDeleteProgram ( programObject );
        return FALSE;
    }
    // 使用这个程序对象
    glUseProgram ( programObject );
    

    统一变量和属性

    统一变量(uniform)是存储应用程序通过OpenGL ES 3.0 API传递给着色器的只读常数值得变量。分两类:
    1、统一变量块:

    uniform TransformBlock {
        mat4 matViewProj;
        mat3 matNormal;
        mat3 matTexGen;
    };
    

    2、统一变量:

    uniform mat4 matViewProj;
    uniform mat3 matNormal;
    uniform mat3 matTexGen;
    

    获取和设置统一变量

    主要函数有:

    // 获取每一个统一变量的细节
    void glGetActiveUniform(GLuint program, 
        GLuint index,
        GLsizei bufSize, 
        GLsizei *length,
        GLint *size, 
        GLenum *type,
        GLchar *name)
     // 获取统一变量值的位置
    GLint glGetUniformLocation(GLuint program,
        const GLchar* name)
    

    查询活动统一变量:

    GLint maxUniformLen;
    GLint numUniforms;
    char *uniformName;
    GLint index;
    // 获取程序中活动统一变量的数量
    glGetProgramiv ( progObj, GL_ACTIVE_UNIFORMS, &numUniforms );
    // 获取程序中活动统一变量的最大长度
    glGetProgramiv ( progObj, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen );
    uniformName = malloc ( sizeof ( char ) * maxUniformLen );
    for ( index = 0; index < numUniforms; index++ ) {
        GLint size;
        GLenum type;
        GLint location;
        // 获取每一个统一变量的细节
        glGetActiveUniform ( progObj, index, maxUniformLen, NULL, &size, &type, uniformName );
        // 获取统一变量值的位置
        location = glGetUniformLocation ( progObj, uniformName );
        switch ( type ) {
            case GL_FLOAT:
                //
                break;
            case GL_FLOAT_VEC2:
                //
                break;
            case GL_FLOAT_VEC3:
                //
                break;
            case GL_FLOAT_VEC4:
                //
                break;
            case GL_INT:
                //
                break;
                // ... Check for all the types ...
            default:
                // Unknown type
                break;
        }
    }
    

    统一变量缓冲区对象

    主要函数有:

    // 检索统一块索引
    GLuint glGetUniformBlockIndex(GLuint program,
        const GLchar *blockName)
    // 将统一块索引与绑定点关联
    void glUniformBlockBinding(GLuint program,
        GLuint blockIndex,
        GLuint blockBinding)
    // 获取lightData的大小
    void glGetActiveUniformBlockiv( GLuint program,
        GLuint index,
        GLenum pname,
        GLint *params)
    

    使用命名统一变量块LightTransform建立一个系统变量缓冲区对象:

    GLuint blockId, bufferId;
    GLint blockSize;
    GLuint bindingPoint = 1;
    GLfloat lightData[] = {
        // 光照方向 
        1.0f, 0.0f, 0.0f, 0.0f,
        // 光照位置
        0.0f, 0.0f, 0.0f, 1.0f
    };
    // 检索统一块索引
    blockId = glGetUniformBlockIndex ( program, “LightBlock” );
    // 将统一块索引与绑定点关联
    glUniformBlockBinding ( program, blockId, bindingPoint );
    // 获取lightData的大小
    glGetActiveUniformBlockiv ( program, blockId, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize );
    // 创建并填充缓冲区对象
    glGenBuffers ( 1, &bufferId );
    glBindBuffer ( GL_UNIFORM_BUFFER, bufferId );
    glBufferData ( GL_UNIFORM_BUFFER, blockSize, lightData, GL_DYNAMIC_DRAW);
    // 将缓冲区对象绑定到统一块绑定点
    glBindBufferBase ( GL_UNIFORM_BUFFER, bindingPoint, buffer );
    

    获取和设置属性

    对顶点属性的查询,可以用GL_ACTIVE_ATTRIBUTES查询找到活动属性列表,也可以
    glGetActiveAttrib()找到某个属性的特性。

    着色器编译器

    编译器必须将抽象表现形式转化为硬件的机器指令。这段工作主要代价为CPU时间和内存。
    OpenGL ES 3.0实现必须支持在线着色器编译。注意,一旦完成了应用程序中着色器的编译,记得调用glReleaseShaderCompiler释放资源。

    // 释放着色器编译器
    void glReleaseShaderCompiler (void)
    

    程序二进制码

    程序二进制码是完全编译和链接的程序的二进制表现形式。可以波窜再文件系统,避免重复再次编译。
    glGetProgramBinary用于检索程序二进制码:

    void glGetProgramBinary( GLuint program,     
        GLsizei bufSize,
        GLsizei *length, 
        GLenum binaryFormat,
        GLvoid *binary)
    

    当检索到程序二进制码之后,可以用glProgramBinary将器保存到文件系统:

    void glProgramBinary( GLuint program, 
        GLenum binaryFormat,
        const GLvoid *binary, 
        GLsizei length)
    

    小结

    本章主要内容包括创建、编译和链接着色器对象到程序对象的方法。

    上一篇:(三)EGL简介:https://www.jianshu.com/p/bb6a13c6066f
    下一篇:(五)OpenGL ES着色语言:https://www.jianshu.com/p/5712ec080cc2

    相关文章

      网友评论

          本文标题:(四)着色器和程序

          本文链接:https://www.haomeiwen.com/subject/fyagpctx.html