# 3D 变换

# 平移

T(tx,ty,tz)=(100tx010ty001tz0001)T(t_x,t_y,t_z)=\begin{pmatrix} 1 & 0&0 &t_x \\ 0 & 1 & 0 & t_y\\ 0 &0 &1 &t_z \\ 0 &0 &0 &1 \end{pmatrix}

# 缩放

S(sx,sy,sz)=(sx0000sy0000sz00001)S(s_x,s_y,s_z)=\begin{pmatrix} s_x & 0&0 &0 \\ 0 & s_y & 0 & 0\\ 0 &0 &s_z &0 \\ 0 &0 &0 &1 \end{pmatrix}

# 旋转

Rx(α)=(10000cos⁡α−sin⁡α00sin⁡αcos⁡α00001)Ry(α)=(cos⁡α0sin⁡α00100−sin⁡α0cos⁡α00001)Rz(α)=(cos⁡α−sin⁡α00sin⁡αcos⁡α0000100001)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}\\ 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}\\ 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}

3D 旋转变换矩阵遵循循环对称:X×Y=Z,Y×Z=X,Z×X=YX\times Y=Z,Y\times Z=X,Z\times X=Y

# 合成的旋转变换

Rxyz(α,β,γ)=Rx(α)Ry(β)Rz(γ)R_{xyz}(\alpha,\beta,\gamma)=R_x(\alpha)R_y(\beta)R_z(\gamma)

  • 称为 “欧拉角”
  • 常用于飞行模拟器:roll、pitch、yaw

# 罗德里格斯旋转公式

绕旋转轴 nn 旋转 α\alpha 角度

R(n,α)=cos⁡(α)I+(1−cos⁡(α))nnT+sin⁡(α)NN=(0−nznynz0−nx−nynx0)R(n,\alpha)=\cos(\alpha)I+(1-\cos(\alpha))nn^T+\sin(\alpha)N\\ N=\begin{pmatrix} 0 & -n_z & n_y \\ n_z & 0 & -n_x\\ -n_y &n_x &0 \\ \end{pmatrix}

四元数:旋转与旋转之间的差值

# 推导过程

  1. 对 vv 做正交分解,得:v=v∥+v⊥v=v_\parallel+v_\perp

  2. 由向量的矢量投影公式,得:v∥=(v⋅k)⋅kv_\parallel=(v\cdot k)\cdot k

  3. 由 ① 和 ② ,得:v⊥=v−v∥=v−(v⋅k)⋅kv_\perp=v-v_\parallel=v-(v\cdot k)\cdot k

  4. ∵\because k,v⊥k,v_\perp 与 ww 两两垂直,且 ∣w∣=∣v⊥∣|w|=|v_\perp|

    ∴\therefore 由向量积得

    w=k×v⊥=k×[v−(v⋅k)k]=k×v−k×(v⋅k)k=k×v−k×v∥\begin{aligned} w=k\times v_\perp&=k\times [v-(v\cdot k) k]\\ &=k\times v-k\times (v\cdot k) k \\ &= k\times v-k\times v_\parallel \end{aligned}

    ∵\because kk 与 v∥v_\parallel 共线

    ∴\therefore w=k×vw=k \times v

  5. v⊥v_\perp 旋转 θ\theta 角后得到 vrot⊥v_{rot\perp}

    将 vrot⊥v_{rot\perp} 正交分解,得:vrot⊥=a+bv_{rot\perp}=a+b

    a=vrot⊥×cos⁡(θ−90∘)=vrot⊥×cos⁡,a=wsin⁡θa=v_{rot\perp}\times \cos(\theta-90^\circ)=v_{rot\perp}\times \cos,a=w\sin\theta

    b=vrot⊥×cos⁡(180∘−θ)=vrot⊥×cos⁡,b=v⊥cos⁡θb=v_{rot\perp}\times \cos(180^\circ-\theta)=v_{rot\perp}\times \cos,b=v_\perp\cos\theta

    ∴vrot⊥=a+b=wsin⁡θ+vrot⊥cos⁡θ=sin⁡θk×v+cos⁡θ[v−(v⋅k)k]\therefore v_{rot\perp}=a+b=w\sin\theta+v_{rot\perp}\cos\theta=\sin\theta k\times v + \cos \theta[v-(v\cdot k) k]

  6. vrot=v∥+vrot⊥=(v⋅k)+sin⁡θk×v+cos⁡θ[v−(v⋅k)k]=(v⋅k)k+sin⁡θk×v+cos⁡θv−cos⁡θ(v⋅k)k=cos⁡θv+(1−cos⁡θ)(v⋅k)k+sin⁡θk×v\begin{align*} v_{rot}=v_\parallel+v_{rot\perp}&=(v\cdot k)+\sin\theta k\times v+\cos\theta[v-(v\cdot k)k]\\ &=(v\cdot k)k+\sin\theta k\times v + \cos\theta v-\cos\theta(v\cdot k)k\\ &=\cos\theta v+(1-\cos\theta)(v\cdot k)k+\sin\theta k\times v \end{align*}

  7. 将得到的结果变为矩阵的形式:

    1. 推导,得:vrot=cos⁡θv+(1−cos⁡θ)(v⋅k)k+sin⁡θk×vv_{rot}=\cos\theta v+(1-\cos\theta)(v\cdot k)k+\sin\theta k\times v

      把 kk 和 vv 分别写作列向量:

      k=(kxkykz)v=(vxvyvz)k=\begin{pmatrix} k_x \\k_y \\k_z \end{pmatrix} v=\begin{pmatrix} v_x \\v_y \\v_z \end{pmatrix}

      令 vrot=Rvv_{rot}=Rv,下面对 RR 进行计算

    2. (v⋅k)k=k(v⋅k)=k(kT⋅v)(v\cdot k)k=k(v\cdot k)=k(k^T\cdot v)

    3. k×v=(kyvz−kzvykzvx−kxvzkxvy−kyvx)=(0−kzkykz0−kx−kykx0)(vxvyvz)k\times v =\begin{pmatrix}k_y v_z-k_z v_y \\k_zv_x-k_xv_z \\k_xv_y-k_yv_x\end{pmatrix}=\begin{pmatrix}0&-k_z&k_y\\k_z&0&-k_x\\-k_y&k_x&0\end{pmatrix}\begin{pmatrix}v_x \\v_y \\v_z\end{pmatrix}

    4. ∴ R=Icos⁡θ+(1−cos⁡θ)(kxkykz)(kxkykz)+sin⁡θ(0−kzkykz0−kx−kykx0)\therefore\ R=I\cos\theta+(1-\cos\theta)\begin{pmatrix}k_x\\k_y \\k_z\end{pmatrix}\begin{pmatrix}k_x&k_y&k_z\end{pmatrix}+\sin\theta\begin{pmatrix}0&-k_z&k_y\\k_z&0&-k_x\\-k_y&k_x&0\end{pmatrix}

      其中 II 为 3×33\times 3 的单位矩阵

