- GLSL语法简介
- WebGL内置函数
WebGL GLSL
GLSL语法简介
glsl是为计算机量声定制的用于编写着色器的语言,它包含一些针对向量和矩阵操作的特性,使渲染管线具有可编程性,
●变量
●语句
●限定符
变量
变量及变量的类型
变量类型 | 说明 | 默认值 | 可选参数 |
---|---|---|---|
bool | 布尔型标量数据类型 | false | |
int/ivec2/ivec3/ivec4 | 表示1/2/3/4 个整型向量 | 0/[0,0]/[0,0,0]/[0,0,0,0] | |
float/vec2/vec3/vec4 | 包含1,2,3,4个浮点型向量 | 0/[0,0]/[0,0,0]/[0,0,0,0] | |
sampler2D | 表示2D纹理,通常使用在图片采样上,进行图片贴图 | default | black、grey、white、normal、default |
samplerCube | 表示立方体纹理 | default-cube | black-cube,white-cube,default-cube |
mat[2..3] | 表示2x2和3x3的矩阵 | 不可用 | |
mat4 | 表示4x4的矩阵 | [1,0,0,0,......] |
标量
构造标量的方式和C语言一致:
float floatValue = 1.0;
bool booleanValue = false;
向量
构造向量时的规则如下:
●若向向量构造器提供一个标量,则向量的所有值都会设定为该标量值
●若提供多个标量或向量,则从左到右使用提供的值赋值,前提是标量或向量的数量之和要等于向量构造器的数量
简单来说就是标量声明和后面赋值的类型是相同的 (vec2 = vec2......)
vec4 myVec4 = vec4(1.0);
vec2 myVec2 = vec2(0.5,0.5);
vec4 newVec4 = vec4(1.0,1.0,myVec2);
向量可以通过r,g,b,a或x,y,z,w进行访问,也可以同时访问多个角标
vec4 myVec4_0 = vec4(1.0);
vec4 myVec4 = vec4(1.0,2.0,3.0,4.0);
float x = myVec4.x;
vec3 myVec3_0 = myVec4.xyz;
vec3 myVec3_1 = myVec4.rgb;
vec3 myVec3_2 = myVec4.zyx;
vec3 myVec3_3 = myVec4.xxx;
矩阵
在GLSL内可构造mat[2...4]来表示2阶到4阶的矩阵
矩阵构造有如下的规则:
●若只为矩阵构造器提供了一个标量,则该值会构造矩阵对角线上的值
●矩阵可以由多个向量构造
●矩阵可以由单个标量从左到右进行构造
mat4 marix4x4 = mat4(1.0);
// marix4x4 ={ 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 }
vec2 col2 = vec2(1.0,0.0);
vec2 col2 = vec2(1.0,0.0);
mat2 matrix2x2 = mat2(col2,col2)
// GLSL 是列矩阵存储,因此构造时,构造器会按照列顺序进行填充
mat3 matrix3x3 = mat3(0.0,0.0,0.0,
0.0,0.0,0.0,
0.0,0.0,0.0);
```Glsl
> 注意:为避免implicit padding,引擎规定若要使用Uniform限定符的矩阵,必须是4阶矩阵,2阶和3阶的矩阵不可作为Unform变量
>
矩阵的访问:
矩阵可以通过索引访问不同的列:
```Glsl
mat2 matrix2x2 = mat2(0.0,0.0,0.0,0.0);
vec4 myVec4 = vec4(matrix2x2[0],matrix2x2[1]);
vec2 myVec2 = matrix2x2[0];
// 访问第一列的第一个元素
float value = matrix2x2[0][0];
matrix2x2[1][1] = 2.0;
结构体
结构体的形成和C语言类似,可由不同数据类型聚合而成:
struct myStruct {
vec4 position;
vec4 color;
vec4 uv;
}
结构构造体的代码示例如下:
myStruct structVar = myStryct( vec4(0.0,0.0,0.0,0.0),vec4(1.0,1.0,1.0,1.0),vec2(0.5,0.5) )
数组
数组的用法和C语言类似,规则如下:
●数组必须声明长度
●数组不能在声明的同时初始化
●数组必须由常量表达式初始化
●数组不能用const修饰
●不支持多维数组
数组声明和初始化的代码示例如下:
float array[4];
for(int i = 0; i < 4; i++ ){
array[i] = 0.0;
}
控制流程
GLSL支持标准的C、C++流程,包括
●if-else switch-case
●for while do-while
●break continue return
●没有goto,若要跳出可使用discard,该语句仅在片元着色器下有效,需要注意的是使用该语句会导致管线放弃当前片元,不会写入帧缓存
if-else的用法和C语言一致,代码示例如下:
if(v_uvMode >= 3.0){
....
}else if(v_uvMode <= 2.0){
...
}else{
.....
}
在GLSL中,循环变量必须是常量或者编译时已知,代码示例如下:
const float value = 10.0;
for(float i = 0.0;i<value;i++){
....
}
错误示范:(没有const关键字定义常量)
float value = 10.0;
for(float i = 0.0;i<value;i++){
....
}
函数
GLSL 的函数由返回值 函数名 和 参数构成,其中返回值和函数名是必须的。若没有返回值,需要使用void代替
注意:GLSL的函数不能递归
代码示例如下:
void scaleMatrix(inout mat4 m, float s){
m[0].xyz *= s;
m[1].xyz *= s;
m[2].xyz *= s;
}
限定符
存储限定符
储存限定符用于描述变量在管线中的作用。
限定符 | 说明 |
---|---|
none:default | 无限定符或使用default,常用语 局部变量,函数参数 |
const | 编译时为常量或作为参数时只读 |
attribute | 应用程序和顶点着色器间通信,用于确定顶点格式 |
uniform | 应用程序和着色器之间交互数据,在顶点着色器和片元着色器中保持一致 |
varying | 顶点着色器传输给片元着色器的插值 |
uniform
在一个渲染过程内声明的unform不能重复。例如在顶点着色器中定义了变量variableA,variableA也会存在于片元着色器且值相同,那么也就是variableA不能在片元着色器中再次定义。
引擎不支持离散声明的unform变量,必须使用UBO并保持内存对齐,以避免 implicit padding
varying
varying是由顶点着色器输出并传输给片元着色器的变量。在管线的作用下,变量值并不会和顶点着色器输出的保持一致,而是由管线进行插值,这就可能会出现顶点输出的法线没有归一化的情况,此时需要手动归一化,代码示例如下:
// 归一化法线
vec3 normal = normalize(v_normal)
参数限定符
GLSL 中函数的参数限定符包括以下几种:
限定符 | 说明 |
---|---|
none:in | 缺省限定符,和C语言的值传递类似,指明传入的参数传递的是值,函数内不会修改传入的值 |
inout | 类似于C语言的引用,参数的值会传入函数并返回函数内修改的值 |
out | 参数的值不会传入函数,由函数内部修改并返回修改后的值 |
精度限定符
GLSL 引入精度限定符,用于指定整型或浮点型变量的精度。精度限定符可使着色器的编写者明确定义着色器变量计算时使用的精度。在Shader头部声明的精度应用于整个Shader,是所有基于浮点型的变量的默认精度,同时也可以定义单个变量的精度。在Shader中如果没有指定默认的精度,则所有的浮点型变量都采用高精度计算。
GLSL支持精度限定符包括以下几种:
限定符 | 说明 |
---|---|
highp | 高精度 浮点型精度范围为【-262,262】 整型精度范围为【-216,216】 |
mediump | 中精度 浮点型精度范围为【-214,214】 整型精度范围为【-210,210】 |
lowp | 低精度 浮点型精度范围为【-28,28】 整型精度范围为【-28,28】 |
代码实例如下:
highp mat4 cc_matWorld;
mediump vec2 dir;
lowp vec4 cc_shderColor;
预处理宏定义
GLSL允许定义和C语言类型的宏定义
预处理宏定义允许着色器定义多样化的动态分支,确定最终的渲染效果
在GLSL中使用预处理宏定义的代码示例如下:
#define // 宏定义 示例:#define 宏名 宏内容
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
下方代码示例若USE_VERTEX_COLOR条件为真,则声明一个名为v_color的四维向量:
#if USE_VERTEX_COLOR
in vec4 v_color;
#endif
WebGL内置函数
和角度相关的函数
函数 | 参数 | 描述 |
---|---|---|
sin(x) | 弧度 | 正弦函数 |
cos(x) | 弧度 | 余弦函数 |
tan(x) | 弧度 | 正切函数 |
asin(x) | 弧度 | 反正弦函数 |
acos(x) | 弧度 | 反余弦函数 |
atan(x) | 弧度 | 反正切函数 |
radians(x) | 弧度 | 角度转换为弧度 |
degrees(x) | 弧度 | 弧度转换为角度 |
数学函数
这类主要是对指数对数幂函数的操作
函数 | 描述 |
---|---|
pow(x,y) | x的y次方,如果x小于0,结果是未定义的,同样,如果x=0并且y<=0,结果也是未定义的 |
exp(x) | e的x次方 |
log(x) | 计算满足x等于e的y次方的y的值。如果x的值小于0,结果是未定义的 |
exp2(x) | 计算2的x次方 |
log2(x) | 计算满足x等于2的y次方的y的值,如果x的值小于0,结果是未定义的 |
sqrt(x) | 计算x的开方,如果x小于0,结果是未定义的 |
inversesqrt(x) | 计算x的开方之一的值,如果x小于等于0,结果是未定义的。 |
常用函数
这里是常用函数,和js中的内置函数很像,需要牢记。
函数 | 描述 |
---|---|
abs(x) | 返回x的绝对值 |
sign(x) | 如果x>0,返回1.0;如果x=0,返回0,如果x<0,返回-1.0 |
floor(x) | 向下取整 |
ceil(x) | 向上取整 |
fract(x) | 返回x的小数部分 |
mod(x, y) | 也就是取x除以y的余数 |
min(x, y) | 最小值 |
max(x, y) | 最大值 |
clamp(x, minVal, maxVal) | 将x值钳于minVal和maxVal之间,意思就是当x<minVal时返回minVal,当x>maxVal时返回maxVal,当x在minVal和maxVal之间时,返回x |
mix(x, y, a) | 返回线性混合的x和y,如:x * ( 1 − a ) + y * a |
step(edge, x) | 如果x < edge,返回0.0,否则返回1.0。 若第二个数大于第一个数,则返回0.0(白色),否则:返回1.0(黑色) |
smoothstep(edge0, edge1, x) | 如果x <= edge0,返回0.0 ;如果x >= edge1 返回1.0;如果edge0 < x < edge1,则执行0~1之间的平滑埃尔米特差值。如果edge0 >= edge1,结果是未定义的。 |
几何函数
这是与长度、距离、向量等相关的函数
length(x) | 返回向量x的长度 |
---|---|
distance(p0:vec2,p1:vec2) | 计算向量p0,p1之间的距离,则就是计算两点之间的距离 |
dot(x,y) | 向量x,y之间的点积 |
cross(x, y) | 向量x,y之间的叉积 |
normalize(x) | 标准化向量,返回一个方向和x相同但长度为1的向量 |
faceforward(N, I, Nref) | 如果Nref和I的点积小于0,返回N;否则,返回-N; |
reflect(I, N) | 返回反射向量 |
refract(I, N, eta) | 返回折射向量 |
经常用的函数差不多就是这些。还需要我们在实践中反复练习,才能使用的得心应手。
内置属性
#define 定义一个变量 #define PI 3.14
tips: 定义函数后面不能加分号“;”