CG中的仿射(affine transformation)和法线变换

Note

这是对MIT Foundation of 3D Computer Graphics第3章的翻译,本章讲解了仿射变换的基本概念,变换矩阵的由来以及分解、通用法线变换的推导等内容。本书内容仍在不断的学习中,因此本文内容会不断的改进。若有任何建议,请不吝赐教ninetymiles@icloud.com

注:文章中相关内容归原作者所有,翻译内容仅供学习参考。
另:Github项目CGLearning中拥有相关翻译的完整资料、内容整理、课程项目实现。


已经完成的章节


仿射(并行)(Affine)

3.1 点和帧(Points and Frames)

将点和矢量看作是两种不同的概念是有用的。点表示在几何世界中的某种固定位置,而矢量表示世界中两个点之间的运动。我们会使用两种不同的标记区分点和矢量。矢量\vec{v}会有一个箭头在顶部,而点\tilde{p}会有波浪线在顶部。

如果我们认为矢量表达两点之间的运动,那么矢量操作(加法和标量乘法)就有明确的意义。如果我们把两个矢量加起来,我们在表达两个运动的串接(concatenation)。如果我们用一个标量乘以矢量,我们就在通过某个因子增加或减少运动。零矢量(zero vector)为一个特别矢量,其代表没有运动。

这些操作对于点不会真正产生任何意义。把两个点加起来应该表示什么含义,比如说,哈佛广场加上剑桥肯德尔广场(这里是两个地点名称)是什么?一个点被一个标量相乘又指得什么?什么是北极点的7倍?是否存在一个零点(zero point)和其它点的行为不一样?

存在一种在两个点之间确实有意义的操作:减法。当我们从另一个点减去一个点,我们应该会得到从第二个点到第一个点路径之间的运动,
\tilde{p} - \tilde{q} = \vec{v}

反过来说,如果我们从一个点开始,然后移动一个矢量(位移),我们应该会到达另一个点。
\tilde{q} + \vec{v} = \tilde{p}

对一个点应用线性变换同样有意义。例如我们可以想象一个点围绕某个固定原点的旋转。而且平移点也是有意义的(但是这个概念对于矢量没有任何意义)。要表达平移,我们需要开发仿射变换(或并行变换 affine transformation)的概念。要完成这个任务,我们借助4 \times 4矩阵。这些矩阵不仅对于处理本章的仿射(并行)变换很方便,而且对于描述(随后在第十章会看到的)相机投射变换也是很有帮助。

3.1.1 帧(Frames)

在仿射空间(affine space)中,我们描述任何点\tilde{p}首先从某个原点\tilde{o}开始,然后给其加上一个矢量的线性组合。这些矢量使用坐标c_i和一个矢量基(basis of vectors)来表示。

\tilde{p} = \tilde{o} + \sum_i c_i\vec{b}_i = \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix} = \vec{\mathbf{f}}^t\mathbf{c}
此处1\tilde{o}被定义为\tilde{o}

而下面这行表达
\begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} = \vec{\mathbf{f}}^t
被称为一个仿射帧(affine space);它就像一个基(basis),但是由3个矢量和一个点组成。

为了借助一个帧指定一个点,我们使用拥有4个条目(entries)的4部件坐标矢量(coordinate 4-vector),其中最后一个条目总为1。要借助一个帧表达一个矢量,我们使用一个让0作为第4坐标的坐标矢量(也就是说,它只是基矢量之和)。当我们建模针孔相机的行为时,要表达几何形状(还有4 \times 4矩阵),4部件坐标矢量的使用都会很便利。

3.2 仿射变换和4\times4矩阵(Affine transformations and Four by Four Matrices)

相似于线性变换的情形,我们想要通过在一个4部件坐标矢量和一个帧之间放置一个合适的矩阵的形式,来定义出仿射变换的概念。

