【免费下载链接】thebookofshaders
Step-by-step guide through the abstract and complex universe of Fragment Shaders.
mat2是 GLSL(OpenGL Shading Language)内置的 2 行 2 列浮点矩阵类型,是片段着色器中实现坐标旋转、缩放等空间变换的基础工具。本文以 The Book of Shaders 项目 glossary 词条 为核心,系统讲解mat2的声明方式、初始化规则、元素与列的访问语法,并结合仓库中 第 08 章 及其 .frag 源码给出可直接运行的旋转、缩放实战代码。读完本文,你将掌握mat2的完整语法,并能在自己的着色器中构造旋转矩阵与缩放矩阵。
mat2是什么
mat2表示一个由浮点数构成的 2×2 矩阵,即 2 行 2 列、共 4 个float元素。它是 GLSL 矩阵家族中最小的成员,同族类型还包括mat3(3×3)与mat4(4×4)。
在 The Book of Shaders 的 glossary 中,mat2被描述为 "2x2 floating point matrix"。与普通变量不同,矩阵可以被当作"作用于向量的一组规则":将向量与矩阵相乘,就能以确定的方式平移、旋转或缩放该向量。这也是 第 08 章 "2D Matrices" 的主题——用mat2变换坐标空间,从而移动、旋转画布上的图形。
声明与初始化:四种写法
mat2可以采用以下方式声明并初始化(以下代码完整来自 glossary/mat2 词条):
mat2 aMat2 = mat2(1.0, 0.0, // 第 1 列 0.0, 1.0); // 第 2 列 mat2 bMat2 = mat2(1.0); mat2 cMat2 = mat2(aVec2, bVec2); mat2 dMat2 = mat2(aVec3, aFloat);关键点在于GLSL 矩阵采用列主序(column-major)构造:构造函数中的参数按"第 1 列 → 第 2 列"的顺序依次填充,注释中标明的"1. column / 2. column"正是这一约定的体现。具体可分为三种初始化方式:
- 逐分量指定:
mat2(1.0, 0.0, 0.0, 1.0)依次给出 4 个元素,前两个属于第 1 列,后两个属于第 2 列;上面aMat2得到的就是单位矩阵。 - 单个标量:
mat2(1.0)只给一个值,该值会被同时赋给主对角线上的元素([0][0]与[1][1]),其余元素为 0,因此bMat2同样等价于单位矩阵。 - 向量与标量组合:
mat2(aVec2, bVec2)表示把两个vec2分别作为第 1 列和第 2 列;mat2(aVec3, aFloat)则混合使用向量与标量——GLSL 允许这种写法,多余的向量分量会被丢弃,不足的部分由后续标量补充。仓库中 mat3 词条 的示例mat3(aVec4, aVec3, bVec4, aFloat)印证了这种混合初始化模式同样适用于更大尺寸的矩阵。
元素与列的访问语法
初始化之后,既可以按"行、列"访问单个元素,也可以按列整体读取或写入一个vec2(代码同样来自 glossary/mat2 词条):
mat2 aMat2; aMat2[1][1] = 1.0; // 写入第 2 行第 2 列 float aFloat = aMat2[1][1]; // 读取单个元素 aMat2[0] = vec2(1.0); // 整列赋值:把第 1 列整体设为 vec2(1.0) vec2 aVec2 = aMat2[0]; // 按列读取两条规则需要牢记:
- 单个元素:使用
矩阵[列][行]的下标语法,索引从 0 开始,aMat2[1][1]定位到右下角元素。 - 整列访问:
aMat2[0]返回一个vec2,对应第 1 列的两个元素;由于列主序布局,第 0 列恰好就是内存中的前两个浮点数,读取效率很高。
相关类型与函数
mat2经常与同族类型及矩阵专用函数配合使用:
- mat3:3×3 浮点矩阵,用于二维坐标的 3×3 齐次变换或颜色空间转换。
- mat4:4×4 浮点矩阵,支持三维空间中的平移、旋转、缩放。
- matrixCompMult():对两个矩阵做逐分量相乘,
result[i][j] = x[i][j] * y[i][j];它与 GLSL 中*运算符的矩阵乘法(行列点积)语义不同,切勿混淆。
仓库实战:用 mat2 构造旋转与缩放矩阵
仅了解语法还不够,第 08 章 的源码演示了mat2最典型的用途——构造 2D 旋转矩阵。在 08/matrices.frag 中可以看到标准写法:
mat2 rotate2D(float angle){ return mat2(cos(angle),-sin(angle), sin(angle),cos(angle)); }注意构造参数的排列:cos(angle), -sin(angle)构成第 1 列,sin(angle), cos(angle)构成第 2 列——这正是二维旋转矩阵[[cosθ, -sinθ], [sinθ, cosθ]]的列主序填充结果。
由于我们的图形通常绘制在画布中心vec2(0.5)附近,而旋转矩阵是绕原点vec2(0.0)生效的,因此需要遵循"平移 → 旋转 → 平移回去"三步流程。08/cross-rotate.frag 给出了完整实现:
mat2 rotate2d(float _angle){ return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)); } void main(){ vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0); st -= vec2(0.5); // 1. 把空间平移到原点 st = rotate2d( sin(u_time)*PI ) * st; // 2. 用 mat2 旋转坐标空间 st += vec2(0.5); // 3. 平移回原位置 color += vec3(cross(st,0.4)); gl_FragColor = vec4(color,1.0); }图中展示的正是"先平移到原点、旋转、再移回"这一流程:直接用rotate2d的结果去乘st向量(st = rotate2d(...) * st),mat2就完成了对坐标空间的整体旋转,而u_time驱动的sin(u_time)*PI让角度随时间变化,产生往复摆动的动画效果。
同理可构造缩放矩阵。在 08/cross-scale.frag 中:
mat2 scale(vec2 _scale){ return mat2(_scale.x,0.0, 0.0,_scale.y); }该矩阵把_scale.x、_scale.y分别放在主对角线[0][0]与[1][1]上,对角元素控制 x、y 两个方向的缩放比例;调用时同样遵循平移—缩放—平移的次序,例如st = scale(vec2(sin(u_time)+1.0)) * st。
从源码结构看,仓库中大量示例将旋转矩阵封装为"以原点为中心旋转一个vec2"的辅助函数,例如 09/checks.frag 与 09/rotatedtiles.frag 中的rotate2D,它们在内部完成"减 0.5 → 乘以矩阵 → 加 0.5"的完整流程,并在平铺(tile)空间中旋转每个单元格:
vec2 rotate2D (vec2 _st, float _angle) { _st -= 0.5; _st = mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)) * _st; _st += 0.5; return _st; }更多应用场景
mat2的作用远不止图形旋转,仓库中的其他示例展示了它的多样化用途:
- 减少噪声轴向偏差:13/clouds.frag 在分形布朗运动(fBm)的迭代中构造固定角度的旋转矩阵
mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.50)),每轮迭代用_st = rot * _st * 2.0 + shift旋转输入坐标,以削弱噪声采样在 x/y 轴上的方向性偏差。 - CMYK 半调网点:00/cmyk-halftone.frag 中的
rotm()函数返回一个mat2旋转矩阵,为青、品红、黄、黑四个颜色通道分别叠加不同的旋转角(15°、75°、0°、45°),实现经典印刷中的半调网角(halftone screen angle)效果:
mat2 rotm (in float r) { float cr = cos(r); float sr = sin(r); return mat2(cr,-sr, sr,cr); }- 颜色空间变换:虽然 08/yuv.frag 使用的是
mat3,但它展示了矩阵在 GLSL 中的另一类应用——把颜色当作向量,通过矩阵乘法在 RGB 与 YUV 颜色空间之间转换,这也是matrixCompMult()与矩阵乘法容易混淆时最值得对比的示例。
小结
mat2以 4 个浮点数承载二维线性变换:按列主序构造、支持标量/向量混合初始化、可按[列][行]或整列访问。在 The Book of Shaders 中,它是"平移、旋转、缩放"三大空间操作的核心载体,其旋转矩阵mat2(cos(a), -sin(a), sin(a), cos(a))在 第 08 章 及 第 09 章平铺模式 等后续章节中被反复使用。想进一步了解更大尺寸矩阵与矩阵函数,可继续阅读 mat3、mat4 与 matrixCompMult() 词条。
【免费下载链接】thebookofshaders
Step-by-step guide through the abstract and complex universe of Fragment Shaders.
相关推荐
doocs/leetcode 面试题 02.08 环路检测:快慢指针求链表环入口的数学证明与多语言实现
doocs/leetcode 面试题 02.08 环路检测:快慢指针求链表环入口的数学证明与多语言实现 本篇技术指南以 doocs/leetcode 仓库中《程
The Book of Shaders 入门:GLSL 布尔向量 bvec2 的声明、初始化与实战解析
The Book of Shaders 入门:GLSL 布尔向量 bvec2 的声明、初始化与实战解析 本指南基于 The Book of Shaders 仓库
The Book of Shaders 中的 GLSL `tan()` 函数详解:声明、行为与着色器实战
The Book of Shaders 中的 GLSL tan 函数详解:声明、行为与着色器实战 tan 是 GLSL 内置的三角函数之一,用于返回指定角度(弧
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考