# 如何将三维变成二维并在屏幕上显示出来

  1. 模型变换 (M)
  2. 相机变换 (V)
  3. 投影变换 (P)

# 相机的定义

  • 位置 e⃗\vec{e}
  • 视线方向 $\hat {g} $
  • 垂直方向 t^\hat{t}

如果把摄像机和世界一起变换,那么照片是一样的,所以把摄像机变换到新坐标系的原点,其他所有物体也做同样的变换

# TEG 坐标系怎么转变为 XYZ 坐标系

Mview=RviewTviewM_{view}=R_{view}T_{view}

  1. 先做平移,Tview=[100−xe010−ye001−ze0001]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}

  2. 再做旋转,顺着思路要把 g^\hat{g} 旋转到 −Z-Z 坐标轴,把 t^\hat{t} 旋转到 YY 坐标轴,把 (g×t)(g\times t) 旋转到 XX 坐标轴,但这样的旋转矩阵非常难写

  3. 所以采用逆向思路,把坐标轴移到相机坐标轴,通过逆操作写(该旋转矩阵为正交矩阵,其逆矩阵就是它的转置矩阵)(基变换)

    Rview−1=[xg^×t^xtx−g0yg^×t^yty−g0zg^×t^ztz−g00001]Rview=[xg^×t^yg^×t^zg^×t^0xtytzt0x−gy−gz−g00001]R^{-1}_{view}=\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_{view}=\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}\\

# 投影变换

# 计算机图形学中的投影

  • 3D 转 2D
  • 正交投影
  • 透视投影

# 透视投影与正交投影

# 正交投影

  • 相机位于原点,面向 −Z-Z,上方是 YY
  • 忽略 ZZ 坐标
  • 将生成的矩形平移并缩放为 [−1,1]2[-1, 1]^2

  • 相机位置无限远,没有远近概念(忽略深度信息)

  • 步骤:先做平移,再做缩放,目的是把投影全塞在 [−1,1]3[-1,1]^3 的长方体内