让我们将仿射矩阵定义为一个如下形式的4 \times 4矩阵
\begin{bmatrix} a & b & c & d \\ e & f & g & h \\ i & j & k & l \\ 0 & 0 & 0 & 1 \end{bmatrix}

然后我们对一个点\tilde{p} = \vec{\mathbf{f}}^t\mathbf{c}应用仿射变换如下
\begin{array}{rl} & \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix} \\ \Rightarrow & \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} a & b & c & d \\ e & f & g & h \\ i & j & k & l \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix} \end{array}

或者简写为
\vec{\mathbf{f}}^t\mathbf{c} \Rightarrow \vec{\mathbf{f}}^tA\mathbf{c}

我们可以验证上面表达的第二行描述了一个有效的点,因为乘法
\begin{bmatrix} x' \\ y' \\ z' \\ 1 \end{bmatrix} = \begin{bmatrix} a & b & c & d \\ e & f & g & h \\ i & j & k & l \\ 0 & 0 & 0 & 1\end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix}
给出了我们一个带有1作为第4条目的4部件坐标矢量。另一方面,我们也能够看到乘法
\begin{bmatrix} \vec{b}_1' & \vec{b}_2' & \vec{b}_3' & \tilde{o} \end{bmatrix} = \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} a & b & c & d \\ e & f & g & h \\ i & j & k & l \\ 0 & 0 & 0 & 1 \end{bmatrix}
此处0\tilde{o}被定义为\vec{0},给出了一个由3个矢量和一个原点组成的有效帧。

同时也要注意到,如果矩阵的最后一行不是[0,0,0,1]这种形式,变换就通常给出一个无效的结果。

类似于线性变换的情形,我们可以针对一个帧应用仿射变换(affine transformation)为
\begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \Rightarrow \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix}\begin{bmatrix} a & b & c & d \\ e & f & g & h \\ i & j & k & l \\ 0 & 0 & 0 & 1 \end{bmatrix}

或者简写为
\vec{\mathbf{f}}^t \Rightarrow \vec{\mathbf{f}}^tA

3.3 对点应用线性变换(Applying Linear Transformations to Points)

假如我们有一个表达线性变换的3\times3矩阵。我们可以将其嵌入4\times4矩阵的左上方角落,并且借助这个更大的矩阵对一个点(或者帧)应用变换。
\begin{array}{rl} & \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix} \\ \Rightarrow & \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} a & b & c & 0 \\ e & f & g & 0 \\ i & j & k & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix} \end{array}

这个变换在c_i上拥有相同效果,就如之前其所参与的线性变换。如果我们把点\tilde{p}当作从原点\tilde{o}偏移矢量\vec{v},我们就明白这个变换和应用线性变换到偏移矢量上具有相同效果。因而,以例子来说,如果3\times3矩阵为旋转矩阵,这个变换将围绕原点旋转这个点(参考图示\text{Figure 3.1})。正如下面我们将在第4章中看到的,当对一个点应用一个线性变换,帧的原点位置扮演了一个重要的角色。

我们借助下列缩写用于描述一个4\times4矩阵,其只是应用了一个线性变换。
L= \begin{bmatrix}l & 0 \\ 0 & 1\end{bmatrix}
此处L是一个4\times4矩阵,l是一个3\times3矩阵,右上角的0代表3\times1由0组成的矩阵,右下角的1是一个标量(scalar)。

Figure3.1.png

Figure 3.1: 对一个点应用线性变换。可以通过应用线性变换到始于原点的偏移矢量上来完成。

3.4 平移(Translations)

可以对点应用平移变换是很有用的。这种变换不是线性的(参考课后练习6)。仿射变换的主要新威力就是在线性变换之上表达平移的能力。实际上,如果我们应用变换
\begin{array}{rl} & \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix} \\ \Rightarrow & \begin{bmatrix} \vec{b}_1 & \vec{b}_2 & \vec{b}_3 & \tilde{o} \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} c_1 \\ c_2 \\ c_3 \\ 1 \end{bmatrix} \end{array}

