头像

zjian

Just Code!

帖子照片墙关于

投影矩阵的推导

2024-06-29 00:11

上篇文章做了视图矩阵的推导过程,实际上就是把物体的坐标转化成摄像机的相对坐标,之后呢需要把三维空间中的物体映射到二维平面上,这里就需要投影矩阵来实现。

投影矩阵一般有两种,一种是正交投影,还有一种是透视投影

正交投影

正交投影由于没有近大远小的特性,常用于显示在三维空间中的 2D 视图,比如,房子的顶面 2D 视图等。

正交相机一般有 6 个参数,分别是 left、right、bottom、top、near、far。 这 6 个参数就可以构成空间中的一个立方体,正交投影做的事也很简单,把空间中的立方体移动到原点为中心且 (x, y, z) 都缩放到 [-1, 1] 的立方体中。

为什么要这么做呢?很简单,要投影 left-right 的物体,那对于屏幕来说,中间点就是 left + right / 2, 所以要放到中间点。缩放到【-1, 1】主要是为了后面再放大到屏幕坐标上。

根据上面的分析,很容易得到正交投影的平移矩阵:

Mtranslate=[100l+r2010top+bottom2001near+far20001]
M_{translate} = \begin{bmatrix}
1 & 0 & 0 & -\frac{l+r}{2} \
0 & 1 & 0 & -\frac{top+bottom}{2}\
0 & 0 & 1 & -\frac{near+far}{2}\
0 & 0 & 0 & 1
\end{bmatrix}

然后缩放矩阵:

Mscale=[2rl00002topbottom00002nearfar00001]
M_{scale} = \begin{bmatrix}
\frac{2}{r-l} & 0 & 0 & 0 \
0 & \frac{2}{top-bottom} & 0 & 0 \
0 & 0 & \frac{2}{near-far} & 0 \
0 & 0 & 0 & 1
\end{bmatrix}

最后的矩阵结果:

M=MscaleMtranslate=[2rl00r+lrl02topbottom0top+bottomtopbottom002nearfarnear+farnearfar0001]
\begin{aligned}
M &= M_{scale}M_{translate}\
&= \begin{bmatrix}
\frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \
0 & \frac{2}{top-bottom} & 0 & -\frac{top+bottom}{top-bottom} \
0 & 0 & \frac{2}{near-far} & -\frac{near+far}{near-far} \
0 & 0 & 0 & 1
\end{bmatrix}
\end{aligned}

透视投影

透视投影实际上就是,先把视锥体,压成长方体,然后执行一次正交投影的方法,把长方体的投影到[-1, 1] 上。

首先,在压的过程中,会有两个特性:

  1. 远平面 f 所在平面变换完还在 f 平面
  2. 近平面 n 所在平面的点转换完还在 n 平面

然后算远平面(f)的点, 根据相似三角形的特性n/f=y/yn / f = y'/y,所以 y=nfyy' = \frac{n}{f}y,

所以可以推导:

M[xyf1]=[nfxnfyf1]=[nxnyf2f]
M * \begin{bmatrix}
x\y\f\1\
\end{bmatrix} = \begin{bmatrix}
\frac{n}{f}x\\frac{n}{f}y\f\1\
\end{bmatrix} = \begin{bmatrix}
nx\ny\f^2\f
\end{bmatrix}

这样就可以推导出矩阵的部分内容。

M=[n0000n0000??0010]
M = \begin{bmatrix}
n & 0 & 0 & 0\
0 & n & 0 & 0\
0 & 0 & ? & ? \
0 & 0 & 1 & 0\
\end{bmatrix}

为什么有两个问好推导不了呢,因为 有可能第一个数是 f,第二个数是 0,也可能第一个数是 0,第二个数是 f2f^2.

那根据第二个性质,我们可以得出 (x, y, z) ⇒ 还是 (x, y, z)。

所以:

M[xyn1]=[xyn1]=[nxnyn2n]
M *\begin{bmatrix}
x\y\n\1
\end{bmatrix} = \begin{bmatrix}
x\y\n\1
\end{bmatrix} = \begin{bmatrix}
nx\ny\n^2\n
\end{bmatrix}

这样也能推出:

M=[n0000n0000??0010]
M = \begin{bmatrix}
n & 0 & 0 & 0\
0 & n & 0 & 0\
0 & 0 & ? & ? \
0 & 0 & 1 & 0\
\end{bmatrix}

假设 M[3,3] = A, M[3,4] = B。

所以有两个公式可以得出:

Af+B=f2An+B=n2
\begin{aligned}
Af+B &= f^2\
An+B &= n^2
\end{aligned}

解:

A=f+nB=nf
\begin{aligned}
A &= f + n\
B &= -nf
\end{aligned}

得到矩阵:

M=[n0000n0000f+nnf0010]
M = \begin{bmatrix}
n & 0 & 0 & 0\
0 & n & 0 & 0\
0 & 0 & f+n & -nf \
0 & 0 & 1 & 0\
\end{bmatrix}

最后再应用正交矩阵即可得到最后的矩阵:

M=[2nrl0r+lrl002ntbt+btb000n+fnf2nfnf0010]
M = \begin{bmatrix}
\frac{2n}{r-l} & 0 & -\frac{r+l}{r-l} & 0\
0 & \frac{2n}{t-b} & -\frac{t+b}{t-b} & 0\
0 & 0 & \frac{n+f}{n-f} & -\frac{2nf}{n-f}\
0 & 0 & 1 & 0\
\end{bmatrix}

然后 t=ntan(fov/2)t = -ntan(fov/2) , 这里 n 是负数, 所以要乘 -1。同理 b=ntan(fov/2)b = ntan(fov/2)

因为宽高比是 aspect, 所以:

r=naspecttan(fov/2)l=naspecttan(fov/2)
\begin{aligned}
r &= -n * aspect * tan(fov/2)\
l &= n * aspect * tan(fov/2)
\end{aligned}

带入得到实际用的矩阵:

M=[1aspecttan(fov/2)00001tan(fov/2)0000n+fnf2nfnf0010]
M = \begin{bmatrix}
-\frac{1}{aspect*tan(fov/2)} & 0 & 0 & 0\
0 & -\frac{1}{tan(fov/2)} & 0 & 0 \
0 &0 &\frac{n+f}{n-f} & -\frac{2nf}{n-f}\
0 & 0 & 1 & 0\
\end{bmatrix}