Skip to content

初识GLSL

GLSL(Graphics Library Shader Language)是一种用于编写着色器程序的编程语言,特别用于在图形处理单元(GPU)上执行图形渲染任务, 有以下几个特点:

  • 类C的语法风格
  • 强类型语言
  • 方便向量和矩阵的计算
  • 内置的数据结构,包括向量类型(vec2、vec3、vec4)、矩阵类型(mat2、mat3、mat4)等

第一个代码片段

当我们在ShaderToy中新建一个Shader会生成下面的代码:

glsl
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // 将坐标归一化到0-1之间
    vec2 uv = fragCoord/iResolution.xy;

    // 时间变化的颜色
    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

    // 输出到屏幕
    fragColor = vec4(col,1.0);
}

上面的代码片段,我们定义了一个mainImage函数,这个函数是我们着色器程序的核心。这个函数接收两个参数fragColorfragCoord。参数前的inout表示函数输入和输出。

我们先来看fragCoord这个输入参数。正如前文提到的,ShaderToy内部帮我们实现了顶点着色器,直接给我们提供了输入。fragCoord是一个vec2类型的值,它代表了画布的XY坐标,左下角的值为(0,0)而右上角是 (iResolution.x, iResolution.y),如下图所示:

坐标

通常我们为了方便处理会把坐标归一化成(0,1)或者是(-1,1)

glsl
vec2 uv = fragCoord/iResolution.xy;

接着是输出参数fragColorfragColor是一个vec4类型的值,代表了片元处理阶段的最终输出颜色,vec4类型包含四个分量(r,g,b,a),分别代表红,绿,蓝还有透明通道(alpha),和CSS颜色常用的Hex Color不同,每个分量的取值范围通常是从01,其中0表示最小值(没有颜色或完全透明),1表示最大值(最大亮度或完全不透明)。

glsl
//  vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
vec3 col = vec3(0.);

点击编辑器左下角的编辑按钮或者用快捷键 Alt+CenterOption+Enter, 就可以看到画布变成黑色了。

GLSL的语法

正如上面提到的,GLSL采用了类似于C语言的语法风格,因此我们不会过多介绍相似的部分。现在让我们重点关注GLSL为我们处理矩阵和矢量提供的语法。

GLSL矢量数据提供了多种分量选择器,这里以vec4为例, 其余vec2vec3同理:

  • v.xv.s 以及 v.rv0 表达的是同一个分量
  • v.yv.t 以及 v.gv1 表达的是同一个分量
  • v.zv.p 以及 v.bv2 表达的是同一个分量
  • v.wv.q 以及 v.av3 表达的是同一个分量

另外GLSL还支持Swizzle,它是一种用于重新排列向量分量的操作。比方说:

glsl
v.yyyy
// 等价于 vec4(v.y, v.y, v.y, v.y)

v.bgra
// 等价于 vec4(v.b, v.g, v.r, v.a)

在我们第一个代码片段中也有用到,当构造一个矢量或矩阵时可以一次提供多个分量,例如:

glsl
vec3 color = vec3(0., 0., 0.);

vec4(col,1.0)
// 等价于 vec4(col.r, col.g, col.b, 1)

vec4(0.)
// 等价于 vec4(0., 0., 0., 0.)

此外,在执行矢量和矩阵运算时,GLSL的语法也相当简洁,例如常量和矢量的乘法。

glsl
vec2 a = vec2(1., 1.);
vec2 b = a * 2.0;
// b 现在是 vec2(2., 2.);
vec2 c = a - 1.
// c 现在是 vec2(0., 0.);
// 加减乘除同理

它同样可以做矩阵乘法以及矢量和矩阵的乘法

glsl
mat4 a = mat4(1.0);
mat4 b = mat4(2.0);
mat4 c = a * b; // mat4(8.0);

vec4 v = vec4(1., 0., 1., 0.)
vec4 y = c * v; // vec4(16.);

更多详细的GLSL语法可以去这里查看GLSL 规范

MGis 地理三维库