0x00 一些废话

如果要深入学习 CG (Computer Graphics,计算机图形学),必然要学习相关的数学知识。CG 涉及到多个不同的领域,根据所研究领域的不同,也会涉及到不同的数学分支。但其中一定少不了线性代数的身影。凡涉及空间中的几何表示与操作,都离不开线性代数的主要研究对象:矩阵。



上图出自电影:The Matrix

以顶点着色器为例,顶点着色器如何完成坐标变换的工作?如果知道矩阵的知识,就会有这样的意识:坐标变换用矩阵来计算是最合适不过的。我们可以利用矩阵简洁地描述几何体的变换,例如缩放、旋转和平移。除此之外,还可以借助矩阵将点或向量的坐标在不同的标架之间进行转换。即,坐标变换。

本文不谈论顶点着色器中坐标变换的具体细节,也不谈论有关矩阵的过多细节,是以快速回顾并熟悉矩阵的仿射变换为目的。

0x01 矩阵乘法

一个规模为 m x n 的矩阵 (matrix) M,是由 m 行 n 列实数所构成的矩形阵列。对于参与矩阵乘法的两个矩阵 A 和 B,如果 A 的规模为 m x n,则 B 的规模须为 n x p。即,A 的行向量的维数与 B 的列向量的维数要一致。两者乘积 AB 的结果是一个规模为 m x p 的矩阵 C。C 中第 i 行、第 j 列的元素,由矩阵 A 的第 i 个行向量与矩阵 B 的第 j 个列向量的点积求得。

例如,

\({\begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{bmatrix}}{\begin{bmatrix} a & b \\ c & d \end{bmatrix}}={\begin{bmatrix} A & B \\ C & D \\ E & F \end{bmatrix}}\)

上式等号右边的矩阵,其中的 B 位于该矩阵的第 1 行、第 2 列。所以,应由乘式左边向量的第 1 个行向量:\({\begin{pmatrix} 1 & 2 \end{pmatrix}}\),与乘式右边向量的第 2 个列向量:\({\begin{pmatrix} b & d \end{pmatrix}}\),两者的点积所得。即,\(B = 1 \times b + 2 \times d\)。

需要注意的是,矩阵乘法不满足交换律。因为,A 和 B 交换后,B 的行向量的维数 p 与 A 的列向量的维数 m 并不能保证一致。

0x02 仿射变换

仿射变换就是线性变换加上平移。

什么是线性变换?线性变换需要满足两点:一是,直线在变换后仍然保持为直线,不能有所弯曲;二是,原点必须保持固定。线性变换包括:缩放、翻转、错切、旋转。下面是这几个操作的变换矩阵。这里假设了所有操作都是在二维空间完成的上,变换前的点记为 \((x, y)\),变换后的点记为 \((x^{'}, y^{'})\)。

缩放:\({\begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}}={\begin{bmatrix} s & 0 \\ 0 & s \end{bmatrix}}{\begin{bmatrix} x \\ y \end{bmatrix}}\)

翻转:缩放的一种,当缩放值为负就可以达到翻转的效果,

错切:\({\begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}}={\begin{bmatrix} 1 & a \\ 0 & 1 \end{bmatrix}}{\begin{bmatrix} x \\ y \end{bmatrix}}\)

旋转:\({\begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}}={\begin{bmatrix} \cos{\Theta} & -\sin{\Theta} \\ \sin{\Theta} & \cos{\Theta} \end{bmatrix}}{\begin{bmatrix} x \\ y \end{bmatrix}}\)

为什么平移不属于线性变换呢?原因是平移操作后,原点的位置会发生了改变。这种情况下,平移也无法写成矩阵乘法的形式。

加法:\({\begin{bmatrix} x^{'} \\ y^{'} \end{bmatrix}}={\begin{bmatrix} x \\ y \end{bmatrix}}+{\begin{bmatrix} t_x \\ t_y \end{bmatrix}}\)

