美文网首页
20.opengl高级-高级GLSL

20.opengl高级-高级GLSL

作者: 天叔 | 来源:发表于2020-07-11 00:11 被阅读0次

    这一章编程实践的内容不多,主要是glsl高级的语言特征。原教程写的很好了。learnopengl-高级glsl

    这一节代码实践不多,阅读一遍,重在理解,做个笔记,加强记忆。

    一、GLSL内建变量

    1. 顶点着色器变量
    • gl_PointSize 设置顶点大小,默认禁用修改,DEMO:
    // 主程序
    glEnable(GL_PROGRAM_POINT_SIZE);
    
    //着色器
    void main()
    {
        gl_Position = projection * view * model * vec4(aPos, 1.0);    
        gl_PointSize = gl_Position.z;    
    }
    
    • gl_VertexID,基本没什么用,可读不可写,存储了正在绘制顶点的当前ID
    2. 片段着色器变量
    • gl_FragCoord,x和y分量是片段的窗口控件坐标,原点在左下角,可以通过gl_FragCoord分量对输出颜色做些特殊处理,DEMO:
    void main()
    {             
        if(gl_FragCoord.x < 400)
            FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        else
            FragColor = vec4(0.0, 1.0, 0.0, 1.0);        
    }
    
    gl_FragCoord使用
    • gl_FrontFacing,判断正向还是背向,和面剔除有相同的功效,demo:
    // 根据前脸还是后脸输出不同的纹理
    #version 330 core
    out vec4 FragColor;
    
    in vec2 TexCoords;
    
    uniform sampler2D frontTexture;
    uniform sampler2D backTexture;
    
    void main()
    {             
        if(gl_FrontFacing)
            FragColor = texture(frontTexture, TexCoords);
        else
            FragColor = texture(backTexture, TexCoords);
    }
    
    gl_FrontFacing使用
    • gl_FragDepth,这个稍微复杂点,可以用来修改片段的Z坐标,即深度值,如果没有设置gl_FragDepth,默认的回取gl_FragCoord.z。

    gl_FragDepth有个缺陷,会导致提前深度测试冲突禁用,原理很好理解,因为只要到真正片段着色器运行才知道实际的深度值,提前深度测试没有意义。从4.2版本开始有个折中的方案,定义gl_FragDepth变量的规则,提供给提前深度测试参考,做个粗略的评估

    layout (depth_<condition>) out float gl_FragDepth;
    
    condition的值

    demo:

    #version 420 core // 注意GLSL的版本!
    out vec4 FragColor;
    layout (depth_greater) out float gl_FragDepth;
    
    void main()
    {             
        FragColor = vec4(1.0);
        gl_FragDepth = gl_FragCoord.z + 0.1;
    }  
    

    二、接口块

    类似c语言中的struct,java中的类,不过多赘述,上代码,一看就明白,注意in和out的定义

    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec2 aTexCoords;
    
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
    
    out VS_OUT
    {
        vec2 TexCoords;
    } vs_out;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(aPos, 1.0);    
        vs_out.TexCoords = aTexCoords;
    }  
    

    三、Uniform缓冲对象

    主要讲Uniform块,稍微复杂了点,可以简单理解为类的静态变量,所有类对象可以共享,在opengl特殊的编程环境下整的略复杂。重点是理解内存对齐的策略和绑定的关系。

    1. 内存绑定关系,不同的shader可以绑定到相同的uniform缓冲对象上
    内存绑定关系

    分三步,创建uniform缓冲对象-->绑定shader对应uniform 字段到绑定点-->uniform缓冲对象绑定到相同的绑定点。关键代码:

    // 生成uniform 缓冲对象
    unsigned int uboExampleBlock;
    glGenBuffers(1, &uboExampleBlock);
    glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
    glBufferData(GL_UNIFORM_BUFFER, 152, NULL, GL_STATIC_DRAW); // 分配152字节的内存
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    
    // 将shader中的uniform字段绑定到相同的“绑定点”
    unsigned int lights_index = glGetUniformBlockIndex(shaderA.ID, "Lights");   
    glUniformBlockBinding(shaderA.ID, lights_index, 2);
    
    // 有两种方式,第二种稍微灵活点,可以支持更多的复用和拓展场景
    glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboExampleBlock); 
    // 或
    glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
    
    2. 理解Uniform块的每个成员的对齐偏移量,理解下面这段代码就可以了。
    layout (std140) uniform ExampleBlock
    {
                         // 基准对齐量       // 对齐偏移量
        float value;     // 4               // 0 
        vec3 vector;     // 16              // 16  (必须是16的倍数,所以 4->16)
        mat4 matrix;     // 16              // 32  (列 0)
                         // 16              // 48  (列 1)
                         // 16              // 64  (列 2)
                         // 16              // 80  (列 3)
        float values[3]; // 16              // 96  (values[0])
                         // 16              // 112 (values[1])
                         // 16              // 128 (values[2])
        bool boolean;    // 4               // 144
        int integer;     // 4               // 148
    }; 
    

    相关文章

      网友评论

          本文标题:20.opengl高级-高级GLSL

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