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. 校内测试:T1秋末的落叶(命题人gxl)官方题解

    秋末的落叶 题解 传送门:https://www.luogu.com.cn/problem/U121886 Part 1:疏通题意 首先,我们从题意和样例解释中很容易提取到以下信息: \(1.\)本题 ...

  2. N叉树的前后序遍历和最大深度

    package NTree; import java.util.ArrayList; import java.util.List; /** * N叉树的前后序遍历和最大深度 */ public cla ...

  3. PC,移动端H5实现实现小球加入购物车效果

    HTML部分: <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" ...

  4. Docker入门教程-Linux环境安装Nginx及入门使用

    介绍 Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服 ...

  5. keepalived的工作原理解析以及安装使用

    一.keepalived keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防止单点故障. keepalived官网http://www.keepali ...

  6. Cinder Volume 服务启动流程分析和周期性任务分析

    1.cinder-volume服务的程序入口 #!/usr/bin/python2 # PBR Generated from u'console_scripts' import sys from ci ...

  7. springboot整合druid监控配置

    方式一:直接引入druid 1.maven坐标 <dependency> <groupId>com.alibaba</groupId> <artifactId ...

  8. Reinforcement Learning Using a Continuous Time Actor-Critic Framework with Spiking Neurons

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Abstract 动物会重复奖励的行为,但基于奖励的学习的生理基础仅得到了部分阐明.一方面,实验证据表明神经调节剂多巴胺携带有关奖励的信息 ...

  9. SpringSecurity权限管理系统实战—九、数据权限的配置

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  10. vue混入mixins时注意的问题

    mixin.js - 方式一:导出对象 const mixin = { mounted () { console.log('fffffffffffff') }, methods: { } } expo ...