线性变换总是将原点映射到原点,因此无法用来呈现平移。不过,我们可以在原空间维度 n 的基础上增加 1 个维度。这样,原空间的平移操作,可以借由更高维度空间中的切变操作来完成。

平移:\({\begin{bmatrix} x^{'} \\ y^{'} \\ w^{'} \end{bmatrix}}={\begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{bmatrix}}{\begin{bmatrix} x + t_x \\ y + t_y \\ 1 \end{bmatrix}}\)

根据矩阵乘法不满足交换律的性质,我们还可以推断出一个信息:变换有时序。先平移再旋转和先旋转再平移,得到的结果是不同的。

0x03 变换练习

#ifdef GL_ES
precision mediump float;
#endif uniform vec2 u_resolution;
uniform float u_time; // 缩放
mat3 scale(vec2 scl) {
return mat3(scl.x, 0.0, 0.0,
0.0, scl.y, 0.0,
0.0, 0.0, 1.0);
} // 错切
mat3 shear(vec2 shr) {
return mat3(1.0, shr.y, 0.0,
shr.x, 1.0, 0.0,
0.0, 0.0, 1.0);
} // 旋转
mat3 rotate(float angle) {
return mat3(cos(angle), -sin(angle), 0.0,
sin(angle), cos(angle), 0.0,
0.0, 0.0, 1.0);
} // 平移
mat3 translate(vec2 pos) {
return mat3(1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
pos.x, pos.y, 1.0);
} void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy; vec3 color = vec3(0.0);
vec3 p3 = vec3(st, 1.0); mat3 t = scale(vec2(2.0));
t *= translate(vec2(0.25, 0.25));
t *= shear(vec2(-0.5, 0.0));
t *= rotate(u_time);
t *= translate(vec2(-0.5, -0.5));
st = (t * p3).xy; // 画个正方形
vec2 bl = step(vec2(0.0), st);
vec2 tr = step(vec2(0.0), 1.0 - st);
float p = bl.x * bl.y * tr.x * tr.y;
color = vec3(p * st, 0.4); gl_FragColor = vec4(color, 1.0);
}

效果:

0x04 一些说明

需要注意的是 OpenGL 的矩阵以列为主。即:

mat2(a, b, //第一列
c, d) //第二列

另外,在上面的变换练习中,是对整个坐标系进行变换的,而非绘制的图形本身。

参考资料:

Book of Shaders 02 - 矩阵:二维仿射变换练习的更多相关文章

  1. Halcon二维仿射变换实例探究

    二维仿射变换,顾名思义就是在二维平面内,对对象进行平移.旋转.缩放等变换的行为(当然还有其他的变换,这里仅论述这三种最常见的). Halcon中进行仿射变换的常见步骤如下: ① 通过hom_mat2d ...

  2. BZOJ 1567: [JSOI2008]Blue Mary的战役地图 矩阵二维hash

    1567: [JSOI2008]Blue Mary的战役地图 Description Blue Mary最近迷上了玩Starcraft(星际争霸) 的RPG游戏.她正在设法寻找更多的战役地图以进一步提 ...

  3. 用Python实现根据角4点进行矩阵二维插值并画出伪彩色图

    哈哈,题目取得这么绕,其实就是自己写了一个很渣的类似图像放大的算法.已知矩阵四周的4点,扩展成更大的矩阵,中间的元素值均匀插入,例如: 矩阵: 1  2 3  4 扩展成3x3的: 1  1.5  2 ...

  4. AcWing - 156 矩阵(二维哈希)

    题目链接:矩阵 题意:给定一个$m$行$n$列的$01$矩阵$($只包含数字$0$或$1$的矩阵$)$,再执行$q$次询问,每次询问给出一个$a$行$b$列的$01$矩阵,求该矩阵是否在原矩阵中出现过 ...

  5. JS-DOM ~ 02. 隐藏二维码、锁定、获取输入框焦点、for循环为文本赋值、筛选条件、全选和反选、属性的方法操作、节点的层次结构、nodeType

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 剑指offer-顺时针打印矩阵-二维数组

    输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1     2  3    4 5     6  7    8 9   10 11 12 13 14 15 16 ...

  7. 【opencv】 solvepnp 和 solvepnpRansac 求解 【空间三维坐标系 到 图像二维坐标系】的 三维旋转R 和 三维平移 T 【opencv2使用solvepnp求解rt不准的问题】

    参考: pnp问题 与 solvepnp函数:https://www.jianshu.com/p/b97406d8833c 对图片进行二维仿射变换cv2.warpAffine() or 对图片进行二维 ...

  8. (转)QRCODE二维码介绍及常用控件推荐

    什么是QR Code码? QR Code码是由日本Denso公司于1994年9月研制的一种矩阵二维码符号,它具有一维条码及其它二维条码所具有的信息容量大.可靠性高.可表示汉字及图象多种文字信息.保密防 ...

  9. Java 二维码生成工具类

    /** * 二维码 工具 * * @author Rubekid * */ public class QRcodeUtils { /** * 默认version */ public static fi ...

随机推荐

  1. 【luogu4137】 Rmq Problem / mex - 莫队

    题目描述 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 思路 莫队水过去了 233 #include <bits/stdc++.h> ...

  2. 痞子衡嵌入式:利用i.MXRT1060,1010上新增的FlexSPI地址重映射(Remap)功能可安全OTA

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT部分型号上新增的FlexSPI Remap功能. OTA升级设计几乎是每个量产客户都绕不开的话题,产品发布后免不了要做固件( ...

  3. Disruptor极速队列

    参考:http://www.cnblogs.com/haiq/p/4112689.html Disruptor 是线程内通信框架,用于线程里共享数据.LMAX 创建Disruptor作为可靠消息架构的 ...

  4. python爬虫抖音 个人资料 仅供学习参考 切勿用于商业

    本文仅供学习参考 切勿用于商业 本次爬取使用fiddler+模拟器(下载抖音APP)+pycharm 1. 下载最新版本的fiddler(自行百度下载),以及相关配置 1.1.依次点击,菜单栏-Too ...

  5. Fiddler+模拟器+APP抓包HTTPS 为什么有时候抓不到?

    抓包的原理是什么? 代理 客户端请求 -> 经过代理 -> 到达服务端 服务端返回 -> 经过代理 -> 到达客户端 任何Https的App都能抓到包么? Android7.0 ...

  6. DataNode(面试开发重点)

    1 DataNode工作机制 DataNode工作机制,如图所示. 1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和 ...

  7. you-get 下载B站上的视频

    安装you-get pip install you-get 安装好后,我们可以查看一下you-get的参数 you-get -h 视频下载 单个视频下载 CMD下载 you-get -o /data/ ...

  8. 技术揭秘:华为云DLI背后的核心计算引擎

    摘要:介绍隐藏在华为云数据湖探索服务背后的核心计算引擎Spark,玩转DLI,,轻松完成大数据的分析处理. 本文主要给大家介绍隐藏在华为云数据湖探索服务(后文简称DLI)背后的核心计算引擎——Spar ...

  9. Linux 部署java web 项目,验证码图片不显示文字问题

    系统上线后,在获取验证码接口时,获取的验证码图片上没有对应的验证码数字,经过验证后,是由于Linux缺少字体造成的. 正常我们也可以将window的字体直接上传到linux服务器上,window的字体 ...

  10. C++入门记-大纲

    缘来 由于某个不可告人的目标以及想趁着还有精力的年龄,开始了C++学习之路.C++ 诞生很多年了,但依然具有强大的生命力. 我们来看下2020年8月TIOBE 8 月编程语言排行榜. 可以看到C以及C ...