WebGL -- 着色器语言GLSL ES

1,215 阅读5分钟

在进入三维世界前,我们先看看三维世界的基石吧,这一篇得先看看什么是着色器,知道着色器语言怎么读和写,这样在之后的三维渲染中更加容易理解。

GLSL ES(OpenGL ES Shading Language)是一种编写着色器程序的语言,用于在OpenGL ES图形API中实现高度定制化的渲染效果。它是基于C语言,它支持向量和矩阵运算、纹理采样、光照计算等操作,可以用于在图形渲染管线中实现各种各样的渲染效果。

在之前的篇章中,每个例子中都会设计两个着色器,顶点着色器和片元着色器,顶点着色器负责将顶点转换到屏幕坐标系中,而片段着色器则计算每个像素的颜色值。

强类型语言

GLSL ES是强类型语言,"强类型语言"指的是编程语言中对变量和表达式的类型进行严格检查的语言,相对于js弱类型语言,这就得在声明变量的时候指出其数据类型了,且该类型不能被隐式转换为其他类型。

基本数据类型

  • 数值类型: 整数型浮点型
  • 布尔值类型: true和false

基本类型

类型描述
float单精度浮点类型
int整数型
bool布尔型, true、false

类型转换

既然是强类型语言,那么类型转换就不能简单的用再次赋值来了,得用内置函数

转换函数描述
转换为整数型int(number)小数点和后面的数截掉; true转换成1
转换为浮点数float(number)float(8) => 8.0; float(true) => 1.0
转换为布尔值bool(number)bool(1.0) => true

矢量和矩阵

  • 矢量是一组有序的实数,可以表示一个点、向量、颜色等。
  • 矩阵是一个二维数组,可以用于表示变换矩阵、投影矩阵、纹理矩阵等。

数据类型

类别数据类型描述
矢量(/i/b)vec(2/3/4)具有(2/3/4)个(浮点数/整数型/布尔值)元素的矢量
矩阵mat2、mat3、 mat42x2、3x3、4x4的浮点数元素的矩阵

矢量

vec2 v2 = vec2(1.0, 2.0);
vec4 v4 = vec4(1.0);

矩阵

WebGL中,矩阵中是以列主序排列的

mat4 m4 = mat4(
1, 2, 3, 4,
5, 6, 7, 8,
1, 2, 3, 4,
5, 6, 7, 8,
);

那么m4就是 m4=1515 2626 3737 4848 m4= \begin{matrix} 1 & 5 & 1 & 5 \\\ 2 & 6 & 2 & 6 \\\ 3 & 7 & 3 & 7 \\\ 4 & 8 & 4 & 8 \\\ \end{matrix}

那么m4[0] = ? 由于m4是GLSL ES语言中的以列主序的矩阵,那么就是第一列的数据[1, 2, 3, 4]

访问元素

类别描述
x, y, z, w用来获取顶点坐标分量
r, g, b, a用来获取颜色分量
s, t, p, q用来获取纹理坐标分量
vec3 v3 = vec3(1.0, 2.0, 3.0);
float f;
f = v3.x;

vec2 v2;
v2 = v3.yz;  // (2.0, 3.0)
v2 = v3.xx;  // (1.0, 1.0)

这里从同一个集合中抽取多个分量,就可以获取某个分量的值,并进行赋值。

取样器

在 WebGL 中,取样器使用 sampler2D 类型表示,它可以被声明为一个 uniform 变量,并且可以在着色器中使用。

precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D u_texture;

void main() {
  gl_FragColor = texture2D(u_texture, v_texCoord);
}

首先在顶点着色器中声明了一个 varying 变量 v_texCoord,用于在顶点着色器和片元着色器之间传递纹理坐标信息。然后在片元着色器中声明了一个 uniform 变量 u_texture,它是一个取样器类型的变量,用于访问纹理。最后,在片元着色器中使用 texture2D() 函数对纹理进行采样,并将采样结果赋值给 gl_FragColor,用于输出颜色。

存储限定字

存储限定字(Storage Qualifier)是用于指定变量存储方式的关键字。存储限定字可以用于在内存中指定变量的存储位置、生命周期和可访问性等信息。

const

表示该变量的值不能被改变

Attribute

attribute变量只能出现在顶点着色器中,并且只能被声明为全局变量,被用来表示逐顶点的信息

uniform

uniform变量可以用在顶点着色器和片元着色器中,并且必须是全局变量。uniform变量是只读的,如果顶点着色器和片元着色器中声明了同名的uniform变量,那么它就会被两种着色器共享。

varying

varying变量必须是全局变量,它的作用是从顶点着色器向片元着色器中传输数据。

in

用于声明片元着色器的输入变量

out

用于声明片元着色器的输出变量

精度限定字

精度限定字,目的是帮助着色器程序提高运行效率,减少内存的开支。

精度限定字描述Floatint
highp高精度(-2^62, 2^62 )(-2^16, 2^16 )
mediump中精度(-2^14, 2^14 )(-2^10, 2^10 )
lowp低精度(-2, 2)(-2^8, 2^8 )

小结

  1. 数据类型:GLSL ES 支持的基本数据类型包括 float、int、bool、vec2、vec3、vec4、mat2、mat3、mat4 等。与 GLSL 不同的是,GLSL ES 中没有双精度浮点数类型 double。
  2. 着色器类型:GLSL ES 支持的着色器类型包括顶点着色器、片元着色器、几何着色器和计算着色器。与 GLSL 不同的是,GLSL ES 中不支持外壳着色器和细分着色器。
  3. 内置变量和函数:GLSL ES 中内置了一些变量和函数,例如 gl_Position、gl_FragColor、texture2D 等。与 GLSL 不同的是,GLSL ES 中的内置变量和函数有所不同,且数量较少。
  4. 存储限定字:GLSL ES 中的存储限定字包括 const、attribute、uniform、varying、in、out 等,用于指定变量的存储方式和生命周期等信息。
  5. 精度修饰符:GLSL ES 中的精度修饰符包括 highp、mediump 和 lowp,用于指定浮点数的精度。与 GLSL 不同的是,GLSL ES 中的默认精度为 mediump。
  6. 预处理指令:GLSL ES 中支持的预处理指令包括 #define、#ifdef、#ifndef、#else、#endif 等,用于在编译前进行宏替换和条件编译等操作。
  7. 控制流语句:GLSL ES 中支持的控制流语句包括 if、else、while、for、do-while 等,用于实现程序的逻辑控制和循环操作。
  8. 内置变量和函数:GLSL ES 中内置了一些变量和函数,例如 gl_Position、gl_FragColor、texture2D 等。与 GLSL 不同的是,GLSL ES 中的内置变量和函数有所不同,且数量较少。