Mortho=[2r−l00002t−b00002n−f00001][100−r+l2010=t+b2001−n+f20001]M_{ortho}=\begin{bmatrix} \dfrac{2}{r-l} & 0 & 0 & 0\\ 0 & \dfrac{2}{t-b} & 0 &0 \\ 0 & 0 & \dfrac{2}{n-f} &0 \\ 0 & 0 & 0 &1\end{bmatrix}\begin{bmatrix} 1 & 0 & 0 & -\dfrac{r+l}{2}\\ 0 & 1 & 0 &=\dfrac{t+b}{2} \\ 0 & 0 & 1 &-\dfrac{n+f}{2} \\ 0 & 0 & 0 &1\end{bmatrix}

  • 沿着 −Z-Z 使远近不直观(n>fn > f)
  • 仅供参考:这就是 OpenGL 使用左手坐标的原因。

# 透视投影

  • 最常见于计算机图形学、艺术、视觉系统
  • 近大远小
  • 平行线不平行; 收敛到单点

# 推导过程

正交投影矩阵的视锥体是一个四棱锥的一部分,其中近平面为 z=nz=n,远平面为z=fz=f,我们要把这个视锥体转换到一个正方体[−1,1][−1,1][−1,1][-1,1][-1,1][-1,1] 中,可以先把远平面压缩,把视锥体压缩成一个长方体,然后再通过第二步中的正交投影矩阵就可以变换到正方体中,如图。

在把视锥体压缩成长方体的过程中,我们规定三个原则

  1. 近平面的所有点坐标不变

  2. 远平面的所有点坐标 zz 值不变 都是 ff

  3. 远平面的中心点坐标值不变 为 (0,0,f)(0,0,f)

然后我们假设视锥体内的任意一点 (x,y,z)(x,y,z),压缩以后的 xyxy 坐标应该与近平面上对应的点相同,如图解相似三角形可以得到 y→ny/z,x→nx/zy\rightarrow ny/z,x\rightarrow nx/z

故对于(x,y,z,1)(x,y,z,1) 一点,它在视锥体压缩以后坐标应该为(nx/z,ny/z,unknow,1)(nx/z,ny/z,unknow,1)。

zz 值我们还不知道,这里先不讨论。

(xyz1)⇒(nx/zny/zunknown1)\begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix}\Rightarrow\begin{pmatrix} nx/z \\ ny/z \\ \text{unknown} \\ 1 \end{pmatrix}

也就是我们现在需要找到一个矩阵 Mpersp→ortho\text{Mpersp}\rightarrow\text{ortho},使得上面的转换成立。

假设矩阵的第一行为 A,B,C,DA,B,C,D。可以得到等式 Ax+By+Cz+D=nx/zAx+By+Cz+D = nx/z。

然后我们发现这个等式好像很难求,如果让 A=n/zA = n/z,其他等于00,的确可以得到结果。

但是矩阵的值应该是常数,n/zn/z 是个变量。

而其他的结果也很难写出来,同时矩阵的第二行也会有同样的问题 Ex+Fy+Gz+H=ny/zEx+Fy+Gz+H = ny/z,也很难求。

所以我们换一种方法,前面根据已学知识可以知道(x,y,z,1)(x,y,z,1) 与(kx,ky,kz,k≠0)(kx,ky,kz,k\not=0) 这两个点是完全等价的点,

所以我们让kk 取zz 可以把坐标(nx/z,ny/z,unknow,1)(nx/z,ny/z,unknow,1) 变为(nx,ny,still unknow,z)(nx,ny,\text{still unknow},z)。

Mpresp→ortho(4×4)(xyz1)=(nxnyunknownz)M_{presp\rightarrow ortho}^{(4\times 4)}\begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix}=\begin{pmatrix} nx \\ ny \\ \text{unknown} \\ z \end{pmatrix}

也就是我们需要找到矩阵 Mpersp→ortho\text{Mpersp}\rightarrow\text{ortho},使得上面的转换成立。

现在就变简单了,Ax+By+Cz+D=nxAx+By+Cz+D = nx,求出 A=n,B=C=D=0A=n,B=C=D=0

Ex+Fy+Gz+H=nyEx+Fy+Gz+H = ny,求出 F=n,E=G=H=0F=n,E=G=H=0

Mx+Ny+Oz+P=zMx+Ny+Oz+P = z,求出 O=1,M=N=P=0O=1,M=N=P=0。

