• GLSL语言基础


    GLSLwiki   chs)是OpenGL(OpenGL ES、WebGL)的着色器语言,拥有如下特点:

    1. 基于C语言的语法(如:大小写敏感,每条语句必须以分号结尾),是一门面向过程的强类型语言(type sensitive language)

    2. 预处理中没有#include包含文件指令

    3. 除了bool、int、uint、float基础类型外,还支持数组类型,另外GLSL还内置了适合3D图形操作的向量与矩阵类型,以及采样器(纹理)类型   

    4. double、dvec*、dmat*类型需要#version 400及以上才支持

    5. 更严格类型隐式转换规则

    6. 变量没有赋初值时,都会被填充为false、0或0.0

    7. if条件语句和switch条件语句与C语言一致

    8. for循环语句和while循环语句与C语言一致

    9. return、continue和break与C语言一致。另外引入了discard,该关键字只能在fs中使用,表示放弃当前片元,直接处理下一个片元。

    10. 无指针、无字符和字符串类型

    11. 无union、无enum

    12. 向量、矩阵、自定义结构体变量可通过构造函数进行初始化

    13. 增添了一些C++语言的特性:如函数重载

    shader运行时,死循环或者崩溃,会导致进程无响应(弹出如下对话框),驱动崩溃重启

    与C语言一样,包括:预处理 -- 编译 -- 链接 -- 执行   四大步骤 

    注释

    单行注释

    // Hello GLSL.

    多行注释

    /*********************************
     This is my first GLSL.
     Let's take a look.
    *********************************/

    预处理

    #version XXX // 用于指定当前glsl文件的版本   

    ①不同的版本glsl,所能使用语言特性是不一样的。如:layout (location = 0) in vec3 Position;  // layout是330才支持的特性

    ②如果要加该#version指令,必须是当前glsl文件的第一句有效代码行

    ③如果不加该#version指令,默认为GLSL 1.1,即:#version 110   注:WebGL1.0中vs和fs开头不用写#version版本,其语法对应GLSL ES 1.0(或GLSL 1.1)

    #version 110          // GLSL 1.1  OpenGL 2.0  【默认】
    #version 120          // GLSL 1.2  OpenGL 2.1
    #version 130          // GLSL 1.3  OpenGL 3.0
    #version 140          // GLSL 1.4  OpenGL 3.1
    #version 150          // GLSL 1.5  OpenGL 3.2
    #version 330          // GLSL 3.3  OpenGL 3.3
    #version 330 core     // 【同上】
    #version 400          // GLSL 4.0  OpenGL 4.0
    #version 410          // GLSL 4.1  OpenGL 4.1
    #version 420          // GLSL 4.2  OpenGL 4.2
    #version 430          // GLSL 4.3  OpenGL 4.3
    #version 440          // GLSL 4.4  OpenGL 4.4
    #version 450          // GLSL 4.5  OpenGL 4.5
    #version 460          // GLSL 4.6  OpenGL 4.6
    
    #version 150 compatibility // GLSL 1.5 并向前兼容GLSL 1.2、1.3、1.4的语法
    
    #version 300 es // GLSL ES 3.0 或称 ESSL 3.0   注:声明为这个后,宏GL_ES会被定义为1 

    GLSL不同版本的差异点,可参考:这里

    #extension  extname : behaivor

    extname为编译器支持的扩展名称

    behaivor可以是require、enable、warn、disable

    #extension all : disable   // 禁用所有扩展
    
    #extension GL_NV_shadow_samplers_cube : enable  // 启用名为GL_NV_shadow_samplers_cube的扩展

    扩展行为说明

    扩展行为 说明
    require 扩展是必需的。若当前扩展不受支持,将抛出错误
    enable 启用扩展。若当前扩展不支持,将抛出警告
    warn 对于扩展的任何使用均抛出警告
    disable 禁用扩展。若当前扩展被使用,将抛出错误

    #if  #elif [defined(), !defined()]  #else    #ifdef   #ifndef     #endif   // 条件编译

    #define TEST1  // 定义为空的宏
    //#define TEST1 1  // 宏已被定义 编译失败 error C7101: Macro TEST1 redefined
    
    #ifdef TEST1  // 条件成立
    #endif
    
    //#if TEST1  // 空值不能进行条件判断 编译失败 error C0105: Syntax error in #if
    //#endif
    
    #undef TEST1  // 取消TEST1宏
    
    #if TEST1  // 条件不成立   注:OpenGL有效; 但openGL es下  编译失败  error C0105: Syntax error in #if
    #endif
    
    #ifndef TEST1  // 条件成立
    #endif
    
    #define TEST1 -1  // 定义为int的宏
    
    #define TEST2 // 定义为空的宏
    
    #if TEST1 && defined(TEST2) // 条件成立
    #endif
    
    #define TEST3 true // 定义为bool的宏
    
    #if TEST3  // 条件不成立  注:OpenGL有效;但openGL es下,bool不能进行条件判断  编译失败  error C0105: Syntax error in #if
    #endif
    
    #if !TEST3  // 条件成立   注:OpenGL有效;openGL es下,bool不能进行条件判断  编译失败  error C0105: Syntax error in #if
    #endif
    
    #if TEST3==true  // 条件成立  注:OpenGL有效;openGL es下,bool不能进行条件判断  编译失败  error C0105: Syntax error in #if
    #endif
    
    #if !defined(TEST0) && TEST1 && defined(TEST2) // 条件成立
    #endif
    
    #define TEST4 100  // 定义为int的宏
    
    #if TEST4  // 条件成立
    #endif
    
    #if TEST4 > 150
    #elif (TEST4 > 120) || TEST1 // 进入elif分支
    #endif
    
    #if !TEST4
    #else // 进入else分支
    #endif
    
    #define TEST5 2.0  // 定义为float的宏
    
    //#if TEST5  //float不能进行条件判断  编译失败  error C0105: Syntax error in #if
    //#endif
    
    //#if TEST5>0.0  //float不能进行条件判断  编译失败  error C0105: Syntax error in #if
    //#endif

    #if

    // Shader inputs and outputs keywords
    //
    // - ATTRIBUTE: used to mark a vertex shader inputs
    // - SHADER_IN: used to mark a non-vertex shader inputs
    // - SHADER_OUT: used to mark a non-fragment shader output
    // - OUT: used to mark a fragment shader output
    #if __VERSION__ >= 130
    
    #define ATTRIBUTE in
    #define SHADER_IN in
    #define SHADER_OUT out
    #define OUT out
    
    #else
    
    #define ATTRIBUTE attribute
    #define SHADER_IN varying
    #define SHADER_OUT varying
    #define OUT
    
    #endif
    
    // Support array attributes
    #if __VERSION__ >= 130
    
    #define ARRAY_ATTRIBUTE(name, size) name[size]
    
    #else
    
    #define ARRAY_ATTRIBUTE(name, size) name[size]
    
    #endif
    
    // Uniform blocks
    #if __VERSION__ >= 130
    
    #define BEGIN_UNIFORM_BLOCK(name)   uniform name {
    
    #define END_UNIFORM_BLOCK() };
    
    #else
    
    #define BEGIN_UNIFORM_BLOCK(name)
    
    #define END_UNIFORM_BLOCK()
    
    #endif
    
    // Input and output blocks
    #if __VERSION__ >= 150
    
    #define BEGIN_INPUT_BLOCK(name) in name {
    #define END_INPUT_BLOCK() };
    
    #define BEGIN_OUTPUT_BLOCK(name) out name {
    #define END_OUTPUT_BLOCK() };
    
    #else
    
    #define BEGIN_INPUT_BLOCK(name)
    #define END_INPUT_BLOCK()
    
    #define BEGIN_OUTPUT_BLOCK(name)
    #define END_OUTPUT_BLOCK()
    
    #endif
    
    // Texturing functions
    #if __VERSION__ >= 130
    
    #define TEXTURE_2D texture
    #define TEXTURE_3D texture
    #define TEXTURE_RECT texture
    #define TEXTURE_CUBE texture
    
    #if __VERSION__ >= 150
    #define TEXTURE_SIZE(sampler) textureSize(sampler)
    #else
    #define TEXTURE_SIZE(sampler) sampler ## _Size
    #endif
    
    #else
    
    #define TEXTURE_2D texture2D
    #define TEXTURE_3D texture3D
    #define TEXTURE_RECT texture2DRect
    #define TEXTURE_CUBE textureCube
    
    #endif
    
    // Invariance
    #if __VERSION__ >= 120
    #define INVARIANT invariant
    #else
    #define INVARIANT
    #endif
    
    // Attribute location
    #if defined(GL_ARB_explicit_attrib_location)
    #define LOCATION(loc)       layout(location = loc)
    #else
    #define LOCATION(loc)
    #endif
    
    // Geometry shader layout
    #if __VERSION__ >= 150
    #define GEOMETRY_LAYOUT_IN(from) layout (from) in
    #define GEOMETRY_LAYOUT(to, max) layout (to, max_vertices = max) out
    #else
    #define GEOMETRY_LAYOUT_IN(from)
    #define GEOMETRY_LAYOUT(to, max)
    #endif
    
    
    
    // 为GLSL ES着色器脚本时,需要设置float和int类型的精度
    #ifdef GL_ES
    precision mediump float;// 设置float类型的精度为中精度  注:高精度为highp、低精度为lowp
    precision mediump int;  // 设置int类型的精度为中精度  注:高精度为highp、低精度为lowp
    #endif

    #define  #undef     // 宏定义、宏取消

    #define TEST1 100  // 定义TEST1宏为100
    
    #ifdef TEST1  // 条件成立
    #undef TEST1   // 取消TEST1宏的定义
    #endif
    
    #if !defined(TEST1) // 条件成立
    #endif
    
    #define SQUARE(a) ((a)*(a))
    
    #define MAX(a,b)    // 宏必须在一行写完,多行写时必须带上 行连接符
        (((a) > (b)) ? (a) : (b))
    
    #define MERGE(a, b) a##b // ## 字符拼接符

    #line    // 指示下一行的行号,及当前所在的文件;该命令会修改__FILE__、__LINE__的值

    该命令是提供给编译器使用的,程序员最好不要使用该命令

    #if __LINE__==10  // 判断当前行号是否为10
    #endif
    
    #if __FILE__==0  // 条件成立  __FILE__好像缺省为0
    #endif
    
    #line 116 // 指定下一行的行号为116
    #if __LINE__==116  // 条件成立
    #endif
    
    #line 200 5  // 指定下一行的行号为200,当前文件的ID标识为5
    #if __FILE__==5  // 条件成立
    #endif

    #pragma   // 用来控制编译器的一些行为

    #pragma optimize(on) // 开启编译器优化 【默认】
    #pragma optimize(off) // 关闭编译器优化
    
    #pragma debug(on)  // 开启debug选项,以获得更多的调试信息
    #pragma debug(off) // 关闭debug选项 【默认】
    
    #pragma STDGL invariant(all)  // 让所有的变量全都不变   注:因为编译器需要保证不变性,所以会限制对着色器进行优化

    #error  // error命令被执行,会导致当前文件编译失败

    #if __VERSION__ >= 150 // __VERSION__为内置宏,十进制整数,为当前GLSL文件的版本号
    #error This is an error! // error C0000: This is an error!
    #endif

    __VERSION__、__FILE__、__LINE__、GL_ES、GL_FRAGMENT_PRECISION_HIGH

    #if __VERSION__ >= 330 // __VERSION__为内置宏,int类型,为当前GLSL文件的版本号
    #endif
    
    #line 100 3  // 指定下一行的行号为100,当前文件的ID标识为3
    #if __FILE__==3  // 条件成立  宏__FILE__为int类型,当前Source String的唯一ID标识
    #endif
    
    #if __LINE__==103  // 条件成立  宏__LINE__为int类型,当前的行号
    #endif
    
    #if GL_ES // OpenGL下,内置宏GL_ES未定义,条件不成立;openGL es下,GL_ES为1,条件成立
    #if GL_FRAGMENT_PRECISION_HIGH  // 若当前片元着色器支持高浮点精度,则宏GL_FRAGMENT_PRECISION_HIGH为1
    precision highp float; // 设置float类型的精度为高精度
    precision highp int; // 设置int类型的精度为高精度
    #else
    precision mediump float;// 设置float类型的精度为中精度
    precision lowp int;  // 设置int类型的精度为低精度
    #endif
    #endif

    运算符

    除了没有指针相关的运算符外,其他的与c语言完全一致

    注:对于向量、矩阵类型,运算符会在各个分量上进行

    变量

    变量名需要符合以下规则:

    ① 只能包括大小写字母、数字和下划线

    ② 变量名不能以数字开头

    ③ 不能是关键字或预留的关键字

    ④ 不能以gl_、webgl_或_webgl_开头

    全局变量:定义在函数体外的变量。作用域规则与c语言全局变量一致。

    局部变量:定义在函数内的变量。作用域规则与c语言局部变量一致。

    内置常量(以gl_开头)

    所在shader 常量
    vs

    const mediump int gl_MaxVertexAttribs = 16; // 可用的顶点输入变量(GLSL 1.3之前为attribute变量)的最大数量

    const mediump int gl_MaxVertexUniformVectors = 256;  // 可用的vec4统一变量(uniform变量)的最大数量  需要#version 410及以上

    const mediump int gl_MaxVertexOutputVectors = 16; // 可用的顶点输出变量(GLSL 1.3之前为varying变量)的最大数量  需要#version 410及以上

    const mediump int gl_MaxVertexTextureImageUnits = 16;  // 可用的纹理的最大数量

    const mediump int gl_MaxCombinedTextureImageUnits = 32; // vs和fs中可用的纹理的最大数量的总和

    fs

    const mediump int gl_MaxFragmentInputVectors = 15; // 片元输入变量(GLSL 1.3之前为varying变量)的最大数量  需要#version 410及以上

    const mediump int gl_MaxTextureImageUnits = 16;  // 可用的纹理的最大数量

    const mediump int gl_MaxFragmentUniformVectors = 224;  // 可用的vec4统一变量(uniform变量)的最大数量  需要#version 410及以上

    const mediump int gl_MaxDrawBuffers = 4;  // 多重渲染目标(MRT)的最大支持数量。

    const mediump int gl_MinProgramTexelOffset = -8;  // 内建ESSL函数texture*Offset偏移参数迟滞的最小偏移值  需要#version 410及以上

    const mediump int gl_MaxProgramTexelOffset = 7;  // 内建ESSL函数texture*Offset偏移参数迟滞的最大偏移值  需要#version 410及以上

    内置变量(以gl_开头)

    所在shader 变量
    vs

    vec4 gl_Position;  //必须将变换后的位置写入到这个变量中,用于输出顶点位置的裁剪坐标。该变量用highp精度限定符声明。

    float gl_PointSize;  // 用于写入以像素表示的点精灵尺寸。在渲染点时使用。该变量用highp精度限定符声明。

    int gl_VertexID; // 输入变量,用于保存当前顶点的索引。该变量用highp精度限定符声明。

    int gl_InstanceID; // 输入变量,用户保存当前图元的编号。对于常规的绘图调用,该值为0。该变量用highp精度限定符声明。

    bool gl_FrontFacing; // 一个特殊变量,但不是vs直接写入,而是根据vs生成的位置和渲染的图元类型生成的。

    struct gl_DepthRangeParameters
    {
        highp float near; // near Z
        highp float far; // far Z
        highp float diff; // far - near
    };
    uniform gl_DepthRangeParameters gl_DepthRange; // vs唯一内建统一变量:窗口坐标中的深度范围

    fs

    vec4 gl_FragCoord;  // 只读变量,保存窗口相对坐标(x,y,z,1/w)。

    bool gl_FrontFacing; // 只读变量,片段是正面时为ture,否则为false。

    vec2 gl_PointCoord;  // 只读变量,保存点精灵的纹理坐标,处于[0.0, 1.0]区间

    float gl_FragDepth;  // 一个只写输出变量。在fs中写入时,覆盖片段固定功能深度值。应谨慎使用该功能,可能禁用GPU的深度优化(如:Early-Z)

    vec4 gl_FragColor;  // fs输出的片元颜色

    const变量

    表示该变量的值不能被修改。声明的同时必须对它进行初始化,声明之后就不能再去改变它的值了,否则会导致编译错误。

    const int lightspeed = 399792458;  // 光速 m/s
    const vec4 red = vec4(1.0, 0.0, 0.0);  // 红色
    const mat4 identity = mat4(1.0);  // 4x4单位矩阵 

    顶点输入变量(GLSL 1.3之前为attribute变量)

    与顶点相关的输入型变量,被用来表示逐顶点的信息,必须声明为全局变量,仅在vs中使用。如:顶点的position、normal、uv等。这些变量为cpu传来的数据。

    其只能是float或由float组合成的复合类型(vec2、vec3、vec4、mat2、mat3、mat4)

    在#version 130及以上,顶点输入变量使用关键字in,而不再使用attribute

    #if __VERSION__ >= 130
    
    in vec3 position;
    in vec3 normal;
    in vec2 uv;
    in vec2 uv2;
    
    #else
    
    attribute vec3 position;
    attribute vec3 normal;
    attribute vec2 uv;
    attribute vec2 uv2;
    
    #endif

    顶点输入变量可以使用布局限定符来修饰

    layout (location = 0) in vec3 position;
    layout (location = 1) in vec3 normal;

    location的值由void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)函数的第一个参数index来指定

    统一变量(uniform变量)

    是只读的,与顶点和像素无关的输入型变量,被用来表示非逐顶点、非逐像素、各顶点、各像素共用的信息,必须声明为全局变量,可在vs和fs中使用。如:mvp矩阵

    可以是除了数组或结构体之外的任意类型。如果vs和fs中声明了同名的统一变量(uniform变量),那么它就会被两种着色器共享。

    vs代码:

    #version 330
    
    layout (location = 0) in vec3 Position;
    
    uniform mat4 gWVP;
    
    out vec4 Color;
    
    void main()
    {
        gl_Position = gWVP * vec4(Position, 1.0);
        Color = vec4(clamp(Position, 0.0, 1.0), 1.0);
    }

    openGL代码:

    GLuint ShaderProgram = glCreateProgram();
    
    // ... ... 
    
    GLuint Location = glGetUniformLocation(ShaderProgram, "gWVP");  // 获取shader中uniform mat4 gWVP变量的location
    
    if (Location != INVALID_UNIFORM_LOCATION) {
        float m[4][4] = { {0.0f, 1.0f, 0.5f, 0.2f},
                          {0.1f, 0.0f, 1.5f, 0.0f},
                          {0.0f, 1.2f, -0.5f, 0.1f},
                          {0.2f, 1.0f, 1.5f, 0.7f}
                        };
        glUniformMatrix4fv(Location, 1, GL_TRUE, (const GLfloat*)m);  // 设置uniform mat4 gWVP变量的值
    }

    统一变量块(uniform变量块) 

    OpenGL中使用统一变量缓冲区对象来支持统一变量块(uniform变量块) 数据的存储。

    相比单一的统一变量(uniform变量),统一变量块(uniform变量块) 具有以下优势:

    ① 更高效   ② 不受默认大小限制,增加了统一变量的可用存储

    vs代码:

    // ... ...
    layout (std140) uniform LightBlock
    {
        vec3 lightDirection;
        vec4 lightPosition;
    };
    
    // ... ...

    openGL代码:

    GLuint ShaderProgram = glCreateProgram();
    
    // ... ...
    
    GLuint blockId, bufferId;
    GLint blockSize;
    GLuint bindingPoint = 1;
    GLfloat lightData[] = 
    {
        // lightDirection (padding to vec4 based on std140 rule)
        1.0f, 0.0f, 0.0f, 0.0f,
        
        // lightPosition
        0.0f, 0.0f, 0.0f, 1.0f
    };
    
    // Retrieve the uniform block index
    blockId = glGetUniformBlockIndex(ShaderProgram, "LightBlock");
    
    // Associate the uniform block index with a binding point
    glUniformBlockBinding(ShaderProgram, blockId, bindingPoint);
    
    // Get the size of lightData
    // alternatively, we can calculate it using sizeof(lightData) in this example
    glGetActiveUniformBlockiv(ShaderProgram, blockId, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
    
    // Create and fill a buffer object
    glGenBuffers(1, &bufferId);
    glBindBuffer(GL_UNIFORM_BUFFER, bufferId);
    glBufferData(GL_UNIFORM_BUFFER, blockSize, lightData, GL_DYNAMIC_DRAW); // 将lightData数组的数据绑定到名为统一变量块LightBlock上
    
    // Bind the buffer object to the uniform block binding point
    glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, bufferId);

    布局限定符

    限定符 说明
    shared(默认) 多个着色器程序间共享。可省略不写
    packed 最小内存占用,无法在多个着色器程序间共享
    std140 标准内存布局
    column_major(默认) 矩阵变量以列优先顺序。可省略不写
    row_major 矩阵变量以行优先顺序

    ① shared、packed和std140有着不同地内存对齐方式

    ② 布局限定符可用于统一的变量块,也可以用在统一变量块中某个单独的变量上    注:用在单独变量上时,对于该变量会覆盖掉全局对应的布局限定符

    layout (shared, column_major) uniform TransformBlock
    {
        layout (std140, row_major) mat4 matViewProj;      // matViewProj布局为std140行优先
        layout (row_major) mat3 matNormal;                // matNormal布局为shared行优先
        mat3 matTexGen;                                    // matViewProj布局为shared列优先
    };

    顶点输出与片元输入变量(GLSL 1.3之前为varying变量)

    必须声明为全局变量,其任务是从vs向fs传输数据。该数据对cpu是不可见的。

    在vs和fs中必须声明同名、同类型的该变量。

    需要注意的是,vs中输出变量的值并不是直接传给fs的输入变量。

    在进入fs之前,会进行光栅化,根据绘制的图形,对vs的输出变量进行插值(Interpolation),然后再传递给fs的v输入变量。

    该类型的变量只能是float或由float组合成的复合类型(vec2、vec3、vec4、mat2、mat3、mat4)

    在#version 130及以上,顶点输出与片元输入变量使用关键字in,而不再使用varying

    与顶点输入变量相比,顶点输出与片元输入变量不能使用layout布局限定符。

    vs中顶点输出变量

    #if __VERSION__ >= 130
    
    out vec3 vPosition;
    out vec3 vNormal;
    out vec2 vUv;
    out vec2 vUv2;
    
    #else
    
    varying vec3 vPosition;
    varying vec3 vNormal;
    varying vec2 vUv;
    varying vec2 vUv2;
    
    #endif

    为了保证不变性,GLSL引入了invariant关键字来修饰顶点输出变量。

    主要的原因是,为了优化,编译器可能对shader指令重新排序,可能导致2个着色器之间的等价计算不能保证产生完全相同的结果。特别是在进行多遍渲染时,尤其可能成为问题。

    例如:fs中第一遍中计算镜面反射光,第二遍计算环境光和漫反射光,顶点输出变量如果不使用invariant关键字,精度带来的小误差会导致深度冲突(Z fighting)。

    invariant关键字既可用于声明变量,也可以用于已经声明过的变量。

    invariant vec2 texCoord; // 用于声明变量
    
    invariant gl_Position;  // 用于已经声明过的变量
    
    #pragma STDGL invariant(all)  // 让所有的变量全都不变   注:因为编译器需要保证不变性,所以会限制对着色器进行优化

    fs中片元输入变量

    #if __VERSION__ >= 130
    
    in vec3 vPosition;
    in vec3 vNormal;
    in vec2 vUv;
    in vec2 vUv2;
    
    #else
    
    varying vec3 vPosition;
    varying vec3 vNormal;
    varying vec2 vUv;
    varying vec2 vUv2;
    
    #endif

    fs中片元输出变量

    layout(location = 0) out vec4 FragColor;
    
    void main()
    {
        FragColor = vec4(1.0, 0.0, 0.0, 0.0);
    }

    注1:在典型情况下,只会渲染一个颜色缓冲区,这个时候,layout(location = 0)布局限定符可忽略不写(默认输出变量会进入位置0)

    注2:当渲染到多个渲染目标(MRT)时,可以使用布局限定符指定每个输出前往的渲染目标

    插值限定符来修饰顶点输出与片元输入变量(GLSL 1.3之前为varying变量)

    插值限定符 说明  示例
    smooth(缺省)

    平滑着色

    /*** vs ***/

    smooth out vec3 v_color;  // smooth可省略不写

    /*** fs ***/

    smooth in vec3 v_color;  // smooth可省略不写

    flat 平面着色

    /*** vs ***/

    flat out vec3 v_color;

    /*** fs ***/

    flat in vec3 v_color;

    centroid

    质心采样(centroid sampling)

    使用多重采样渲染时,centroid可用于强制插值发生在被渲染图元内部

    这可防止图元的边缘出现伪像

    /*** vs ***/

    centroid out vec3 v_color;

    /*** fs ***/

    centroid in vec3 v_color;

    vs/fs中能容纳的顶点输入变量(attribute变量)、uniform变量、顶点输出与片元输入变量(varying变量)是储存在硬件中的,其最大数目与设备有关,具体详见下表:

    变量类别 保存在硬件的哪个位置 是否会打包 内置全局变量(表示最大数量) glGetintegerv查询 OpenGL ES 3.0最小值
    顶点输入变量(attribute变量)   No const mediump int gl_MaxVertexAttribs   16
    vs:统一变量(uniform变量) 常量存储:对应一个向量的物理数组 Yes const mediump int gl_MaxVertexUniformVectors GL_MAX_VERTEX_UNIFORM_VECTORS 256
    fs:统一变量(uniform变量) 常量存储:对应一个向量的物理数组 Yes const mediump int gl_MaxFragmentUniformVectors GL_MAX_FRAGMENT_UNIFORM_VECTORS 224

    顶点输出变量

    片元输入变量

    (varying变量)

    插值器:对应一个向量的物理数组

    Yes

    const mediump int gl_MaxVertexOutputVectors

    const mediump int gl_MaxFragmentInputVectors

    const mediump int gl_MaxVaryingVectors

     

    16

    15

    8(Open GL ES 2.0)

    注1:为了有效利用宝贵的硬件存储资源,OpenGL会对变量打包再进行存放。

    注2:用uniform修饰的变量、const变量、字面值(如:在代码中写的0,1.0等)都会占用常量储存空间。

    精度限定符

    用来表示每种数据具有的精度(占用的字节数)。精度越高,计算结果误差就越小、效果也更好,但也意味着更大的内存、更多能耗和更久的计算时间。

    使用精度限定符,可以精细地控制shader程序在效果和性能间的平衡。

    精度限定符 描述 float数值范围和精度 int数值范围
    highp(高精度)

    vs的最低精度

    注:在某些webgl环境中,fs可能不支持highp精度

    如果支持的话,会定义内置宏GL_FRAGMENT_PRECISION_HIGH

    范围:(-2^62~2^62)

    精度:2^-16

    (-2^16~2^16)
    mediump(中精度)

    fs的最低精度

    范围:(-2^14~2^14)

    精度:2^-10

    (-2^10~2^10)
    lowp(低精度) 可以表示所有的颜色

    范围:(-2~2)

    精度:2^-8

    (-2^8~2^8)

    各精度限定符的数值范围和精度实际上与系统环境有关,可动态地使用gl.GetShaderPrecisionFormat()来获取

    对单个变量

    mediump float size;  // 中精度的浮点型变量
    highp vec4 position;  // 具有高精度浮点型元素的vec4对象
    lowp vec4 color; // 具有低精度浮点型元素的vec4对象

    对整个文件

    precision mediump float; // 所有float和由float组合成的复合类型(vec2、vec3、vec4、mat2、mat3、mat4)的数默认为中精度
    precision highp int;  // 所有int和由int组合成的复合类型的数默认为高精度

    注:需要放在shader文件紧跟#version xxx的后面,其他语句之前

    各数据类型的默认精度

    shader类型 数据类型 默认精度
    vs int highp
    float highp
    sampler2D lowp
    samplerCube lowp
    fs int mediump
    float

    无(需手动指定,否则会编译报错)

    sampler2D lowp
    samplerCube lowp

    基础类型

    bool b1 = true;
    
    int n1 = 10;
    int n2 = -25;
    int n3 = 0;
    //int n4 = 3.5;  // 编译失败! 不能将float隐式地转换成int
    
    //uint u1 = 0; // 编译失败! 不能将int隐式地转换成uint
    uint u2 = 0u;
    uint u3 = 100u;
    
    
    float f1 = 2.0;
    float f2 = 3;
    float f3 = 0.2f;
    float f4 = n1;
    float f5 = float(n1);
    float f6 = u2;
    float f7 = float(u3);
    //float f8 = b1; // 编译失败! 不能将bool隐式地转换成float
    //float f9 = (float)b1;// 编译失败! 不能使用c类型的转换方式
    float f9 = float(b1);
    
    int n4 = int(f3);
    //int n5 = f3; // 编译失败! 不能将float隐式地转换成int
    //int n6 = u3; // 编译失败! 不能将uint隐式地转换成int
    int n7 = int(u3);
    //uint u4 = n1; // 编译失败! 不能将int隐式地转换成uint
    uint u5 = uint(n2);
    
    //bool b2 = n1; // 编译失败! 不能将int隐式地转换成bool
    bool b3 = bool(n1);
    //bool b4 = u3; // 编译失败! 不能将uint隐式地转换成bool
    bool b5 = bool(u3);
    //bool b6 = f3; // 编译失败! 不能将float隐式地转换成bool
    bool b7 = bool(f3);

    数组

    只支持一维数组。

    const float a1[3] = float[](0.25, 0.5, 1.0);
    float a2[2] = float[2](0.3, 0.8);
    
    float a4[3];
    a4[0] = 0.1;
    a4[1] = 0.2;
    a4[2] = 0.3;
    
    int len = a4.length(); // len为3  获取数组a4的元素个数
    
    const int N = 2;
    vec3 va1[N];
    va1[0] = vec3(1.0, 0.0, 0.0);
    va1[1] = vec3(0.0, 0.0, 1.0);
    
    vec3 va2[2] = vec3[](vec3(1.0), vec3(0.2, 0.3, 0.5));

    结构体(struct)

    ① 与C语言结构体一样,不可从其他结构体上派生

    ② 与C语言结构体一样,不允许有构造函数和析构函数

    ③ 可直接对2个结构体变量进行比较

    #version 330
    
    out vec4 FragColor;
    
    struct light // 与C语言一样,不允许从其他结构体上派生
    {
        vec4 color;
        vec3 position;
        
        //light(){} // 与C语言一样,不允许有构造函数
        //~light(){} // 与C语言一样,不允许有析构函数
    
        void test()
        {
            color.x = 0.2;
        }
    } GL1; // 定义light结构体,并定义全局变量GL1
    
    light GL2; // 定义light结构体的全局变量GL2
    
    void main()
    {
        // light结构体的构造函数参数的顺序必须与结构体定义中的成员顺序一致
        // 如下:参数一 vec4(1.0, 1.0, 0.0, 1.0)会赋值给vec4 color  参数二 vec3(10.0, 10.0, 0.0)会赋值给vec3 position
        GL1 = light(vec4(1.0, 1.0, 0.0, 1.0), vec3(10.0, 10.0, 0.0));
        
        GL1.test();
    
        GL2.color.r = 1.0;
        GL2.position = vec3(3.0, 4.0, 5.0);
    
        light L1, L2; // 定义light结构体的局部变量L1,L2
        L1.color = vec4(0.0, 1.0, 0.0, 1.0);
        
        L2 = L1;
        if (L1 == L2)  // true  结构体支持==运算符比较
        {
            
        }
    
        L2.position.x = 100;
        if (L1 != L2)  // true   结构体支持!=运算符比较
        {
            
        }
    
        FragColor = GL1.color;
    }

    向量

    向量的分量可以为:

    ① {x,y,z,w} : 用来获取顶点坐标分量

    ② {r,g,b,a} : 用来获取颜色分量

    ③ {s,t,p,q} :用来获取纹理坐标分量

    从向量中可以同时抽取多个分量,这个过程称作混合(swizzling)。但要注意地是,以上三种不能相互混着使用,如:xyr、rgst、xrsw等

    分量类型

    2维

    3维

    4维

    bool bvec2 bvec3 bvec4
    int ivec2 ivec3 ivec4
    uint uvec2 uvec3 uvec4
    float vec2 vec3 vec4
    vec2 v2a; // v2a为(0.0, 0.0)
    vec2 v2b = vec2(1.0f); // v2b为(1.0f, 1.0f)
    vec2 v2c = vec2(1.0, 0.0); // v2c为(1.0, 0.0)
    //vec3 v2d = v2c.xx; // 编译失败 incompatible types in initialization
    vec2 v2e; // v2e为(0.0, 0.0)
    v2e = v2c.yx; // v2e为(0.0, 1.0)
    vec2 v2f; // v2f为(0.0, 0.0)
    v2f = v2c.rr; // v2f为(1.0, 1.0)
    
    float f1 = v2c[0];  // f1为1.0  v2c[0]=v2c.x=v2c.r=v2c.s
    float f2 = v2c.y;  // f1为0.0  v2c.y=v2c.g=v2c.t=v2c[1]
    
    // 向量运算
    vec2 v2g = vec2(0.4, 0.6);
    vec2 v2h = vec2(0.1, 0.2);
    vec2 v2i = v2g + v2h; // v2i为(0.5, 0.8)
    vec2 v2j = v2g + 0.2; // v2j为(0.6, 0.8)
    vec2 v2k = v2h * 2; // v2k为(0.2, 0.4)
    vec2 v2m = v2g * v2h; // v2m为(0.04, 0.12)
    
    vec3 v3a = vec3(0.5); // v3a为(0.5, 0.5, 0.5)
    //vec3 v3b = vec3(1.0, 1.0); // 编译失败  too little data in type constructor
    vec3 v3c = vec3(1.0, 0.5, 0.25); // v3c为(1.0, 0.5, 0.25)
    
    //vec3 v3d = vec3(v2a); // 编译失败  cast not allowed
    vec3 v3e = vec3(v2a, 1.0); // v3e为(0.0, 0.0, 1.0)
    
    vec2 v2n = vec2(v3c);  // 使用v3c的前2个元素 v2n为(1.0, 0.5)
    
    vec4 v4a = vec4(0.0, 0.3, 1.0, 0.5);  // v4a为(0.0, 0.3, 1.0, 0.5)
    v4a.xw = vec2(0.2, 0.6);  // v4a为(0.2, 0.3, 1.0, 0.6)
    v4a.gbr = vec3(0.0, 0.0, 1.0);  // v4a为(1.0, 0.0, 0.0, 0.6)
    v4a.pq = vec2(1.0, 0.0); // v4a为(1.0, 0.0, 1.0, 0.0)
    vec4 v4b = vec4(v2c, v3c);  // 先使用v2c来填充,如果没填满继续使用v3c来填充  v4b为(1.0, 0.0, 1.0, 0.5)
    vec4 v4c;
    v4c = vec4(0.0, 0.3, 1.0, 0.5).wwwx;  // v4c为(0.5, 0.5, 0.5, 0.0)

    矩阵

    分量类型均为float,按照列优先顺序来存储(列主序)

    矩阵类型 解释
    mat2(mat2x2) 由2个列向量vec2组成(可通过m[0]、m[1]来访问)
    mat2x3 由2个列向量vec3组成(可通过m[0]、m[1]来访问)
    mat2x4 由2个列向量vec4组成(可通过m[0]、m[1]来访问)
    mat3x2 由3个列向量vec2组成(可通过m[0]、m[1]、m[2]来访问)
    mat3(mat3x3) 由3个列向量vec3组成(可通过m[0]、m[1]、m[2]来访问)
    mat3x4 由3个列向量vec4组成(可通过m[0]、m[1]、m[2]来访问)
    mat4x2 由4个列向量vec2组成(可通过m[0]、m[1]、m[2]、m[3]来访问)
    mat4x3 由4个列向量vec3组成(可通过m[0]、m[1]、m[2]、m[3]来访问)
    mat4(mat4x4) 由4个列向量vec4组成(可通过m[0]、m[1]、m[2]、m[3]来访问)
    vec2 v2a = vec2(1.0, 0.5); // v2a为(1.0, 0.5)
    vec3 v3a = vec3(0.3, 0.2, 0.9); // v3a为(0.3, 0.2, 0.9)
    vec4 v4a = vec4(0.2, 0.3, 0.8, 0.0); // v4a为(0.2, 0.3, 0.8, 0.0)
    mat2 m2a;  // m2a为(0.0, 0.0, 0.0, 0.0)
    mat2 m2b = mat2(1.0);  // m2b为(1.0, 0.0, 0.0, 1.0)
                           // | 1.0  0.0 |
                           // | 0.0  1.0 | 
    mat2 m2c = mat2(0.2, 0.5, 0.0, 0.8);  // m2c为(0.2, 0.5, 0.0, 0.8)
                                          // | 0.2  0.0 |
                                          // | 0.5  0.8 |
    mat2 m2d = mat2(v2a, 0.1, 0.3); // m2d为(1.0, 0.5, 0.1, 0.3)
    mat2 m2e = mat2(0.6, v3a); // m2e为(0.6, 0.3, 0.2, 0.9)
    mat2 m2f = mat2(v2a, v3a); // 先使用v2a来填充,如果没填满继续使用v3a来填充  m2f为(1.0, 0.5, 0.3, 0.2)
    mat2 m2g = mat2(v4a); // m2g为(0.2, 0.3, 0.8, 0.0)
                          // | 0.2  0.8 |
                          // | 0.3  0.0 |
    mat2 m2h = mat2(v2a.yyxx); // m2g为(0.5, 0.5, 1.0, 1.0)
                          // | 0.5  1.0 |
                          // | 0.5  1.0 |
    mat2x3 m2x3a = mat2x3(v2a.xyx, v3a); // m2x3a为(1.0, 0.5, 1.0, 0.3, 0.2, 0.9)
                                         // | 1.0  0.3 |
                                         // | 0.5  0.2 |
                                         // | 1.0  0.9 |
    
    vec2 v2b = m2b[1];  // v2b为(0.0, 1.0)
    vec3 v3b = m2x3a[0]; // v3b为(1.0, 0.5, 1.0)
    int n = 1;
    vec3 v3c = m2x3a[n]; // v3c为(0.3, 0.2, 0.9)
    
    float f1 = m2c[1][0];  // f1为0.0
    float f2 = m2c[0].y;  // f2为0.5
    float f3 = m2x3a[0].b;  // f3为1.0
    
    mat4 m4a = mat4(0.5); // m4a为(0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5)
                          // | 0.5  0.0  0.0  0.0 |
                          // | 0.0  0.5  0.0  0.0 |
                          // | 0.0  0.0  0.5  0.0 |
                          // | 0.0  0.0  0.0  0.5 |
    // 矩阵与浮点数相加
    mat4 m4b = m4a + 0.5; // m4b为(1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.5, 1.0)
                          // | 1.0  0.5  0.5  0.5 |
                          // | 0.5  1.0  0.5  0.5 |
                          // | 0.5  0.5  1.0  0.5 |
                          // | 0.5  0.5  0.5  1.0 |
    // 矩阵与浮点数相乘
    mat4 m4c = m4a * 2;   // m4c为(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)
                          // | 1.0  0.0  0.0  0.0 |
                          // | 0.0  1.0  0.0  0.0 |
                          // | 0.0  0.0  1.0  0.0 |
                          // | 0.0  0.0  0.0  1.0 |
    
    mat4 m4d = mat4(1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 1.0);
                          // | 1.0  0.5  0.5  0.5 |
                          // | 0.5  1.0  0.25 0.5 |
                          // | 0.5  0.5  0.25 0.5 |
                          // | 0.5  0.5  0.5  1.0 |
    
    // 矩阵右乘向量 
    vec4 v4b = m4d * v4a; // v4b为(0.75, 0.6, 0.45, 0.65)  注:v4a被当成列向量
                          // v4b.x = m4d[0].x * v4a.x + m4d[1].x * v4a.y + m4d[2].x * v4a.z + m4d[3].x * v4a.w = 0.75
                          // v4b.y = m4d[0].y * v4a.x + m4d[1].y * v4a.y + m4d[2].y * v4a.z + m4d[3].y * v4a.w = 0.6
                          // v4b.z = m4d[0].z * v4a.x + m4d[1].z * v4a.y + m4d[2].z * v4a.z + m4d[3].z * v4a.w = 0.45
                          // v4b.w = m4d[0].w * v4a.x + m4d[1].w * v4a.y + m4d[2].w * v4a.z + m4d[3].w * v4a.w = 0.65
    // 矩阵左乘向量 
    vec4 v4c = v4a * m4d; // v4c为(0.75, 0.8, 0.375, 0.65)  注:v4a被当成行向量
                          // v4c.x = v4a.x * m4d[0].x  + v4a.y * m4d[0].y + v4a.z * m4d[0].z + v4a.w * m4d[0].w = 0.75
                          // v4c.y = v4a.x * m4d[1].x  + v4a.y * m4d[1].y + v4a.z * m4d[1].z + v4a.w * m4d[1].w = 0.8
                          // v4c.z = v4a.x * m4d[2].x  + v4a.y * m4d[2].y + v4a.z * m4d[2].z + v4a.w * m4d[2].w = 0.375
                          // v4c.w = v4a.x * m4d[3].x  + v4a.y * m4d[3].y + v4a.z * m4d[3].z + v4a.w * m4d[3].w = 0.65
    
    // 矩阵矩阵相乘
    mat2 m2i = mat2(0.1, 0.0, 0.6, 0.2);  // m2i为(0.1, 0.0, 0.6, 0.2)
                                          // | 0.1  0.6 |
                                          // | 0.0  0.2 |
    mat2 m2j = m2c * m2i; // m2j为(0.02, 0.05, 0.12, 0.46)
                          // | m2c[0].x*m2i[0].x+m2c[1].x*m2i[0].y  m2c[0].x*m2i[1].x+m2c[1].x*m2i[1].y |    |  0.02  0.12  |
                          // | m2c[0].y*m2i[0].x+m2c[1].y*m2i[0].y  m2c[0].y*m2i[1].x+m2c[1].y*m2i[1].y |    |  0.05  0.46  |

    采样器(纹理)

    只能是uniform变量,该变量从OpenGL中接受纹理单元编号,使得shader能通过该编号来访问纹理数据。

    采样器(sampler)类型:

    大类型 小类型 说明 示例
    浮点采样器(不透明) sampler1D 1D纹理 uniform sampler1D s;
    sampler2D 2D纹理 uniform sampler2D s;
    sampler3D 3D纹理 uniform sampler3D s;
    samplerCube 立方图纹理 uniform samplerCube s;
    samplerCubeShadow 带有对比的立方图深度纹理 uniform samplerCubeShadow s;
    sampler1DShadow 带有对比的1D深度纹理 uniform sampler1DShadow s;
    sampler1DArray 1D数组纹理 uniform sampler1DArray s;
    sampler1DArrayShadow 带有对比的1D数组深度纹理 uniform sampler1DArrayShadow s;
    sampler2DShadow 带有对比的2D深度纹理 uniform sampler2DShadow s;
    sampler2DArray 2D数组纹理 uniform sampler2DArray s;
    sampler2DArrayShadow 带有对比的2D数组深度纹理 uniform sampler2DArrayShadow s;
    有符号整数采样器(不透明) isampler1D 有符号整数1D纹理 uniform isampler1D s;
    isampler2D 有符号整数2D纹理 uniform isampler2D s;
    isampler3D 有符号整数3D纹理 uniform isampler3D s;
    isamplerCube 有符号整数立方图纹理 uniform isamplerCube s;
    isampler1DArray 有符号整数1D数组纹理 uniform isampler1DArray s;
    isampler2DArray 有符号整数2D数组纹理 uniform isampler2DArray s;
    无符号整数采样器(不透明) usampler1D 无符号整数1D纹理 uniform usampler1D s;
    usampler2D 无符号整数2D纹理 uniform usampler2D s;
    usampler3D 无符号整数3D纹理 uniform usampler3D s;
    usamplerCube 无符号整数立方图纹理 uniform usamplerCube s;
    usampler1DArray 无符号整数1D数组纹理 uniform usampler1DArray s;
    usampler2DArray 无符号整数2D数组纹理 uniform usampler2DArray s;

    除了=、==和!=外,采样器变量不可以作为操作数参与运算

    vs/fs中能使用采样器的个数,详见下表:

    着色器类型 最大数量 最小数量
    vs gl_MaxVertexTextureImageUnits 0
    fs gl_MaxTextureImageUnits 8

    函数

    函数用法和C语言一样

    vs和fs执行的入口函数均为void main()  {  }

    函数参数限定词说明:

    限定词 说明
    in 缺省限定词,可以省略不写
    const 当前参数为常量,不可在函数内被修改
    out

    ① 进入函数时,会被初始化为0, 0.0或false

    ② 在函数内修改后,对外可见

    inout

    ① 接受函数外传入的初始值

    ② 在函数内修改后,对外可见

    ① 参数限定词只需要用在函数上,函数调用时不用带。

    ② 不允许函数递归    这一限制的原因是编译器会把函数都内联展开,以支持没有堆栈的GPU

    float square(float value) // 求平方
    {
        return value * value;
    }
    
    void fuc1(const float value) // const参数不能在函数内部修改
    {
        //value = 0.2; // assignment to const variable value  编译错误
    }
    
    void fuc2(out float value)  // value进入函数时,会被重新初始化为0;在函数内修改,对外可见
    {
        value += 0.5;
    }
    
    void fuc3(inout float value) // value的初始值从函数外传入;在函数内修改,对外可见
    {
        value += 0.5;
    }
    
    int fun4(int n)  // 如果在main函数中直接或间接调用fun4函数,会编译报错:recursive call to function
    {
        if (n == 0 || n == 1)
        {
            return 1;
        }
        return fun4(n-1) + fun4(n-2);
    }

    内置函数

    类别 内置函数
    角度函数

    radians //角度转弧度

    degrees // 弧度转角度

    三角函数

    sin // 正弦

    cos // 余弦

    tan // 正切

    asin // 反正弦

    acos // 反余弦

    atan // 反正切

    指数函数

    pow // x^y 

    exp // 自然指数

    log // 自然对数

    exp2  // 2^x 

    log2 // 以2为底对数

    sqrt // 开平方

    inversesqrt // 开平方倒数 

    通用函数

    abs // 绝对值

    min // 最小值

    max // 最大值

    mod // 取余数

    sign // 取正负号

    floor // 向下取整

    ceil // 向上取整

    clamp // 限定范围

    mix // 线性内插

    step // 步进函数

    smoothstep // 艾米内插步进

    fract // 获取小数部分

    几何函数

    length // 矢量长度

    distance // 两点间距离

    dot // 内积

    cross // 外积

    normalize // 归一化 

    reflect // 矢量反射

    faceforward // 使矢量“朝前”

    矩阵函数 matrixCmpMult // 逐元素乘法
    矢量函数

    lessThan // 逐元素小于

    lessThanEqual // 逐元素小于等于

    greaterThan // 逐元素大于

    greaterThanEqual // 逐元素大于等于

    equal // 逐元素相等

    notEqual // 逐元素不等

    any // 任一元素为true则为true

    all // 所有元素为true则为true

    not // 逐元素取补

    纹理查询函数

    texture2D // 在二维纹理中获取纹素

    textureCube // 在立方体纹理中获取纹素

    texture2DProj // texture2D的投影版本

    texture2DLod // texture2D的金字塔版本

    textureCubeLod // textureCube的金字塔版本

    texture2DProjLod // texture2DLod的投影版本

    限定符顺序规则

    一般变量中:不变性(invariant ) >  插值(smooth、flat)  > 存储(const、in、out、uniform、centroid in、centroid out)  >  精度(highp、mediump、lowp)

    参数变量中:存储(const、in、out、uniform、centroid in、centroid out)  >  参数(in、out、inout)   >  精度(highp、mediump、lowp)

    帮助手册

    OpenGL ES 1.1 API(含GLSL内置函数)帮助手册:https://www.khronos.org/registry/OpenGL-Refpages/es1.1/xhtml/

    OpenGL ES 2.0 API(含GLSL内置函数)帮助手册:https://www.khronos.org/registry/OpenGL-Refpages/es2.0/

    OpenGL ES 3.0 API(含GLSL内置函数)帮助手册:https://www.khronos.org/registry/OpenGL-Refpages/es3.0/

    OpenGL ES 3.1 API(含GLSL内置函数)帮助手册:https://www.khronos.org/registry/OpenGL-Refpages/es3.1/

    OpenGL ES 3.2 API(含GLSL内置函数)帮助手册:https://www.khronos.org/registry/OpenGL-Refpages/es3/

    OpenGL 2.1, GLX, and GLU帮助手册:https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/

    OpenGL 4.5 API(含GLSL内置函数)帮助手册:https://www.khronos.org/registry/OpenGL-Refpages/gl4/

    Khronos OpenGL and OpenGL ES 参考页:https://www.khronos.org/registry/OpenGL-Refpages/

    WebGL 1.0 API帮助手册:https://www.khronos.org/registry/webgl/specs/latest/1.0/

    WebGL 2.0 API帮助手册:https://www.khronos.org/registry/webgl/specs/latest/2.0/

    参考卡片

    OpenGL ES 2.0(含API和GLSL)参考卡片:https://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf

    OpenGL ES 3.0(含API和GLSL)参考卡片:https://www.khronos.org/files/opengles3-quick-reference-card.pdf

    OpenGL ES 3.1(含API和GLSL)参考卡片:https://www.khronos.org/files/opengles31-quick-reference-card.pdf

    OpenGL ES 3.2(含API和GLSL)参考卡片:https://www.khronos.org/files/opengles32-quick-reference-card.pdf 

    OpenGL ES 3.2(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl-quick-reference-card.pdf

    OpenGL 3.2(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl-quick-reference-card.pdf

    OpenGL 4.1(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl41-quick-reference-card.pdf

    OpenGL 4.2(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl42-quick-reference-card.pdf

    OpenGL 4.3(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl43-quick-reference-card.pdf

    OpenGL 4.4(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl44-quick-reference-card.pdf

    OpenGL 4.5(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl45-quick-reference-card.pdf

    OpenGL 4.6(含API和GLSL)参考卡片:https://www.khronos.org/files/opengl46-quick-reference-card.pdf 

    WebGL 1.0(含API和GLSL)参考卡片:https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf

    WebGL 2.0(含API和GLSL)参考卡片:https://www.khronos.org/files/webgl20-reference-guide.pdf

    Vulkan 1.0(含API)参考卡片:https://www.khronos.org/files/vulkan10-reference-guide.pdf

    Vulkan 2.0(含API)参考卡片:https://www.khronos.org/files/vulkan11-reference-guide.pdf

    参考

    高级GLSL

  • 相关阅读:
    数据库设计准则(第一、第二、第三范式说明)
    Linux之chmod使用
    数据备份——PHP
    PHP语言性能优化——少使用魔术方法
    PHP性能之语言性能优化:安装VLD扩展——检测性能
    PHP性能之语言性能优化:安装VLD扩展——检测性能
    PHP性能之语言性能优化:安装VLD扩展——检测性能
    socket、fsockopen、curl、stream 区别
    iOS 下 Podfile 使用方法
    使用 NVM 管理不同的 Node.js 版本
  • 原文地址:https://www.cnblogs.com/kekec/p/14065756.html
Copyright © 2020-2023  润新知