六、GLSL ES基础
GLSL ES是在GLSL(OpenGL着色器语言)的基础上,删除和简化了一部分功能后形成的,ES版本主要降低了硬件功耗,减少了性能开销。
实际上WebGL并不支持GLSL ES的所有特性,所以大家以后在WebGL API里可能会遇到部分参数无效的情况。
1.基本规范
GLSL ES 是写在着色器中的,其具备以下基本规范:
- 大小写敏感
- 语句末尾必须要有分号
- 以main函数为主函数
- 注释语法和js 一样
// 单行注释
/*
多行
注释
*/2.变量
2.1 基本数据类型
- 数字型
- 浮点型 float,如1.0
- 整型 int,如1
- 布尔型 bool
- true
- false
2.2 声明变量
GLSL ES是强类型语言,在声明变量的时候应该指明变量类型,如:
// <类型> <变量名> = 值
float f = 1.0;
int i = 1;
bool b = true;2.3 变量命名规范
- 只能包括a-z,A-Z,0-9,_
- 变量名首字母不能是数字
- 不能是GLSL 关键字,如attribute,vec4,bool
- 不能是GLSL 保留字,如cast,class,long
- 不能以下单词开头:gl_, webgl_, _webgl_
2.4 变量的赋值
变量使用等号=赋值,=两侧的数据类型需要一致。
int i=8; // ✔
int i=8.0; // ✖
float f=8; // ✖
float f=8.0; // ✔2.5 类型转换
可以通过以下方法实现强制类型转换
- 转换成整型:
int() - 转换成浮点型:
float() - 转换成布尔型:
bool()
2.6 运算符
- 算数运算符:
+、-、*、/ - 比较运算符:
>、<、>=、<=,==、!= - 赋值运算符:
+=、-=、/=、*= - 逻辑运算符:
!、&&、|| - 一元运算符:
++、-- - 三元运算符:
表达式 ? 为真的结果 : 为假的结果 - 异或:
^^
3.向量/矢量
3.1 向量的分类
GLSL ES 支持2、3、4维向量,根据分量的数据类型,向量可以分为3类:
- 分量是浮点数:
vec2、vec3、vec4 - 分量是整数:
ivec2、ivec3、ivec4 - 分量是布尔数:
bvec2、bvec3、bvec4
3.2 向量的创建
在GLSL ES 中,向量占有很重要的地位,所以GLSL ES为其提供了非常灵活的创建方式。
需要通过vec构造函数来赋值
vec3 v3 = vec3(1.0, 0.0, 0.5); // (1.0, 0.0, 0.5)
vec2 v2 = vec2(v3); // (1.0, 0.0)
vec4 v4 = vec4(1.0); // (1.0,1.0,1.0,1.0)我们还可以将多个向量合在一起:
vec4 v4b=vec4(v2,v4); // (1.0,0.0,1.0,1.0)注:= 两侧的数据类型必须一致,比如下面的写法会报错:
vec4 v4 = vec2(1.0); //错的3.3 向量的访问
向量的分量在不同情况下代表不同的含义
- 在齐次坐标系中通过x、y、z、w来访问齐次坐标的分量
- 在色值中通过r、g、b、a来访问色值的分量
- 在纹理坐标中通过s、t、p、q来访问纹理坐标的分量
vec4 position = vec4(1.0,1.0,0.0,1.0)
position.x // 1.0
position.Y // 1.0
position.Z // 0.0
position.W // 1.0也可以通过混合的方式获取多个值,获取到的是⼀个新的矢量内容
vec4 v4 = vec4(1.0,2.0,3.0,4.0);
v4.xy //(1.0,2.0)
v4.yx //(2.0,1.0)
v4.xw //(1.0,4.0)通过分量索引访问
vec4 v4 = vec4(1.0,2.0,3.0,1.0);
v4[0] // 1.0
v4[1] // 2.0
v4[2] // 3.0
v4[3] // 1.0用上面的方法访问到向量后,也可以用=号为向量赋值。
v4.x=1.0
v4[0]=1.0
v4.xy=vec2(1.0,2.0)4.矩阵
GLSL ES 支持2*2、3*3、4*4维矩阵:
- mat2
- mat3
- mat4
矩阵中的元素都是浮点型。
4.1 矩阵的创建
GLSL ES 中的矩阵是列主序的,在建立矩阵的时候,其参数结构有很多种。
- 浮点数,其参数是按照列主序排列的。
mat4 m=mat4(
1,5,9,13,
2,6,10,14,
3,7,11,15,
4,8,12,16
);- 向量
vec4 v4_1=vec4(1,2,3,4);
vec4 v4_2=vec4(5,6,7,8);
vec4 v4_3=vec4(9,10,11,12);
vec4 v4_4=vec4(13,14,15,16);
mat4 m=mat4(v4_1,v4_2,v4_3,v4_4);
/*
[
1,2,3,4,
5,6,7,8,
9,10,11,12,
13,14,15,16
]
*/- 浮点+向量
vec4 v4_1=vec4(1,5,9,13);
vec4 v4_2=vec4(2,6,10,14);
mat4 m=mat4(
v4_1,
v4_2,
3,7,11,15,
4,8,12,16
);
/*
1,5,9,13,
2,6,10,14,
3,7,11,15,
4,8,12,16
*/- 单个浮点数
mat4 m=mat4(1);
/*
[
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]
*/注:如矩阵中的参数数量大于1,小于矩阵元素数量,会报错
mat4 m4 = mat4(1.0,2.0);
/*报错*/4.2 矩阵的访问
4.2.1 访问某一行
使用[indexX]可以访问矩阵的某一行。
mat4 m=mat4(
1,5,9,13,
2,6,10,14,
3,7,11,15,
4,8,12,16
);
m[0]
/*
1,5,9,13,
*/4.2.2 访问某个元素
使用 m[indexX][indexY] 方法,可以访问矩阵第y行,第x列的元素。
mat4 m=mat4(
1,5,9,13,
2,6,10,14,
3,7,11,15,
4,8,12,16
);
m[0][0]
/* 1 */4.2.3 一行可以是一个向量
m[y] 可以理解为一个向量,其内部的元素,可以像访问向量元素一样去访问。
mat4 m=mat4(
1,5,9,13,
2,6,10,14,
3,7,11,15,
4,8,12,16
);
m[0].[0] //1
m[0].x //1
m[0].r //1
m[0].s //14.2.4 索引值的限制
[] 中的索引值只能通过以下方式定义:
- 整形字面量,如0,1,2,3
m[0]
m[1]- 用const 修饰的变量
const int y=0;
m[y];注:以下写法是错误的
int y=0;
m[y];- 循环索引
mat4 n=mat4(
1,5,9,13,
2,6,10,14,
3,7,11,15,
4,8,12,16
);
mat4 m=mat4(1);
void main(){
for(int i=0;i<4;i++){
m[i]=n[i];
}
……
}- 前面三项组成的表达式
const int y=0;
m[y+1];5.纹理取样器
取样器有两种: sampler2D 和 samplerCube,只能声明为 uniform 变量
5.1 声明
// 声明二位纹理
uniform sampler2D uSampler;
// 立方体纹理
uniform samplerCube usamplerCube;二维纹理的使用
const texture = gl.createTexture()
gl.pixelStorei(gl.UNPACK_FILP_Y_WEBGL,1)
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D,texture)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FLIP,gl.LINEAR)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FLIP,gl.LINEAR)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE)
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE)
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)
gl.uniform1I(uSampler,0)立方体纹理的使用
const cubeMap = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_CUBE_MAP,cubeMap ) ;
gl.pixelStorei(g1.UNPACK_FLIP_Y_WEBGL, true) ;
gl.texParameteri(gl.TEXTURE_CUBE_MAP,gl.TEXTURE_MAG_FILTER,gl.LINEAR)
gl.texParameteri(gl.TEXTURE_CUBE_MAP,gl.TEXTURE_MIN_FILTER,gl.LINEAR)
gl.texParameteri(gl.TEXTURE_CUBE_MAP,gl.TEXTURE_NRAP_S, gl.CLAMP_TO_EDGE)
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE)
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z ,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,images[0]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_z ,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,images[1]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_x ,0,g1.RGB,gl.RGB,g1.UNSIGNED_BYTE,images[2]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_x ,0,gl.RGB,g1.RGB,g1.UNSIGNED_BYTE,images[3]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y ,0,gl.RGB,gl.RGB,g1.UNSIGNED_BYTE,images[4]);
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,images[5]);
gl.uniform1i(usamplerCube,1);6.分支和循环
6.1 分支
6.1.1 if-else
if(条件1){
// ...
}else if(条件2){
// ...
}else{
// ...
}6.1.2 switch
switch(){
case 条件1:
// ...
break;
case 条件2:
// ...
break;
// ...
default:
break;
}6.2 循环
6.2.1 语句
for(){}
while(){}
do{
}while()6.2.2 跳出循环
continue //结束本次循环,进行下一次循环
break //结束整个循环
discard
//discard 只能在片元着色器中使用,表示放弃当前片元直接处理下一个片元。7.函数
glsl函数的语法类似与c语言
返回值类型 函数名(参数1类型 参数1,参数2类型 参数2){
// 函数体
return 返回值
}
float getFloat(float num){
return num+1.0
}8.内置函数
8.1 角度函数
radians(); // 角度转弧度
degrees(); // 弧度转角度8.2 三角函数
sin(); // 正弦
cos(); // 雨弦
tan(); // 正切
asin(); // 反正弦
acos(); // 反正弦
atan(); // 反正弦8.3 指数函数
pow(); // 次方
exp(); // 自然质数
log(); // 对数
sqrt(); // 平方根
inversesqrt() // 平方根的倒数8.4 通用函数
abs(); // 绝对值
min(); // 最小值
max(); // 最大值
mod(); // 取余数
sign(); // 取符号
floor(); // 向下取整
ceil(); // 向上取整
clamp(); // 限定范围
fract(); // 获取小数部分8.5 几何函数
length(x); // 计算x的长度
distance(x,y); // 计算向量xy之间的距离
dot(x,y); // 计算向量xy的点积
cross(x,y); // 计算向量xy的差积
normalize(x); // 返回方向同x,长度为1的向量8.6 矢量函数
any(); // 矢量的任意一个元素为true
all(); // 矢量的所有元素为true
not(); // 逐元素取补9.存储限定词
const // 声明一个常量,定义之后不能被修改
attribute // 使用在顶点着色器中,只能声明全局变量,表示单个顶点信息
uniform // 可使用在顶点和片元着色器中,只读类型,用来存储影响所有顶点的数据
varying // 从顶点着色器向片元着色器传递数据
// 单个变量精度限制
mediump float f;
highp float f;
lowp float f;
// 定义着色器的默认精度
precision highp/mediump/lowp float