头像

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]
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}

透视投影

透视投影实际上就是,先把视锥体,压成长方体,然后执行一次正交投影的方法,把长方体的投影到[-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
Af+B = f^2\
An+B = n^2

解:

A=f+nB=nf
A = f + n\
B = -nf

得到矩阵:

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)
r = -n * aspect * tan(fov/2)\
l = n * aspect * tan(fov/2)

带入得到实际用的矩阵:

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}