ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

The Book of Shaders 实战精读(08):GLSL 二维矩阵变换——平移、旋转与缩放

The Book of Shaders 实战精读(08):GLSL 二维矩阵变换——平移、旋转与缩放 【免费下载链接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.项目地址https://gitcode.com/gh_mirrors/th/thebookofshaders点击查看免费下载导读本章是《The Book of Shaders》仓库根目录的第八课主题为2D Matrices二维矩阵。在上一章用坐标系统绘制出形状之后本章解决如何让形状动起来的问题通过矩阵这一强大的向量操作工具自由地对图形进行平移Translate、旋转Rotate与缩放Scale。由于该技术可以等量应用于任何用向量表达的事物学完本章后你不仅能操控几何图形还能用同样的手段处理颜色空间如 YUV为后续的程序化图案创作打下扎实基础。本章核心思想矩阵是操作向量的万能工具本章开篇08/SUMMARY-pt.md给出了全章提纲挈领的论断矩阵是操作向量的强大工具。精通矩阵用法后你可以自由地平移、缩放和旋转形状。由于这套技术可以等量地应用于任何用向量表达的事物本书后面还会看到矩阵更多进阶用法。矩阵乍看之下很复杂但一旦掌握概念就会发现它非常实用。让我们在这里通过一些简单示例练习并掌握基础。这段概括蕴含三个要点矩阵的本质是向量变换器在片元着色器中坐标、颜色、法线都是向量矩阵乘法是改变向量取值最规范的手段操作对象是坐标系而非形状本身Shader 里没有选中某个物体的概念所有变换都是对每个片元的坐标空间进行整体操作学的是可迁移的方法论同样的mat2/mat3/mat4技巧后面章节会在噪声、纹理、光照等场景反复出现。前置认知变换形状 变换坐标系在上一章07 形状中我们学会了用smoothstep在归一化坐标st即gl_FragCoord.xy / u_resolution.xy取值范围0.0 ~ 1.0上裁出矩形、圆形等形状。移动这些形状的诀窍不是修改形状的定义而是移动坐标系统本身——只需向保存每个片元位置的变量st加上一个向量整个空间坐标系就会随之移动。这种动空间而不是动物体的思想贯穿本章全部三个操作平移是加向量旋转和缩放则是左乘一个矩阵。平移Translate给 st 加一个向量平移是最直观的变换。参考仓库中的 cross-translate.frag作者 patriciogv2015// Author patriciogv ( patriciogonzalezvivo.com ) - 2015 #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; uniform float u_time; float box(in vec2 _st, in vec2 _size){ _size vec2(0.5) - _size*0.5; vec2 uv smoothstep(_size, _sizevec2(0.001), _st); uv * smoothstep(_size, _sizevec2(0.001), vec2(1.0)-_st); return uv.x*uv.y; } float cross(in vec2 _st, float _size){ return box(_st, vec2(_size,_size/4.)) box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st gl_FragCoord.xy/u_resolution.xy; vec3 color vec3(0.0); // To move the cross we move the space vec2 translate vec2(cos(u_time),sin(u_time)); st translate*0.35; // Show the coordinates of the space on the background // color vec3(st.x,st.y,0.0); // Add the shape on the foreground color vec3(cross(st,0.25)); gl_FragColor vec4(color,1.0); }代码要点box()与cross()是上一章的形状函数cross由两个矩形拼成十字关键一行st translate * 0.35;其中translate vec2(cos(u_time), sin(u_time))是一个绕单位圆运动的向量乘以0.35把运动幅度限制在画布中央附近练习一取消第 35 行color vec3(st.x,st.y,0.0);的注释即可看到空间本身的坐标颜色随十字一起移动直观验证移动的是空间。本章给出的进阶练习很有价值结合u_time与第 5 章的塑造函数shaping functions参见 05 章让十字按你感兴趣的运动品质移动——例如海浪的往复、单摆的摆动、弹跳的球、加速的汽车或刹车的自行车。建议先从真实世界录制一段参考运动再反推数学表达这是训练运动感的经典方法。旋转Rotate2D 旋转矩阵旋转同样需要移动整个空间系统但手段升级为矩阵矩阵是按行列组织的一组数字向量按照精确的规则与矩阵相乘从而以特定方式修改向量取值。GLSL 中的矩阵类型GLSL 原生支持二、三、四维矩阵mat22×2、mat33×3、mat44×4——浮点矩阵类型支持矩阵乘法运算符*内置矩阵专用函数matrixCompMult()对两个矩阵做逐分量相乘。仓库 glossary/mat2/README.md 给出了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初始化即参数按列填写同时支持分量访问与按列访问mat2 aMat2; aMat2[1][1] 1.0; float aFloat aMat2[1][1]; aMat2[0] vec2(1.0); vec2 aVec2 aMat2[0];mat3、mat4的声明规则相同见 glossary/mat3/README.mdmatrixCompMult()则逐分量相乘result[i][j] x[i][j] * y[i][j]见 glossary/matrixCompMult/README.md。构造 2D 旋转矩阵基于矩阵行为可以构造出特定功能的矩阵。二维旋转矩阵的标准公式如下mat2 rotate2d(float _angle){ return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)); }按照列主序展开这个矩阵的第一列是(cos, sin)第二列是(-sin, cos)对应二维向量绕原点vec2(0.0)逆时针旋转_angle弧度的标准公式。关键套路移到原点 → 旋转 → 移回去但直接套用上面的公式并不满足我们的需求本章的十字形状画在画布中心即位置vec2(0.5)附近而rotate2d绕原点vec2(0.0)旋转。因此旋转空间之前必须先把形状从center移到vec2(0.0)坐标旋转空间最后再移回原位。对应代码见 cross-rotate.frag// Author patriciogv ( patriciogonzalezvivo.com ) - 2015 #ifdef GL_ES precision mediump float; #endif #define PI 3.14159265359 uniform vec2 u_resolution; uniform float u_time; mat2 rotate2d(float _angle){ return mat2(cos(_angle),-sin(_angle), sin(_angle),cos(_angle)); } float box(in vec2 _st, in vec2 _size){ _size vec2(0.5) - _size*0.5; vec2 uv smoothstep(_size, _sizevec2(0.001), _st); uv * smoothstep(_size, _sizevec2(0.001), vec2(1.0)-_st); return uv.x*uv.y; } float cross(in vec2 _st, float _size){ return box(_st, vec2(_size,_size/4.)) box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st gl_FragCoord.xy/u_resolution.xy; vec3 color vec3(0.0); // move space from the center to the vec2(0.0) st - vec2(0.5); // rotate the space st rotate2d( sin(u_time)*PI ) * st; // move it back to the original place st vec2(0.5); // Show the coordinates of the space on the background // color vec3(st.x,st.y,0.0); // Add the shape on the foreground color vec3(cross(st,0.4)); gl_FragColor vec4(color,1.0); }代码中的三段式注释直接点明了套路第 38 行st - vec2(0.5);—— 把空间从中心移到原点第 40 行st rotate2d( sin(u_time)*PI ) * st;—— 用随时间变化的角度sin(u_time)*PI范围-π ~ π做往复摆动旋转空间第 42 行st vec2(0.5);—— 旋转完成后移回原位。本章给出的旋转练习同样值得亲手验证取消第 45 行背景坐标代码的注释观察空间坐标如何随旋转改变注释掉第 37、39 行的平移即旋转前后的两次位移观察后果——会发现十字绕着左下角原点旋转而不是绕画布中心从而深刻理解原点居中的必要性用旋转改进你在平移练习中模拟的动画例如让摆动中的物体同时自转。缩放Scale2D 缩放矩阵如果你用过 3D 建模软件或 Processing 的pushMatrix/popMatrix就知道矩阵同样可以用来改变物体大小。仿照旋转矩阵的推导思路二维缩放矩阵为mat2 scale(vec2 _scale){ return mat2(_scale.x,0.0, 0.0,_scale.y); }对角线上的两个因子分别控制 x、y 方向的缩放倍数大于 1 放大小于 1 缩小负值可做镜像。完整示例见 cross-scale.frag// Author patriciogv ( patriciogonzalezvivo.com ) - 2015 #ifdef GL_ES precision mediump float; #endif #define PI 3.14159265359 uniform vec2 u_resolution; uniform float u_time; mat2 scale(vec2 _scale){ return mat2(_scale.x,0.0, 0.0,_scale.y); } float box(in vec2 _st, in vec2 _size){ _size vec2(0.5) - _size*0.5; vec2 uv smoothstep(_size, _sizevec2(0.001), _st); uv * smoothstep(_size, _sizevec2(0.001), vec2(1.0)-_st); return uv.x*uv.y; } float cross(in vec2 _st, float _size){ return box(_st, vec2(_size,_size/4.)) box(_st, vec2(_size/4.,_size)); } void main(){ vec2 st gl_FragCoord.xy/u_resolution.xy; vec3 color vec3(0.0); st - vec2(0.5); st scale( vec2(sin(u_time)1.0) ) * st; st vec2(0.5); // Show the coordinates of the space on the background // color vec3(st.x,st.y,0.0); // Add the shape on the foreground color vec3(cross(st,0.2)); gl_FragColor vec4(color,1.0); }注意第 38 行scale( vec2(sin(u_time)1.0) )sin(u_time)范围-1.0 ~ 1.0加1.0后缩放因子范围是0.0 ~ 2.0十字在缩到看不见与放大两倍之间脉动。同样沿用了移到原点 → 缩放 → 移回的三段式。本章的缩放练习给出了几个极具工程价值的训练取消第 42 行注释查看空间坐标被缩放的效果注释第 37、39 行的平移观察缩放中心从画布中心漂移到原点尝试把旋转矩阵与缩放矩阵组合——牢记矩阵乘法顺序敏感先构造矩阵相乘再用结果矩阵乘向量即M_combined * st其中M_combined rotate2d(...) * scale(...)综合运用既然已经会画形状又会移动、旋转、缩放就可以做真正的合成了——设计并构造一个假的 UI 或 HUD抬头显示界面参考 ShaderToy 社区中 Ndel 的 HUD 类示例作为灵感。矩阵不止用于几何YUV 颜色空间的矩阵变换本章最精彩的收尾是把矩阵从几何空间迁移到颜色空间。YUV是用于照片和视频模拟编码的一种颜色空间它考虑到人类视觉感知的特性以降低色度chrominance分量的带宽。GLSL 中可以直接用矩阵把颜色从一个空间变换到另一个空间见 yuv.frag// Author patriciogv - 2015 // http://patriciogonzalezvivo.com #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; uniform float u_time; // YUV to RGB matrix mat3 yuv2rgb mat3(1.0, 0.0, 1.13983, 1.0, -0.39465, -0.58060, 1.0, 2.03211, 0.0); // RGB to YUV matrix mat3 rgb2yuv mat3(0.2126, 0.7152, 0.0722, -0.09991, -0.33609, 0.43600, 0.615, -0.5586, -0.05639); void main(){ vec2 st gl_FragCoord.xy/u_resolution; vec3 color vec3(0.0); // UV values goes from -1 to 1 // So we need to remap st (0.0 to 1.0) st - 0.5; // becomes -0.5 to 0.5 st * 2.0; // becomes -1.0 to 1.0 // we pass st as the y z values of // a three dimensional vector to be // properly multiply by a 3x3 matrix color yuv2rgb * vec3(0.5, st.x, st.y); gl_FragColor vec4(color,1.0); }这段代码的示范意义在于把颜色当作向量与矩阵相乘从而搬动颜色分量的取值rgb2yuvRGB → YUV 的 3×3 转换矩阵第一行是亮度系数0.2126、0.7152、0.0722即 Rec.601 标准亮度权重yuv2rgb其逆变换矩阵由于 UV 分量范围是-1 ~ 1而st范围是0 ~ 1需要先st - 0.5再st * 2.0完成重映射最终以vec3(0.5, st.x, st.y)作为 YUV 输入Y 固定为 0.5 中灰左乘yuv2rgb得到 RGB 彩色输出画布上会呈现与坐标位置对应的色相渐变。仓库源码级深化从 2D 到 3D/4D 的矩阵工具箱本章仓库内还有两份源码可以帮你把视野从 2D 拓展到更高维度章节头部的动态演示 matrix.frag这是章节页面顶部 canvas 播放的矩阵雨效果——用floor(st*rows)切出 80 行网格借助random()与u_time让字符按行坠落本质上是把空间重复切分 随机函数的预演为第 9 章程序化图案埋下伏笔进阶矩阵库 matrices.frag完整给出了rotate2D以及三维、四维版本——rotateX3D/rotateY3D/rotateZ3D、对应的mat4四维版本以及scale4D、translate4D。例如绕 X 轴旋转的 3×3 矩阵mat3 rotateX3D(float phi){ return mat3( vec3(1.,0.,0.), vec3(0.,cos(phi),-sin(phi)), vec3(0.,sin(phi),cos(phi))); }这份文件展示了矩阵变换的可组合、可复用特性旋转、缩放、平移都是把单位矩阵相应位置替换为变换参数并且低维公式可以一致地推广到高维这正是后续章节做复杂空间操作如噪声扰动、纹理坐标变换的基础工具。另外值得留意的是 GLSL 的矩阵乘法语义matrixCompMult()与*完全不同——前者逐分量相乘对应数学上的 Hadamard 积后者才是线性代数意义上的矩阵乘法。做几何变换时必须使用*本章所有rotate2d(...) * st、scale(...) * st均是后者。本章小结与下一步本章我们学会了用矩阵变换来平移、旋转、缩放向量平移是给st加向量旋转与缩放是构造mat2并左乘坐标且都遵循移到原点 → 变换 → 移回的通用套路。这些变换对把上一章学到的形状组织成复杂构图至关重要而 YUV 示例则证明了同一套矩阵工具可以跨界作用于颜色空间——凡是向量皆可变换。下一章09 图案将把本章所学全部应用到程序化图案的创作中通过包装与重复空间用并行而非逐对象的方式绘制重复图案。你会发现编码重复与变化是一件令人兴奋的实践。工具箱备注若想深入学习用矩阵操纵空间的实用函数集合可参考 LYGIA 的 space functions 库——一套面向 GLSL 空间操作的细粒度、可复用函数库设计上注重复用、性能与灵活性可轻松集成到任意项目与框架中。赞分享【免费下载链接】thebookofshadersStep-by-step guide through the abstract and complex universe of Fragment Shaders.项目地址https://gitcode.com/gh_mirrors/th/thebookofshaders点击查看免费下载相关推荐The Book of Shaders 精读用 GLSL 二维矩阵变换平移、旋转与缩放坐标空间The Book of Shaders 精读用 GLSL 二维矩阵变换平移、旋转与缩放坐标空间 本篇文章精读开源项目 thebookofshaders httThe Book of Shaders 第 8 章精读用 GLSL 二维矩阵驱动平移、旋转与缩放变换The Book of Shaders 第 8 章精读用 GLSL 二维矩阵驱动平移、旋转与缩放变换 本文基于开源仓库 thebookofshaders 第The Book of Shaders 第 08 章GLSL 二维矩阵变换实战指南 —— 平移、旋转、缩放与 YUV 色彩空间The Book of Shaders 第 08 章GLSL 二维矩阵变换实战指南 —— 平移、旋转、缩放与 YUV 色彩空间 本章 08/README v上一篇AIOpsLab革命性AI运维评估框架 - 一站式解决60云故障场景下一篇OBS Studio 应用LUT调色4步给直播画面加电影感创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表