美文网首页
webgl GLSL ES 着色器语言

webgl GLSL ES 着色器语言

作者: Viewwei | 来源:发表于2021-07-19 16:49 被阅读0次
    • 前言
      GLSL 语言是 OpenGL 着色器语言的基础上,删除和简化一部分功能后形成的.GLSL ES 的语法与 C 语言的较为类似.

    基础

    就像很多语言一样,GLSL ES 语言编写着色器程序的时候,应该注意两点

    • 程序是大小写敏感的
    • 每一个语句都应该以一个英文分号结束

    执行顺序

    GLSL ES 语言和其他语言一样,执行顺序都是顺序执行,循环执行和条件执行

    注释

    GLSL ES 语言两种注释方式
    -单行注释 //

    • 多行注释 /注释内容/

    数据值类型

    GLSL 支持两种数据类型

    • 数值数据类型:GLSL ES 支持整数类型和浮点类型.没有小数点的值被认为是整数型,而有小数点的数值称为浮点数
      布尔值类型: GLSL ES 支持布尔值类型,包括 true 和 false 两个布尔值常量

    变量

    变量命名规则

    • 只包括 a-z A-Z 0-9 和下划线
    • 变量名的首字母不能是数字
    • 不能是程序的特定字符串和 webgl 内置的变量
    • 不能以 gl_ webgl_和_webgl 开头

    GLSL ES 语言

    GLSL ES 不像 JavaScript都使用 var 来申明变量.GLSL ES 需要要求你具体的指出变量的数据类型.申明变量的格式为
    <变量类型><变量名>
    例如:

    vec4 a_Position
    

    GLSL基本数据类型

    类型 描述
    float 单精度浮点数据类型
    int 整形数
    bool 布尔值

    赋值和类型转换

    使用=可以给变量赋值,但是需要特别注意的是,在赋值的时候一定要确保变量的类型和数据的类型一致,不然会报错.GLSL ES 语言中内置了很多数据类型转换的函数

    转换 函数 描述
    转换为整数 int(float),int(bool) 如果是浮点数转换成整数,那么是将小数点部分删除,如果是 bool 值,则 true转换成1,false 转换成 0
    转换成浮点数 float(int) float(bool) 如果是整数,则是添加小数点(8->8.0),如果是布尔值,true 转换成 1.0,false 转换成 0.0
    转换为布尔值 bool(int) bool(float) 0转换成 false,非 0 转换成 true,0.0转换成 false,其他非 0 转换成 true

    矢量和矩阵

    GLSL ES 支持矢量和矩阵.这两种数据很适合处理计算机图形.矢量和矩阵包含多个元素.每个元素是一个数值.

    类别 GLSL ES 数据类型 描述
    矢量 vec2 vec3,vec4 具有 2,3,4个浮点数元素的矢量
    矢量 ivec2 ivec3,ivec4 具有 2,3,4个整形数元素的矢量
    矢量 bvec2 bvec3,bvec4 具有 2,3,4个布尔值元素的矢量
    矩阵 mat2 mat3,mat4 具有 2x2,3x3,4x4个浮点数元素的矩阵
    赋值和构造

    使用等号(==)来对矢量和矩阵进行赋值的操作,左右两边的数量/值.同时 webgl 还提供创建指定类型的变量函数被称为构造函数.构造函数的名称和器创建的变量的类型保持一致

    矢量构造函数

    在 GLSL 中矢量非常的重要.所以 GLSL 体重了丰富灵活的方式来创建矢量

    vec3 v3 = vec3(1.0,2.0,3.0) // v3 设置为(1.0,2.0,3.0)
    vec2 v2 = vec2(v3) // 使用 v3 的前两个元素,将 v2 设为(1.0,1.0)
    vec4 v4 = vec4(1.0) //将 v4 设置为(1.0,1.0,1.0,1.0)
    

    矢量构造函数还支持组合

    vec4 v5 = vec4(v2,v4) //把 v5 设置为(1.0,1.0,1.0,1.0)
    //规则就是:先把第一个参数 v2 的所以元素填充进去,如果还没有填满,就继续使用第二个元素v4填充
    
    矩阵构造函数

    矩阵构造函数的使用方式与矢量构造函数的方式基本类似.但是你要保证存储在矩阵中的元素是按照列主序的

    • 向矩阵构造函数传入矩阵中的每一个元素的数值来构造矩阵.*主要传入值的顺序
    mat4 m4 = mat4(
                  1.0,2.0,3.0,4.0,
                  5.0,6.0,7.0,8.0,
                  9.0,10.0,11,0,12.0,                
                  13.0,14.0,15.0,16.0
    
    )
    //如果需要得到上面这样格式的矩阵,需要按照如下格式传递
    [1.0,5.0,9.0,13.0,
    2.0,6.0,10.0,14.0,
    3.0,7.0,11.0,15.0,
    4.0,8.0,12.0,16.9
    ]
    
    • 向矩阵传入一个或多个矢量
    vec2 v2_1 = vec2(1.0,3.0)
    vec2 v2_2 = vec2(2.0,4.0)
    mat2 m2_1 = mat2(v2_1,v2_2)
    //使用一个 vec4对象来创建 mat2 对象
    vec4 v4 = vec4(1.0,2.0,3.0,4.0)
    mat2 m2_2 = mat2(v4) // 1.0,2.0
                          // 3.0,4.0
    
    
    • 向矩阵传入单个元素
      想矩阵传入单个数值,这样将生成一个对角线元素都是该数值,其他元素为 0.0 的矩阵
    mat4 m4 = mat4(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
    
    • 注意
      与矢量构造函数类似,如果传入的数值大于 1,又没有达到矩阵元素的数量,就会报错

    访问元素

    运算符

    在矢量变量名后接点运算符号(.),然后接上分量名称,就可以访问矢量的元素,矢量的分量如下表所示

    类别 描述
    x,y,z,w 用来获取顶点坐标分量
    r,g,b,a 用来获取颜色分量
    s,t,p,q 用来获取纹理坐标分量

    x,r,s虽然名称不同,单数都能访问到第一个分量.如果访问超出矢量长度的分量,则会报错
    将多个分量共同置于点运算符后,就可以从矢量中同时抽取出多个分量.这个过程叫做混合.根据抽取出来分量的多少,组合成一个相对应的矢量

    vec3 v3 = vec2(1.0,2.0,3.0)
    vec2 v2 = v2.xy // v2为(1.0,2.0)
    
    []运算符号

    除了点(.)运算符号,还可以使用[]运算符号并且使用数组下标来访问矢量或者矩阵的元素.注意,矩阵的元素任然是按照列主序读取,与 JavaScript 一样,下标从 0 开始,所以通过[0]可以访问到矩阵中的第一列元素.

    mat4 m4 = mat4(
          1.0,2.0,3.0,4.0,
          5.0,6.0,7.0,8.0,
          9.0,10.0,11.0,12.0,
          13.0,14.0,15.0,16.0
    )
    vec4 v4 = m4[0] // 获取 m4 矩阵的第1 列 即 [1.0,2.0,3.0,4.0]
    
    • 注意
      使用[]中只能出现的索引值必须是常量索引值,常量索引值的定义如下
    • 整形字面量(如 0/1)
    • 用 const 修饰的全局变量或者局部变量
    • 循环索引
    运算符号
    • 矢量和浮点数的运算
    v3b = v3a +f
    // v3b.x=v3a.x+f
    //v3b.y = v3a.y+f
    //v3b.z = v3a.z+f
    
    • 矢量运算
    v3c = v3a +v3b
    //v3c.x =v3a.x+v3b.x
    //v3c.y = v3a.y+v3b.y
    //v3c.z =v3a.z+v3b.z
    
    • 矩阵右乘矢量
    v3b = m3a *v3a
    // v3b.x = m3a[0].x*v3a.x+m3a[1].x*v3a.y+m3a[2].x*v3a.z
    //v3b.z = m3a[0].y*v3a.y +m3a[1].y*v3a.y+m3a[1].y*v3a.z
    //v3b.z = m3a[0].z*v3a.x +m3a[1].z*v3a.y+m3a[1].z*v3a.z
    

    -- 矩阵左乘

    v3b = v3a*m3a
    //v3b.x = v3a.x*m3a[0].x+v3a.y+m3a[0].y +v3a.z*m3a[0].z
    //v3b.y = v3a.x*m3a[1].x+v3a.y+m3a[1].y +v3a.z*m3a[1].z
    //v3b.z = v3a.x*m3a[2].x+v3a.y+m3a[2].y +v3a.z*m3a[2].z
    
    • 矩阵相乘
    m3c = m3a*m3b
    //m3c[0].x = v3a.x*m3a[0].x+v3a.y+m3a[0].y +v3a.z*m3a[0].z
    //m3c[0].y = v3a.x*m3a[1].x+v3a.y+m3a[1].y +v3a.z*m3a[1].z
    //m3c[0].z = v3a.x*m3a[2].x+v3a.y+m3a[2].y +v3a.z*m3a[2].z
    //..
    
    结构体

    GLSL ES 支持用户自定义类型,即结构体.使用关键词struct,将已存在的类型数据聚合到一起,就可以定义为结构体

    struct light {
      vec4 color;
      vec3 position
    }
    light l1,l2
    

    上面代码定义了一种新的结构体 light,它包含两个成员变量:color 变量和 position 变量.之后申明了两个 light 类型的变量l1,l2.此外为了方便,可以在用一条语句中定义结构体并声明结构体类型变量如

    struct light {
      vec4 color;
      vec3 position
    }l1
    
    赋值和构造

    结构体有标准的构造函数,器名称和结构体一致.构造函数的参数的顺序必须与结构体的成员顺序一致

    l1 = light(vec4(1.0,2.0,3.0,4.0),vec3(1.0,2.0,3.0))
    
    访问成员变量

    在结构体变量名后面根点(.)运算,然后再加上成员名称,就可以访问变量的名称

    vec4 color = l1.color;
    

    数组

    GLSL ES 支持数组类型.与JavaScript 中的数组不同的是,GLSL ES 只支持一维数组,而且对象不支持pop,push 等操作.创建数组的时候也不需要使用 new 运算符号,只需要在变量名称后加上中括号([])和数组的长度.数组的长度必须大于 0 的整形常量表达式

    • 整形字面量
    • 用 const 限定字修饰的全局变量或者局部变量
    float floatArray[4]
    
    取样器

    将 GLSL ES 支持一种内置的取样器,我们必须通过该类型变量访问纹理.有两种基本取样器类型:sampler2D 和 samplerCube.取样器变量只能是uniform变量,或者需要访问纹理的函数,如texture2Dh 函数的参数

    uniform sampler2D u_Sampler
    
    函数

    GLES ES 函数和 JavaScript 的函数使用方式基本一致,唯一不用的就是 GLSL ES 函数不支持递归调用

    函数参数限定词

    在 GLSL ES中可以为函数参数指定限定词,以控制参数的行为.我们可以将函数参数定位为一下几种

    • 1 传递给函数
    • 2 将要子啊函数中被赋值
    • 3 即是传递给函数的,也要讲要在函数中被赋值的
      其中 2 和 3 有点类似 C 语言中的指针
    参数限定字表如下所示
    类别 规则 描述
    in 向函数传入值 参数传入函数,函数内可以使用参数的值,也可以修改其值,但函数内部的修改不会影响传入的变量
    const in 向函数传入值 参数传入函数,函数内可以使用参数的值,单不能修改
    out 在函数中被赋值,并被传出 传入变量的引用,若其函数被修改,会影响函数外部传入的变量
    intout 传入函数,同时在函数中被赋值,并传出 传入变量的引用,函数会用到变量的初始值,然后修改变量的值,会影响到函数外部传入的值

    全局变量和局部变量

    和 JavaScript 语言一样,GLSL ES中的全局变量和局部变量一样.但是不同的是 GLSL ES 中的 attribute 变量 varying 变量和uniform变量必须为全局变量

    const 变量

    声明 const 变量的时候,需要把 const 写在类型之前,同时对其进行初始化.用 const 修饰的整行数可以作为数组的下标

    attribute 变量

    attribute 变量只能出现在顶点着色器中,并且类型只能是vec2,vec3,vec4,mat2,mat3,mat4,float.webgl的环境都支持至少 8 个 attribute 变量

    uniform 变量

    uniform 变量可以在顶点着色器和片元着色中,必须是全局变量.

    varying 变量

    varying 变量只要的作用是将顶点着色器中的数据传递给片元着色器中.传递的过程中不是直接将顶点着色器中的 varying 变量传递给片元着色器中的 varying 变量.这其中发生了光栅化过程.根据绘制的图形,对前者(顶点着色器的 varying 变量)进行内插,然后在传递给片元着色器.正是因为 varying 变量需要内插,所以我们需要限定它的数据类型

    精度限定字

    在顶点着色器中数据类型默认定义了精度,在片元着色器中 float 的精度需要进行设置.如果一个个的设置的化,会很麻烦,webgl 提供 precision对整个着色器进行设置

    precision mediump float //着色器中float 使用中精度
    

    相关文章

      网友评论

          本文标题:webgl GLSL ES 着色器语言

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