Skip to content

六、GLSL ES基础

GLSL ES是在GLSL(OpenGL着色器语言)的基础上,删除和简化了一部分功能后形成的,ES版本主要降低了硬件功耗,减少了性能开销。

实际上WebGL并不支持GLSL ES的所有特性,所以大家以后在WebGL API里可能会遇到部分参数无效的情况。

1.基本规范

GLSL ES 是写在着色器中的,其具备以下基本规范:

  • 大小写敏感
  • 语句末尾必须要有分号
  • 以main函数为主函数
  • 注释语法和js 一样
glsl
// 单行注释

/*
    多行
    注释
*/

2.变量

2.1 基本数据类型

  • 数字型
    • 浮点型 float,如1.0
    • 整型 int,如1
  • 布尔型 bool
    • true
    • false

2.2 声明变量

GLSL ES是强类型语言,在声明变量的时候应该指明变量类型,如:

glsl
// <类型> <变量名> = 值
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类:

  • 分量是浮点数:vec2vec3vec4
  • 分量是整数:ivec2ivec3ivec4
  • 分量是布尔数:bvec2bvec3bvec4

3.2 向量的创建

在GLSL ES 中,向量占有很重要的地位,所以GLSL ES为其提供了非常灵活的创建方式。

需要通过vec构造函数来赋值

js
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)

我们还可以将多个向量合在一起:

js
vec4 v4b=vec4(v2,v4);             // (1.0,0.0,1.0,1.0)

注:= 两侧的数据类型必须一致,比如下面的写法会报错:

js
vec4 v4 = vec2(1.0);   //错的

3.3 向量的访问

向量的分量在不同情况下代表不同的含义

  • 在齐次坐标系中通过x、y、z、w来访问齐次坐标的分量
  • 在色值中通过r、g、b、a来访问色值的分量
  • 在纹理坐标中通过s、t、p、q来访问纹理坐标的分量
js
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

也可以通过混合的方式获取多个值,获取到的是⼀个新的矢量内容

js
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)

通过分量索引访问

js
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

用上面的方法访问到向量后,也可以用=号为向量赋值。

js
v4.x=1.0
v4[0]=1.0
v4.xy=vec2(1.0,2.0)

4.矩阵

GLSL ES 支持2*23*34*4维矩阵:

  • mat2
  • mat3
  • mat4

矩阵中的元素都是浮点型。

4.1 矩阵的创建

GLSL ES 中的矩阵是列主序的,在建立矩阵的时候,其参数结构有很多种。

  • 浮点数,其参数是按照列主序排列的。
js
mat4 m=mat4(
    1,5,9,13,
    2,6,10,14,
    3,7,11,15,
    4,8,12,16
);
  • 向量
js
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
]    
*/
  • 浮点+向量
js
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]可以访问矩阵的某一行。

js
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列的元素。

js
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] 可以理解为一个向量,其内部的元素,可以像访问向量元素一样去访问。

js
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 //1

4.2.4 索引值的限制

[] 中的索引值只能通过以下方式定义:

  • 整形字面量,如0,1,2,3
js
m[0]
m[1]
  • const 修饰的变量
js
const int y=0;
m[y];

注:以下写法是错误的

js
int y=0;
m[y];
  • 循环索引
js
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];
    }
    ……
}
  • 前面三项组成的表达式
js
const int y=0;
m[y+1];

5.纹理取样器

取样器有两种: sampler2DsamplerCube,只能声明为 uniform 变量

5.1 声明

glsl
// 声明二位纹理
uniform sampler2D uSampler;

// 立方体纹理
uniform samplerCube usamplerCube;

二维纹理的使用

js
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)

立方体纹理的使用

js
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

js
if(条件1){
    // ...
}else if(条件2){
    // ...
}else{
    // ...
}

6.1.2 switch

js
switch(){
    case 条件1:
        // ...
        break;
    case 条件2:
        // ...
        break;
    // ...
    default:
        break;
}

6.2 循环

6.2.1 语句

js
for(){}

while(){}

do{
    
}while()

6.2.2 跳出循环

glsl
continue  //结束本次循环,进行下一次循环

break 	//结束整个循环

discard 
//discard 只能在片元着色器中使用,表示放弃当前片元直接处理下一个片元。

7.函数

glsl函数的语法类似与c语言

glsl
返回值类型 函数名(参数1类型 参数1,参数2类型 参数2){
    // 函数体
    return 返回值
}

float getFloat(float num){
    return num+1.0
}

8.内置函数

8.1 角度函数

glsl
radians(); // 角度转弧度
degrees(); // 弧度转角度

8.2 三角函数

glsl
sin();	// 正弦
cos();	// 雨弦
tan();	// 正切
asin();	// 反正弦
acos();	// 反正弦
atan();	// 反正弦

8.3 指数函数

glsl
pow();	// 次方
exp();	// 自然质数
log();	// 对数
sqrt();	// 平方根
inversesqrt()	//	平方根的倒数

8.4 通用函数

glsl
abs(); 	// 绝对值
min(); 	// 最小值
max(); 	// 最大值
mod(); 	// 取余数
sign(); 	// 取符号
floor(); 	// 向下取整
ceil(); 	// 向上取整
clamp(); 	// 限定范围
fract(); 	// 获取小数部分

8.5 几何函数

glsl
length(x); 	// 计算x的长度
distance(x,y);	// 计算向量xy之间的距离
dot(x,y);	// 计算向量xy的点积
cross(x,y);	// 计算向量xy的差积
normalize(x);	// 返回方向同x,长度为1的向量

8.6 矢量函数

glsl
any();	// 矢量的任意一个元素为true
all();	// 矢量的所有元素为true
not();	// 逐元素取补

9.存储限定词

glsl
const		// 声明一个常量,定义之后不能被修改
attribute	// 使用在顶点着色器中,只能声明全局变量,表示单个顶点信息
uniform		// 可使用在顶点和片元着色器中,只读类型,用来存储影响所有顶点的数据
varying		// 从顶点着色器向片元着色器传递数据
    
// 单个变量精度限制
mediump float f;
highp float f;
lowp float f;

// 定义着色器的默认精度
precision highp/mediump/lowp float

MIT Licensed