我们看到变换在坐标上的效果为
\begin{array}{rcl} c_1 & \Rightarrow & c_1 + t_x \\ c_2 & \Rightarrow & c_2 + t_y \\ c_3 & \Rightarrow & c_3 + t_z \end{array}

针对平移,我们使用简写
T= \begin{bmatrix} i & t \\ 0 & 1 \end{bmatrix}

此处T为 一个4\times4矩阵,i为一个3\times3同一矩阵(identity matrix),右上角的t为一个表达平移的3\times3矩阵,左下角的0表示一个由0组成的1\times3矩阵,右下角的1为一个变量。

注意如果\mathbf{c}在第4坐标中为0,如此就表达了一个矢量而不是一个点,从而不会被平移所影响。

3.5 汇总(Putting Them Together)

任何仿射矩阵(affine matrix)都可以被分解为线性部分和平移部分。
\begin{bmatrix} a & b & c & d \\ e & f & g & h \\ i & j & k & l \\ 0 & 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} a & b & c & 0 \\ e & f & g & 0 \\ i & j & k & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & d \\ 0 & 1 & 0 & h \\ 0 & 0 & 1 & l \\ 0 & 0 & 0 & 1 \end{bmatrix}

或者简写为
\begin{bmatrix} l & t \\ 0 & 1 \end{bmatrix} = \begin{bmatrix} i & t \\ 0 & 1 \end{bmatrix} \begin{bmatrix} l & 0 \\ 0 & 1\end{bmatrix} \tag{3.1}
A = TL \qquad\quad \tag{3.2}

注意因为矩阵乘法不是可互换顺序的,乘法TL中的顺序很关键。一个仿射矩阵(affine matrix)也可以借助一个不同的平移矩阵T'被分解为A=LT'(线性部分是不会发生变化的),但是我们不会使用这种形式。

如果LA的线性部分,是一个旋转,我们把这种形式记作
A=TR \tag{3.3} \qquad\quad

在这种情形中,我们称A矩阵为刚体矩阵(rigid body matrix),它所对应的变化,刚体变换(rigid body transform),简称RBT。刚体变换保留了矢量之间的点积(dot product),基的手(螺旋)性(handedness),还有点之间的距离。

3.6 法线(Normals)

在计算机图形学中,我们经常借助表面法线确定一个表面点如何被着色。所以当表面点经历由矩阵A表示的仿射变换时,我们需要懂得表面法线是如何变换的。

你可能猜测我们只要用矩阵A乘以法线的坐标就可以了。例如,如果我们旋转几何形状,法线会以完全相同的方式旋转。但是事实上使用矩阵A不总是正确的。例如在图示\text{Figure 3.2}中,我们顺着y轴挤压一个球体。在这种情形中,实际的法线变换会顺着y轴拉伸而不是挤压。在这里我们要推导出可以应用在所有情形中的正确变换。

Figure3.2.png

Figure 3.2: 左侧:蓝色的形状拥有以黑色表示的法线。中间:现在在轴方向上被缩小同时(未标准化的)法线在轴方向被拉伸。右侧:法线被重新标准化从而给出被挤压形状的正确的单位法线。

让我们定义位于点上平滑表面的法线为一个矢量,这个矢量正交于那个点表面的切线平面。切线平面是矢量平面,这个矢量平面通过临近的(距离无限小地)表面点之间的减法来定义,所以,针对法线\vec{n}和两个非常接近的点\tilde{p}_1\tilde{p}_2,我们有如下表达。
\vec{n}.(\tilde{p}_1 - \tilde{p}_2) = 0

在某种固定的正交标准化坐标系中,这可以被表达为
\begin{bmatrix} nx & ny & nz & * \end{bmatrix} \left( \begin{bmatrix} x1 \\ y1 \\ z1 \\ 1 \end{bmatrix} - \begin{bmatrix} x0 \\ y0 \\ z0 \\ 1 \end{bmatrix} \right) = 0 \tag{3.4}
在这个公式中我们在前面的插槽中使用'*'是因为它被0乘,从而和结果不相关。