Mpresp→ortho(n0000n00????0010)M_{presp\rightarrow ortho}\begin{pmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \end{pmatrix}

于是,我们求出了矩阵的其中三行,只剩下第三行是未知的。

然后我们想下之前的三个原则,其中一个,近平面的所有点坐标不变。

也就是点 (x,y,n,1)(x,y,n,1) 通过矩阵 Mpersp→ortho\text{Mpersp}\rightarrow\text{ortho} 变换后,应该还是等于 (x,y,n,1)(x,y,n,1)。

(n0000n00????0010)∗(xyn1)=(xyn1)\begin{pmatrix} n & 0 & 0 &0 \\ 0 & n & 0 & 0\\ ? &? &? &? \\ 0 &0 & 1 &0 \end{pmatrix}*\begin{pmatrix} x\\y\\n\\1 \end{pmatrix}=\begin{pmatrix} x\\y\\n\\1 \end{pmatrix}

对于第一二四行,我们写出等式

nx+0y+0n+0∗1=x0x+ny+0n+0∗1=y0x+0y+1n+0∗1=1nx+0y+0n+0*1=x\\ 0x+ny+0n+0*1=y\\ 0x+0y+1n+0*1=1\\

很明显这是有问题的,因为 nn 应该是任意常数,但是现在只有在 nn 等于 11 时,一二四行的运算才成立

所以我们根据前面的方法,再把 (x,y,n,1)(x,y,n,1) 都乘以一个 nn 等价变为 (nx,ny,n∗n,n)(nx,ny,n*n,n)。

这样转换就变成了

(n0000n00????0010)∗(xyn1)=(nxnyn∗nn)\begin{pmatrix} n & 0 & 0 &0 \\ 0 & n & 0 & 0\\ ? &? &? &? \\ 0 &0 & 1 &0 \end{pmatrix}*\begin{pmatrix} x\\y\\n\\1 \end{pmatrix}=\begin{pmatrix} nx\\ny\\n*n\\n \end{pmatrix}

对于第一二四行,我们写出等式

nx+0y+0n+0∗1=nx0x+ny+0n+0∗1=ny0x+0y+1n+0∗1=nnx+0y+0n+0*1=nx\\ 0x+ny+0n+0*1=ny\\ 0x+0y+1n+0*1=n\\

完美成立。现在我们可以安心的求第三行了。

设第三行的四个数分别为 ABCD

可以获得等式 Ax+By+Cn+D=n∗nAx+By+Cn+D = n*n。

明显 A=0,B=0,Cn+D=n∗nA=0,B=0,Cn+D = n*n ①

我们接下来考虑第三个原则,远平面的中心点坐标值不变 为(0,0,f)(0,0,f)

同样为了保证之前求的矩阵一二四行成立,我们需要把 (0,0,f,1)(0,0,f,1) 写成 (0,0,f∗f,f)(0,0,f*f,f)

(n0000n00????0010)∗(00f1)=(00f∗ff)\begin{pmatrix} n & 0 & 0 &0 \\ 0 & n & 0 & 0\\ ? &? &? &? \\ 0 &0 & 1 &0 \end{pmatrix}*\begin{pmatrix} 0\\0\\f\\1 \end{pmatrix}=\begin{pmatrix} 0\\0\\f*f\\f \end{pmatrix}

Cf+D=f∗fCf+D = f*f ②

联立 ① ②,解得:C=n+f,D=−nfC = n+f,D = -nf

终于,我们求得了 Mpersp→ortho\text{Mpersp}\rightarrow\text{ortho} 矩阵为

(n0000n0000n+f−nf0010)\begin{pmatrix} n & 0 & 0 &0 \\ 0 & n & 0 & 0\\ 0 &0 &n+f &-nf \\ 0 &0 & 1 &0 \end{pmatrix}

也就是通过这个矩阵,我们可以把原来的透视投影的视锥体压缩为正交投影的视锥体(长方体)

最后我们再乘上一开始求出来正交投影矩阵 Morth\text{Morth} 就得到了透视投影矩阵:Mpersp=Mortho∗Mpersp→ortho\text{Mpersp} = \text{Mortho}*\text{Mpersp}\rightarrow\text{ortho}

(2/(r−l)00002/(t−b)00002/(n−f)00011)∗(100−(l+r)/2010−(b+t)/2001−(f+n)/20001)=(n0000n0000n+f00010)\begin{pmatrix} 2/(r-l) & 0 & 0 &0 \\ 0 & 2/(t-b) & 0 & 0\\ 0 &0 &2/(n-f) &0 \\ 0 &0 & 1 &1 \end{pmatrix}*\begin{pmatrix} 1 & 0 & 0 &-(l+r)/2 \\ 0 & 1 & 0 & -(b+t)/2\\ 0 &0 &1 &-(f+n)/2 \\ 0 &0 & 0 &1 \end{pmatrix}=\begin{pmatrix} n & 0 & 0 &0 \\ 0 & n & 0 & 0\\ 0 &0 &n+f &0 \\ 0 &0 & 1 &0 \end{pmatrix}