二维矩阵变换:挪动的其实是坐标纸
2D Matrix Transforms in Shaders
形状挪不动,就挪坐标纸
上一课的形状都是用一条式子画在某个坐标空间里的:「离原点多远」「横坐标是不是大于 0.1」。想把形状挪到别处,没办法把它「拿起来」,因为根本不存在一个可以拿的东西。
能动的只有坐标系。**把整张坐标纸挪一下,画在纸上的形状就跟着走了。**这一课的所有技巧都是这句话的变体。
平移:给坐标加减一个向量
给每个像素的坐标减去一个向量 t,得到新坐标 q = p - t,再在 q 空间里照常画形状:
注意方向:坐标减去 t,形状往 t 的方向走;坐标加上 t,形状反而往反方向走。这和 3D 距离场里的写法一致:先对位置做逆变换,再代进形状的式子。
也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。
旋转:用 mat2 转动坐标系
旋转要用到矩阵。GLSL 原生支持 mat2、mat3、mat4 三种方阵,可以直接用 * 和向量、矩阵相乘;另外还有一个逐元素相乘的 matrixCompMult。
二维旋转矩阵只需要 cos 和 sin:
mat2 rotate2d(float a) {
return mat2(cos(a), -sin(a),
sin(a), cos(a));
}
绕哪一点转?
旋转矩阵总是绕原点转。如果坐标原点在画布左下角,而形状画在中间,直接乘上旋转矩阵,形状就会绕着左下角甩出画面。
正确的做法分三步:先把中心挪到原点,旋转,再挪回去。
写成代码就是一行:
vec2 q = rotate2d(angle) * (st - center) + center;
下面的例子把原点留在了左下角。拖动「支点」滑块,比较两种转法:
也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。
缩放,以及乘法的顺序
缩放矩阵更简单,只在对角线上放两个缩放系数:
mat2 scale2d(vec2 s) {
return mat2(s.x, 0.0,
0.0, s.y);
}
和旋转一样,想绕中心缩放,也要先移到原点再移回来。
旋转和缩放放在一起时,乘的顺序很要紧。矩阵乘向量时,离向量最近的那个矩阵最先起作用;连乘几个矩阵,顺序就对应着变换一层层叠上去的顺序。左右两种顺序的结果完全不同:
也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。
拼一个假 HUD
会画形状,又会移动、旋转、缩放,就可以开始做构图了。书里的练习是做一个仿 UI 或 HUD(抬头显示)的画面。下面这个例子用了几个圆环:
- 外圈的虚线环慢慢顺时针转;
- 中间三段长弧逆时针转得快一些;
- 内圈的细环随时间一呼一吸,靠的是缩放;
- 中心的准星是两个长条,再用差集挖掉中间。
也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。
矩阵也能变换颜色
矩阵不只用来变换空间。颜色也是向量,同样可以乘矩阵。
YUV 是一种用于照片和视频模拟编码的颜色空间:Y 是亮度,U、V 是两个色度分量。它照顾了人眼的感知特点,用来压缩色度信息占的带宽。RGB 和 YUV 之间的转换,各是一个 3 × 3 矩阵。
下面右半边的画面先转到 YUV,把 U、V 缩放或者在 UV 平面里转一个角度,再转回 RGB:
也可以直接改右边的代码:停手约 0.3 秒会自动重新运行;改坏了点「还原代码」。
在空间里移动点,在颜色空间里移动颜色,用的是同一套线性代数。
在游戏里怎么用
取舍与常见的坑
小结与练习
- 片元着色器里移动形状,靠的是移动坐标系:平移是加减向量,旋转和缩放是乘
mat2。 - 旋转和缩放都绕原点进行,想绕中心就「移到原点 → 变换 → 移回去」。
- 矩阵的乘法顺序会改变结果;变换坐标时,形状看到的是逆变换。
- 颜色也是向量,RGB 和 YUV 之间的转换就是一次矩阵乘法。
练习:把第三课的色轮和这一课结合起来:在画布上排几个色轮,每个转速不同、大小不同,有的自转,有的绕着画布中心公转。
在片元里「移动形状」其实是移动坐标系:平移加向量;旋转与缩放用 mat2 乘到坐标上。绕画布中心变换时,要先把空间挪到原点、变换、再挪回。矩阵乘法顺序有关;同一套矩阵也可拿来做 YUV↔RGB 等颜色空间线性变换。
平移:给 st 加向量
形状画在 st 空间里;给 st 加一个偏移向量,整个坐标系(因而形状)平移。可用 u_time 与塑形函数模拟波浪、钟摆、弹跳、加减速等真实运动质感。
旋转:mat2 绕原点
GLSL 原生 mat2/mat3/mat4,支持 * 与 matrixCompMult。二维旋转矩阵:
mat2 rotate2d(float _angle){
return mat2(cos(_angle), -sin(_angle),
sin(_angle), cos(_angle));
}
形状若画在中心 vec2(0.5),需:中心→原点 → 旋转 → 再回中心。省略前后平移会看到绕左下(或原点)转,而非绕图形中心。
缩放
mat2 scale(vec2 _scale){
return mat2(_scale.x, 0.0,
0.0, _scale.y);
}
同样常需先移到原点再缩放。旋转与缩放组合时乘法顺序重要:先乘矩阵再乘向量;多矩阵连乘的顺序对应变换堆叠次序。
综合练习:用平移/旋转/缩放拼 HUD/UI 风构图。
矩阵用于颜色:YUV
YUV 按人类感知压缩色度带宽。把颜色当向量与矩阵相乘,可在 RGB↔YUV 间「搬动」分量——与空间变换同一套线性代数直觉。
与本库变换页的分工
- 基本仿射变换:三维/游戏数学中的仿射、齐次坐标约定等。
- 本页:BoS 片元 2D 课——在归一化
st上做 TRS,为图案平铺与构图服务。
工具箱:LYGIA space 分区。