GLSL ES语法
GLSL ES是在GLSL基础上 删除和简化一部分功能后形成的。
尽管是基于OpenGL着色器语言专为 电子产品/嵌入式设备 打造的,
但现在 GLSL ES 也开始被用来完成一些通用任务,如 GPGPU(图像处理和数据运算)。
基础语法
- 大小写敏感
- 语句以分号结尾
以唯一的main函数为入口。
- 单行注释 //
- 多行注释 /**/
- 数值类型
- 整型数
- 浮点数
- 布尔值类型
GLSL变量命名不能以gl_、webgl_、_webgl_开头。
矢量和矩阵
1 | void main(){ |
每种类型都对应一种 构造函数(constructor functions) 以供创建对应类型变量。
构造函数的名称和其创建变量的类型名称总是一致的。
1 | vec3 position = vec3(1.0,0.0,0.5); |
GLSL ES构建矢量的方式相当灵活。
标准构建
1 | vec3 v3 = vec3(1.0,0.3,0.5); |
需要剔除多余元素的构建
1 | vec3 v3 = vec3(1.0,0.3,0.5); |
使用同一值填充全矢量元素的构建
1 | vec4 v4 = vec4(1.0); //(1.0,1.0,1.0,1.0) |
使用多个其他变量结构构建
1 | vec3 v3 = vec3(1.0,0.3,0.5); |
参数数量>1且小于应付的值数,报错
1 | vec3 v33 = vec3(1.0,0.5); //Error |
GLSL中矩阵元素的存储是列主序的。
传入矩阵的每一个元素
1 | /* |
传入一个或多个矢量
1 | // 使用2个vec2构建mat2对象 |
同时传入矢量和数值
1 | // 使用两个浮点数和一个vec2对象创建mat2对象 |
只传一个数值,生成一个对角线全为该数值的矩阵
1 | // 1.0 0.0 |
传入数值数量大于1,又没有达到矩阵元素的数量,导致错误
1 | mat4 m4 = mat4(1.0,2.0,3.0); //Error |
TIP1:这些可以通过名称访问的分量事实上还是通过参数顺序获取的。
TIP2:这些分量只是索引的访问的语法糖,因此可以随意交叠使用。
TIP3:访问超过矢量长度的分量会出错。
1 | vec3 v3 = vec3(1.0,2.0,3.0); |
混合是指将多个分量名共同置于点运算符后,
可以同时从矢量中抽取出多个分量。
1 | vec3 v3 = vec3(1.0,2.0,3.0); |
聚合分量名可作为赋值表达式的左值
1 | vec3 v3 = vec3(1.0,2.0,3.0); |
混合的分量名必须属于同一个分量集合
1 | vec3 v3 = vec3(1.0,2.0,3.0); |
矩阵元素读取仍然按照列主序。
1 | mat4 m4 = mat4( |
使用两个[]访问具体元素
1 | mat4 m4 = mat4( |
使用[]和分量名访问具体元素
1 | float m12 = m4[0].g; // 2.0 |
常量索引值包括:
- 整型字面量
- const声明的值
- 循环索引
- 常量表达式
矢量和矩阵的比较运算符只限于==和!=,不等大小的比较需要通过内置函数。
矢量和浮点数的运算
相加运算
1 | v3b = v3a + f; |
运算结果
1 | v3b.x = v3a.x + f; |
矢量运算
矢量的每个分量都参与运算
1 | v3c = v3a + v3b; |
运算结果
1 | v3c.x = v3a.x + v3b.x; |
矩阵和浮点数运算
矩阵的每个分量都参与浮点数运算
1 | m3b = m3a * f; |
运算结果
1 | m3b[0].x = m3a[0].x * f; |
矩阵右乘矢量
结果为矢量
1 | v3b = m3a * v3a; |
运算结果
1 | v3b.x = m3a[0].x * v3a.x + m3a[1].x * v3a.y + m3a[2].x + v3a.z; |
矩阵左乘矢量
左乘结果与右乘不同
1 | v3b = v3a * m3a; |
运算结果
1 | v3b.x = v3a.x * m3a[0].x + v3a.y * m3a[0].y + v3a.z * m3a[0].z; |
矩阵相乘
1 | m3c = m3a * m3b; |
运算结果
1 | m3c[0].x = m3a[0].x * m3b[0].x + m3a[1].x * m3b[0].y + m3a[2].x * m3b[0].z; |
结构体
注意:结构体成员不能包含数组。
1 | // 定义结构体类型 |
可以在定义结构体的同时声明该类型的变量。
1 | struct light { |
结构体构造函数的名称与结构体名称 一致。
参数顺序必须与结构体中定义的成员顺序 一致。
1 | // 定义结构体类型 |
<结构体对象>.<成员名称>
1 | struct light { |
结构体相等的条件是所有成员都相等。
数组
- 只支持 一维数组
- 数组的长度必须是 大于0的整型常量表达式(integral constant expression)
- 索引值 从0开始
- 索引值只能是 整型常量表达式 或 uniform变量
- 数组不能在声明时 被一次性的初始化,必须显式 对每个元素进行初始化
- 数组元素可以参与其自身类型支持的任意运算
数组的声明
1 | float floatArray[4]; |
数组长度必须是大于0的整型常量表达式
1 | int size = 4; |
使用索引访问数组元素
1 | int intArray[4]; |
必须显式对数组每个元素进行初始化
1 | vec4 vec4Array[4]; |
数组的运算
1 | float floatArray[4]; |
取样器(sampler)
- sampler2D
- samplerCube
只能是 uniform 变量。
1 | uniform sampler2D u_Sampler; |
sampler唯一能够接收的变量就是 纹理单元编号,
必须使用 gl.uniform1i() 将纹理单元编号从WebGL传入 shader 中。
1 | gl.uniform1i(u_Sampler,0); |
sampler变量只能进行赋值(=)、相等(==)、不等(!=)操作。