文章目录
- 前言
- OpenGL ES基础
- 一段基本的着色器代码
- 大小写和分号
- 数据值类型、命名规范、类型转换
- 运算符
- 矢量和矩阵
- 矢量和矩阵类型
- 矢量构造、访问
- 矩阵构造、访问
- 矢量矩阵运算规则
- 特殊类型—结构体和数组
- 结构体
- 数组
- 取样器
- 总结
前言
着色器语言通过控制GPU来进行前端图形的渲染,WebGL使用名为GLSL ES的规范进行着色器语言的编写,GLSL ES是在OpenGL的基础上进行一定的精简后形成的,它的语法与C语言有些类似。 本文对webgl常用到的GLSL ES知识进行记录。
着色器以字符串的形式存储在javascript中
OpenGL ES基础
一段基本的着色器代码
// 顶点着色器
const vertex = `
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
gl_PointSize = 10.0;
}
`
// 片元着色器
const fragment = `
precision highp float;
uniform vec4 uColor;
void main(){
gl_FragColor = uColor;
}
`
大小写和分号
- 大小写敏感
const vertex = `
// 不会报错,aPosition和aposition是两个不同的变量
attribute vec4 aPosition;
attribute vec4 aposition;
void main() {
gl_Position = aPosition;
gl_PointSize = 10.0;
}
`
- 强制分号
const vertex = `
attribute vec4 aposition // 运行会报错
void main() {
gl_Position = aPosition;
gl_PointSize = 10.0;
}
`
- 执行次序
着色器的执行从main函数开始逐行运行,无论是顶点着色器还是片元着色器都有且只有一个main函数作为整个程序的入口,该函数由void声明,不接受任何参数,也没有返回值。
- 注释
着色器的注释与js相同, // 进行单行注释;/* xxx */ 进行多行注释。
数据值类型、命名规范、类型转换
GLSL 是强类型语言,数据声明时必须指定类型。GLSL支持整形(int),浮点型(float),布尔(bool)三种数据类型。
const vertex = `
void main() {
int ten = 10; // 整型
float pie = 3.14; // 浮点型
bool isOk = true; // 布尔型
gl_Position = aPosition;
gl_PointSize = 10.0;
}
`
变量的命名需要遵守以下规则:
- 只包括a-z,A-Z,0-9,_,无其它特殊字符
- 首位不能是数字
- 不能以gl_、webgl_、_webgl_开头
- 避免与webgl内置关键字或者保留字重名
不同类型的变量之间不能直接相互赋值,但是通过内置函数进行类型转换后可以:
名称 | 参数类型 | 含义 |
---|---|---|
int ( x ) | float / bool | 转换为整数 |
float ( x ) | int / bool | 转换为小数 |
bool ( x ) | float / int | 转换为布尔 |
运算符
矢量和矩阵
矢量和矩阵类型
类型 | GLSL ES类型 | 含义 |
---|---|---|
矢量 | vec2、vec3、vec4 | 长度为2、3、4,元素类型为float的矢量 |
矢量 | ivec2、ivec3、ivec4 | 长度为2、3、4,元素类型为int的矢量 |
矢量 | bvec2、bvec3、bvec4 | 长度为2、3、4,元素类型为bool的矢量 |
矩阵 | mat2、mat3、mat4 | 维度为2 * 2、3 * 3、4 * 4,元素类型为float的矩阵 |
矢量构造、访问
- 矢量构造函数赋值
const vertex = `
void main() {
vec4 vector4 = vec4(1.0, 1.0, 1.0, 1.0); // 普通赋值
vec4 vector4_copy = vec4(vector4); // 复制
vec2 vector2 = vec2(vector4); // 取vector4前两个值组成矢量
vec4 vector4_copy2 = vec4(2.0); // vec4(2.0, 2.0, 2.0, 2.0)
vec4 vector4_new = vec4(vector2, vector2); // 组装成一个vec4
···
}
`
- 矢量访问
可以通过 . 进行访问
const vertex = `
void main() {
vec4 vector4 = vec4(1.0, 2.0, 3.0, 1.0); // 普通赋值
float v1 = vector4.x // 1.0
vec2 v2 = vector4.xy // vec2(1.0, 1.0)
vec2 v2_ = vector4.zx // vec2(3.0, 1.0)
···
}
`
也可以通过 [ ] 获取下标进行访问
const vertex = `
void main() {
vec4 vector4 = vec4(1.0, 2.0, 3.0, 1.0); // 普通赋值
float v1 = vector4[0] // 1.0
}
`
矩阵构造、访问
- 矩阵赋值
矩阵传入值必须是列主序的
像上面整个矩阵,赋值方式如下:
mat m4 = (
a, e, i, m,
b, f, j, n,
c, g, k, o,
d, h, l, p
)
// 或者
vec4 vec1 = (a, e, i, m)
vec4 vec2 = (b, f, j, n)
vec4 vec3 = (c, g, k, o)
vec4 vec4 = (d, h, l, p)
mat4 m4 = mat4(vec1, vec2, vec3, vec4)
- 矩阵访问
可以通过 . 和 [ ] 进行访问
const vertex = `
void main() {
vmat m4 = (
a, e, i, m,
b, f, j, n,
c, g, k, o,
d, h, l, p
)
vec4 v4_ = vector4[3]; // [m, n, o, p]
float v4_2 = vector4[3][1] ; // n
vec4 v4_2 = vector4[3].y; // n
···
}
`
矢量矩阵运算规则
- 当矩阵之间进行计算时(+ 、- 、* 、/),遵从矩阵运算规则。
- 矢量之间进行计算时(+ 、- 、* 、/),
对应位置上的元素进行相应计算
。 - 矩阵矢量之间进行计算时(* 、/),
当向量在左,计算规则按照1 * n的矩阵与n阶矩阵相乘;当向量在右边,按照n阶矩阵与n*1的矩阵相乘
。
特殊类型—结构体和数组
结构体
GLSL ES支持使用结构体来创建用户自定义的类型,与C++十分类似:
// 定义结构体pen
struct pen {
vec4 color;
float lenght;
}
// 声明pen类型的对象
pen pen1, pen2;
// 给结构体赋值
pen1 = pen(vec4(1.0,0.0,0.0,1.0, 10.1);
// 访问结构体
vec4 pen1_color = pen1.color;
float pen1_length = pen1.length;
数组
GLSL ES同时也支持数据类型,但是仅支持一维数组,数组不支持pop()和push()操作,数组不能一次性初始化,必须显式地对每个元素初始化。
// 声明数组
float floatArray[4]; // 元素类型是float,长度是4的数组
vec4 vec4Array[2]; // 元素类型是vec4,长度是2的数组
// 数组赋值
floatArray[0] = 0.0;
floatArray[1] = 1.0;
floatArray[2] = 2.0;
floatArray[3] = 3.0;
vec4Array[0] = (0.0,0.0,0.0,0.0);
vec4Array[1] = (1.0,1.0,1.0,1.0);
取样器
GLSL ES支持一种名为取样器(sampler的变量类型获取纹理,取样器变量必须是uniform变量,取样器支持两种类型sampler2D和samplerCube,sampler2D的使用见webgl纹理贴图机制,samplerCube是立方体纹理,使用和sampler2D差不多,唯一区别就是在使用gl.texImage2D()进行图像分配给纹理对象时,要把六个面的数据都分配一次。
总结
OpenGL ES基础
- 一段基本的着色器代码
- 大小写和分号
- 数据值类型、命名规范、类型转换
- 运算符
矢量和矩阵
- 矢量和矩阵类型
- 矢量构造、访问
- 矩阵构造、访问
- 矢量矩阵运算规则
特殊类型—结构体和数组
- 结构体
- 数组
取样器