旋转矩阵的符号差异源于坐标系的手系规则和旋转方向定义。
首先是我们最常规的绕着z轴旋转,这是右手系下的标准定义,符合"x轴转向y轴"的正方向。
R z ( α ) = ( cos α − sin α 0 0 sin α cos α 0 0 0 0 1 0 0 0 0 1 ) \mathbf{R}_z(\alpha) = \begin{pmatrix} \cos \alpha & -\sin \alpha & 0 & 0 \\ \sin \alpha & \cos \alpha & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} Rz(α)= cosαsinα00−sinαcosα0000100001
这个时候,我们通常都把x轴与y轴线性变换之后所形成的角度设为 α \alpha α ,不同角的设置就会出现不同的符号,我们通常设置角的优先度就是x>y>z,所以就有了下面不同的符号。
R x ( α ) = ( 1 0 0 0 0 cos α − sin α 0 0 sin α cos α 0 0 0 0 1 ) \mathbf{R}_x(\alpha) = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos \alpha & -\sin \alpha & 0 \\ 0 & \sin \alpha & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} Rx(α)= 10000cosαsinα00−sinαcosα00001
R y ( α ) = ( cos α 0 sin α 0 0 1 0 0 − sin α 0 cos α 0 0 0 0 1 ) \mathbf{R}_y(\alpha) = \begin{pmatrix} \cos \alpha & 0 & \sin \alpha & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \alpha & 0 & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} Ry(α)= cosα0−sinα00100sinα0cosα00001
我们把沿着每个角的旋转角度分开来表示被称之为欧拉角
[!note]
R x y z ( α , β , γ ) = R x ( α ) R y ( β ) R z ( γ ) \mathbf{R}_{xyz}(\alpha, \beta, \gamma) = \mathbf{R}_x(\alpha) \, \mathbf{R}_y(\beta) \, \mathbf{R}_z(\gamma) Rxyz(α,β,γ)=Rx(α)Ry(β)Rz(γ)
这里挖坑:可以去探究下罗德里格斯旋转公式是什么,以及怎么推导的,参考[数学]罗德里格旋转公式(Rodrigues’ rotation formula) - 知乎
相机本体放在(0,0,0)上,正方向为-Z方向,正上方向为+Y方向,然后场景移动,而不是相机移动
有了这些概念之后我们就应该明白,即便我们要把相机放在世界坐标系的原点上也是世界坐标系移动,使得原点跑到了相机的坐标上,而不是移动相机跑到原点上。那么此刻我们感受到的应该是反客为主,此时相机的坐标就是原点,而世界坐标系才是需要移动的。
既然反客为主,这个时候世界坐标系的原点也不一样了,应该是相机视角下世界坐标系原点的坐标。比如,此刻相机的坐标系为(10,5,3),那么此时原点现对于相机的坐标为 ( 0 − 10 , 0 − 5 , 0 − 3 0-10,0-5,0-3 0−10,0−5,0−3) ,或者一个物品此时的坐标为(15,7,8),那么这个物品的相对坐标就为:(15-10,7-5,8-3)。
所以想要把世界坐标轴原点移动到相机就得直接减去相对坐标才行。
那么此时的变换矩阵就应该是 T v i e w = [ 1 0 0 − x e 0 1 0 − y e 0 0 1 − z e 0 0 0 1 ] T_{view} = \begin{bmatrix}1 & 0 & 0 & -x_e \\0 & 1 & 0 & -y_e \\0 & 0 & 1 & -z_e \\0 & 0 & 0 & 1\end{bmatrix} Tview= 100001000010−xe−ye−ze1
当我们有了找个标准的视角之后,如果相机不是标准方向,那么就需要我们把相机的视角旋转到找个标准的位置。我们就要尝试找到找个旋转矩阵。但是这个矩阵肉眼并不好看出来,只能靠其他的办法去求了。
我们虽然不知道怎么直接拿到世界坐标系旋转到详细坐标系的旋转矩阵,但是能知道怎么把相机坐标系的点怎么在世界坐标系来表示:
R = [ x g ^ × t ^ x t x − g 0 y g ^ × t ^ y t y − g 0 z g ^ × t ^ z t z − g 0 0 0 0 1 ] R = \begin{bmatrix} x_{\hat{g}\times\hat{t}} & x_t & x_{-g} & 0 \\ y_{\hat{g}\times\hat{t}} & y_t & y_{-g} & 0 \\ z_{\hat{g}\times\hat{t}} & z_t & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} R= xg^×t^yg^×t^zg^×t^0xtytzt0x−gy−gz−g00001
那么表示起来就是这样: p world = R ⋅ p camera p_{\text{world}} = R \cdot p_{\text{camera}} pworld=R⋅pcamera 这里的 p camera p_{\text{camera}} pcamera 就是相机坐标的点(基本坐标 x 倍数 = 坐标系下的坐标),那么我们要把世界坐标转换到相机坐标只需要我们用 R T R = R R T = I R^T R = R R^T = I RTR=RRT=I 的性质对其进行转换。
我们把 p world = R ⋅ p camera p_{\text{world}} = R \cdot p_{\text{camera}} pworld=R⋅pcamera 两边同时乘一个 R T R^T RT 那么就出现了 R T ⋅ p world = R R T ⋅ p camera R^T \cdot p_{\text{world}} = RR^T \cdot p_{\text{camera}} RT⋅pworld=RRT⋅pcamera 最后结果就是 R T ⋅ p world = p camera R^T \cdot p_{\text{world}} = p_{\text{camera}} RT⋅pworld=pcamera
所以旋转矩阵就是:
R T = [ x g ^ × t ^ y g ^ × t ^ z g ^ × t ^ 0 x t y t z t 0 x − g y − g z − g 0 0 0 0 1 ] R^T=\begin{bmatrix} x_{\hat{g}\times\hat{t}} & y_{\hat{g}\times\hat{t}} & z_{\hat{g}\times\hat{t}} & 0 \\ x_t & y_t & z_t & 0 \\ x_{-g} & y_{-g} & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} RT= xg^×t^xtx−g0yg^×t^yty−g0zg^×t^ztz−g00001
最后再加上平移矩阵,最后的总矩阵就是:
[ x g ^ × t ^ y g ^ × t ^ z g ^ × t ^ − x e x t y t z t − y e x − g y − g z − g − z e 0 0 0 1 ] \begin{bmatrix} x_{\hat{g}\times\hat{t}} & y_{\hat{g}\times\hat{t}} & z_{\hat{g}\times\hat{t}} & -x_e \\ x_t & y_t & z_t & -y_e \\ x_{-g} & y_{-g} & z_{-g} & -z_e \\ 0 & 0 & 0 & 1 \end{bmatrix} xg^×t^xtx−g0yg^×t^yty−g0zg^×t^ztz−g0−xe−ye−ze1
正交投影应该没什么可说的,很直观,我们这里只看一个东西。
很多时候我们都把一个物体等价缩放到一个2x2的标准正方体里面,如图:
我们重点还是透视投影。
透视投影的核心概念是远近缩放效应,即物体越远,看起来越小。
透视投影说白了就是个三角形,关系如下:
y ′ = n z y , x ′ = n z x y' = \frac{n}{z} y, \quad x' = \frac{n}{z} x y′=zny,x′=znx
其中:
这个关系说明,投影后的 x′,y′值与z 反比,物体越远 (z 大),投影坐标越小。
这个时候我们希望有一个矩阵在齐次坐标能够表示到把 ( x y z 1 ) \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} xyz1 映射为 ( n x z n y z unknown 1 ) \begin{pmatrix} \frac{nx}{z} \\ \frac{ny}{z} \\ \text{unknown} \\ 1 \end{pmatrix} znxznyunknown1
让我们一点一点地分析 :
为了方便计算我们将整个映射后的矩阵再乘以一个z
( n x n y still unknown z ) \begin{pmatrix} nx \\ ny \\ \text{still unknown} \\ z \end{pmatrix} nxnystill unknownz
那么这个变换矩阵就应该是这样:
M persp → ortho ( x y z 1 ) = ( n x n y still unknown z ) M_{\text{persp}\rightarrow\text{ortho}}\begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} nx \\ ny \\ \text{still unknown} \\ z \end{pmatrix} Mpersp→ortho xyz1 = nxnystill unknownz
所以我们直接看都能看出来,x与y只用乘一个 n n n ,而最后保证和z的值一样就行,所以就有了初步的结果:
M persp → ortho = ( n 0 0 0 0 n 0 0 ? ? ? ? 0 0 1 0 ) M_{\text{persp}\rightarrow\text{ortho}}=\begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \end{pmatrix} Mpersp→ortho= n0?00n?000?100?0
我们看到 ( n x n y still unknown z ) \begin{pmatrix} nx \\ ny \\ \text{still unknown} \\ z \end{pmatrix} nxnystill unknownz 的最后一行实际上就是 ( x y z 1 ) \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} xyz1 的z。
其中第三个分量 ? 就是新的 z’,它必须满足以下要求:
我们其实早就能发现z的值与xy的值是没有关系的,
所以前面的两个数都会是 ( 0 , 0 , ? , ? ) (0,0,?,?) (0,0,?,?)
我们知道:
[!note] 近平面上的点 (z = n) 不能变动,即:
M persp → ortho ( x y n 1 ) = ( x y n 2 1 ) M_{\text{persp}\rightarrow\text{ortho}} \begin{pmatrix} x \\ y \\ n \\ 1 \end{pmatrix} = \begin{pmatrix} x \\ y \\ n^2 \\ 1 \end{pmatrix} Mpersp→ortho xyn1 = xyn21
这表明,第三行应该是 ( 0 0 A B ) (0 \ 0 \ A \ B) (0 0 A B) 同时满足: A n + B = n 2 An + B = n^2 An+B=n2
[!note] 远平面上的点 (z = f) 不能变动:
A f + B = f 2 Af + B = f^2 Af+B=f2
通过解方程:
{ A n + B = n 2 A f + B = f 2 \begin{cases} An + B = n^2 \\ Af + B = f^2 \end{cases} {An+B=n2Af+B=f2
得到:
{ A = n + f B = − n f \begin{cases} A = n + f \\ B = -nf \end{cases} {A=n+fB=−nf
所以,第三行最终确定为:
( 0 , 0 , ( n + f ) , − n f ) (0 \ ,0 \ ,(n+f) \ ,-nf) (0 ,0 ,(n+f) ,−nf)
最终的完整矩阵就为:
M persp → ortho = ( n 0 0 0 0 n 0 0 0 0 n + f − n f 0 0 1 0 ) M_{\text{persp}\rightarrow\text{ortho}} = \begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & 1 & 0 \end{pmatrix} Mpersp→ortho= n0000n0000n+f100−nf0
得到了这个投影之后在做一个正交投影就能直接投射到摄像机上
[!note]
当空间中有一个点,在frustum内,但是不在近平面与远平面上的时候,经过压缩变换之后,这个点在Z轴上的坐标,会变得离近平面更近、还是离远平面更近、还是不变?
这里的意思实际上是想让我们思考:
这个地方我们的第一反应就应该去求 Z 轴坐标的值,这个地方实际上很好求,因为前面我们已经有了这样一个旋转矩阵了: ( n 0 0 0 0 n 0 0 0 0 n + f − n f 0 0 1 0 ) \begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & 1 & 0 \end{pmatrix} n0000n0000n+f100−nf0 。
我们设这个frustum内一点P的齐次坐标为: ( x y z 1 ) \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} xyz1
变换后,得到新的齐次坐标:
M persp → ortho ( x y z 1 ) = ( n x n y ( n + f ) z − n f z ) M_{\text{persp} \rightarrow \text{ortho}} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} nx \\ ny \\ (n+f)z - nf \\ z \end{pmatrix} Mpersp→ortho xyz1 = nxny(n+f)z−nfz
那么我们的 z’ = ( n + f ) z − n f z = ( n + f ) − n f z \frac{(n+f)z - nf}{z} = (n+f) - \frac{nf}{z} z(n+f)z−nf=(n+f)−znf ,其中 n < z < f
这个时候就很简单了,我们只需要知道这个式子的单调性就能知道整个式子随着 z’ 的增大是减小还是增加,如果是前者,那么就是更靠近远平面,反之亦然。也就是说,当 z 越发靠近 n ,变换后的值也会越小,越小,那么离摄像机越近,离摄像机,那可不越靠近n吗
这里值得一提的是,这里n,f,z都是大于0的,因为在摄像机视角中,只能看见正面,后面是看不见的,也不用进行处理,所以这里的n,f,z一定都是大于0的。
这个式子不用多说,想知道单调性直接求个导就出来了:
d d z z ′ = d d z ( ( n + f ) − n f z ) = n f z 2 \frac{d}{dz} z' = \frac{d}{dz} \left( (n+f) - \frac{nf}{z} \right) = \frac{nf}{z^2} dzdz′=dzd((n+f)−znf)=z2nf
无论 z 等于何值,倒数都大于0,整个函数单调递增。
问题解决。