假设存在一个由仿射矩阵A表示的仿射变换,我们把这个变换应用到所有的点上。什么矢量会和任意的切线矢量保持正交状态?让我们重写方程式(3.4)为
(\begin{bmatrix} nx & ny & nz & * \end{bmatrix}A^{-1})(A \left( \begin{bmatrix} x1 \\ y1 \\ z1 \\ 1 \end{bmatrix} - \begin{bmatrix} x0 \\ y0 \\ z0 \\ 1 \end{bmatrix} \right)) = 0

如果我们定义[x',y',z',1]^t=A[x,y,z,1]^t为被变换点的坐标,同时让[nx',ny',nz',*]=[nx,ny,nz,*]A^{-1},那么我们就得到如下表达
(\begin{bmatrix} nx' & ny' & nz' & * \end{bmatrix})( \left( \begin{bmatrix} x1' \\ y1' \\ z1' \\ 1 \end{bmatrix} - \begin{bmatrix} x0' \\ y0' \\ z0' \\ 1 \end{bmatrix} \right)) = 0

并且我们看到[nx',ny',nz']^t是被变换的几何体法线的坐标(要依靠伸缩变换来获得标准态)。

注意因为我们不关注'*'值,因而我们不需要关注A^{-1}的第四列。同时,因为A是一个仿射矩阵(affine matrix),所以A^{-1}也是,进而剩下三列的第四行全部是0,从而可以安全地被忽略。因而,参考简写方式
A= \begin{bmatrix} l & t \\ 0 & 1 \end{bmatrix}

我们可以得到这种关系
\begin{bmatrix} nx' & ny' & nz' \end{bmatrix} = \begin{bmatrix} nx & ny & nz \end{bmatrix}l^{-1}

此时调换整个表达式,我们就获得最终表达式
\begin{bmatrix} nx' \\ ny' \\ nz' \end{bmatrix} = l^{-t}\begin{bmatrix} nx \\ ny \\ nz \end{bmatrix}
此处l^{-t}3\times3矩阵的反转加调换(等价于调换加反转)。注意如果l为一个旋转矩阵,且这个矩阵是正交标准化的,那么它的反转加调换事实上仍然是l。在这种情形中法线的坐标表现的就像点的坐标一样。然而对于其它线性变换,法线的表现就不相同了。(参考图示\text{Figure 3.2}。)同时也要注意到A的平移部分对法线没有影响。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,622评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,716评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,746评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,991评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,706评论 6 413
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,036评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,029评论 3 450
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,203评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,725评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,451评论 3 361
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,677评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,161评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,857评论 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,266评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,606评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,407评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,643评论 2 380

推荐阅读更多精彩内容

  • 仿射变换 AffineTransform,在iOS中他的实现类是CGAffineTransform和CATrans...
    UILabelkell阅读 3,800评论 1 8
  • 如果不熟悉线性代数的概念,要去学习自然科学,现在看来就和文盲差不多。”,然而“按照现行的国际标准,线性代数是通过公...
    Drafei阅读 1,581评论 0 3
  • 多久没看书了? 这是一个直击心灵的拷问。虽然时不时总要写点什么,恰是每一次的绞尽脑汁让我越来越意识到知识的匮乏。没...
    灰公主阅读 350评论 4 3
  • 22天,写作22000字,收获2次排里最佳,一次连里最佳,找到了继续写作的内驱力,像有一种无形的力量在引导我前进。...
    e8d83e9aa398阅读 304评论 8 8
  • 难得的好天气,阳光明媚,带孩子们一起去倒盏村看文俗庙会。 一辆车坐了四个孩子,大的对成语接龙,小的看手机玩游戏。不...
    彭晓芬阅读 90评论 0 0