着色器和GLSL - WebGL
顶点着色器
一个顶点着色器的工作是生成裁剪空间坐标值,通常是以下的形式
1 |
|
每个顶点调用一次(顶点)着色器,每次调用都需要设置一个特殊的全局变量 gl_Position, 该变量的值就是裁减空间坐标值
顶点着色器需要的数据,可以通过以下三种方式获得:
- Attributes 属性 (从缓冲中获取的数据)
1 |
|
1 |
|
- Uniforms 全局变量 (在一次绘制中对所有顶点保持一致值)
全局变量在一次绘制过程中传递给着色器的值都一样
1 |
|
1 |
|
要注意的是全局变量属于单个着色程序,如果多个着色程序有同名全局变量,需要找到每个全局变量并设置自己的值。 我们调用 gl.uniform???的时候只是设置了当前程序的全局变量,当前程序是传递给 gl.useProgram 的最后一个程序
全局变量有很多类型,对应的类型有对应的设置方法:
1 |
|
还有一些类型 bool, bvec2, bvec3, and bvec4。它们可用 gl.uniform?f?或 gl.uniform?i?
一个数组可以一次设置所有的全局变量:
1 |
|
如果你想单独设置数组中的某个值,就要单独找到该值的地址:
1 |
|
同样的,如果你创建了一个结构体:
1 |
|
你需要找到每个元素的地址
1 |
|
- ⌛️ Textures 纹理 (从像素或纹理元素中获取的数据)
片段着色器
一个片段着色器的工作是为当前光栅化的像素提供颜色值,通常是以下的形式:
1 |
|
每个像素都将调用一次片段着色器,每次调用需要从你设置的特殊全局变量 gl_FragColor 中获取颜色信息
片段着色器所需的数据,可以通过以下三种方式获取:
- Uniforms 全局变量 (values that stay the same for every pixel of a single draw call)
同上(顶点着色器)
- Textures 纹理 (data from pixels/texels)
在着色器中获取纹理信息,可以先创建一个 sampler2D 类型全局变量,然后用 GLSL 方法 texture2D 从纹理中提取信息:
1 |
|
从纹理中获取的数据取决于很多设置。 至少要创建并给纹理填充数据,例如
1 |
|
- Varyings 可变量 (data passed from the vertex shader and interpolated)
可变量是一种顶点着色器给片段着色器传值的方式
为了使用可变量,要在两个着色器中定义同名的可变量。 给顶点着色器中可变量设置的值,会作为参考值进行内插,在绘制像素时传给片段着色器的可变量
1 |
|
GLSL
GLSL 全称是 Graphics Library Shader Language (图形库着色器语言),是着色器使用的语言。 它有一些不同于 JavaScript 的特性,主要目的是为栅格化图形提供常用的计算功能。 所以它内建的数据类型例如 vec2, vec3 和 vec4 分别代表两个值,三个值和四个值, 类似的还有 mat2, mat3 和 mat4 分别代表 2x2, 3x3 和 4x4 矩阵。 你可以做一些运算例如常量和矢量的乘法
1 |
|
他还为矢量数据提供多种分量选择器,例如 vec4:
- v.x 和 v.s 以及 v.r , v[0] 表达的是同一个分量。
- v.y 和 v.t 以及 v.g , v[1] 表达的是同一个分量。
- v.z 和 v.p 以及 v.b , v[2] 表达的是同一个分量。
- v.w 和 v.q 以及 v.a , v[3] 表达的是同一个分量。
它还支持矢量调制,意味者你可以交换或重复分量:
1 |
|
值得注意的是 GLSL 是一个强类型的语言:
1 |
|
上例中 vec4(v.rgb, 1) 不会因为 1 报错,因为 vec4 内部进行了转换类似 float(1)
GLSL 有一系列内置方法,其中大多数运算支持多种数据类型,并且一次可以运算多个分量,例如:
1 |
|