# 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α00100sinα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+(1cos(α))nnT+sin(α)NN=(0nznynz0nxnynx0)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+vv=v_\parallel+v_\perp

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

  3. 由 ① 和 ② ,得:v=vv=v(vk)kv_\perp=v-v_\parallel=v-(v\cdot k)\cdot k

  4. \because k,vk,v_\perpww 两两垂直,且 w=v|w|=|v_\perp|

    \therefore 由向量积得

    w=k×v=k×[v(vk)k]=k×vk×(vk)k=k×vk×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 kkvv_\parallel 共线

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

  5. vv_\perp 旋转 θ\theta 角后得到 vrotv_{rot\perp}

    vrotv_{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=vcosθb=v_{rot\perp}\times \cos(180^\circ-\theta)=v_{rot\perp}\times \cos,b=v_\perp\cos\theta

    vrot=a+b=wsinθ+vrotcosθ=sinθk×v+cosθ[v(vk)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=(vk)+sinθk×v+cosθ[v(vk)k]=(vk)k+sinθk×v+cosθvcosθ(vk)k=cosθv+(1cosθ)(vk)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+(1cosθ)(vk)k+sinθk×vv_{rot}=\cos\theta v+(1-\cos\theta)(v\cdot k)k+\sin\theta k\times v

      kkvv 分别写作列向量:

      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. (vk)k=k(vk)=k(kTv)(v\cdot k)k=k(v\cdot k)=k(k^T\cdot v)

    3. k×v=(kyvzkzvykzvxkxvzkxvykyvx)=(0kzkykz0kxkykx0)(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θ+(1cosθ)(kxkykz)(kxkykz)+sinθ(0kzkykz0kxkykx0)\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}

      其中 II3×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=[100xe010ye001ze0001]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. 所以采用逆向思路,把坐标轴移到相机坐标轴,通过逆操作写(该旋转矩阵为正交矩阵,其逆矩阵就是它的转置矩阵)(基变换)

    Rview1=[xg^×t^xtxg0yg^×t^ytyg0zg^×t^ztzg00001]Rview=[xg^×t^yg^×t^zg^×t^0xtytzt0xgygzg00001]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=[2rl00002tb00002nf00001][100r+l2010=t+b2001n+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 坐标应该与近平面上对应的点相同,如图解相似三角形可以得到 yny/z,xnx/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}

也就是我们现在需要找到一个矩阵 Mpersportho\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,k0)(kx,ky,kz,k\not=0) 这两个点是完全等价的点,

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

Mpresportho(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}

也就是我们需要找到矩阵 Mpersportho\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

Mpresportho(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) 通过矩阵 Mpersportho\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+01=x0x+ny+0n+01=y0x+0y+1n+01=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,nn,n)(nx,ny,n*n,n)

这样转换就变成了

(n0000n00????0010)(xyn1)=(nxnynnn)\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+01=nx0x+ny+0n+01=ny0x+0y+1n+01=nnx+0y+0n+0*1=nx\\ 0x+ny+0n+0*1=ny\\ 0x+0y+1n+0*1=n\\

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

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

可以获得等式 Ax+By+Cn+D=nnAx+By+Cn+D = n*n

明显 A=0,B=0,Cn+D=nnA=0,B=0,Cn+D = n*n

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

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

(n0000n00????0010)(00f1)=(00fff)\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=ffCf+D = f*f

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

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

(n0000n0000n+fnf0010)\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=MorthoMpersportho\text{Mpersp} = \text{Mortho}*\text{Mpersp}\rightarrow\text{ortho}

(2/(rl)00002/(tb)00002/(nf)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}