- 前言
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 使用中精度
网友评论