投射投影过程数学推导

Perspective Projection

顶点数据经过模型变换、相机变换转换到观察空间,之后渲染系统引入视椎体的概念,并通过投影变换将视椎体转换到统一设备坐标系中,方便剪裁和后续窗口映射工作。

投影变换其实就是将不同对的视锥体映射到标准设备坐标的过程,投影变换过程中实际上并未实际计算顶点的NDC坐标,而是在后面齐次除法中进行,不过投影变换的整个过程与之息息相关,应该说是作为一个目标。
mark

1 视锥体

一般而言,常用的视锥体有两种, 如下图所示。视锥体一般由6个剪裁平面决定,包括近剪裁面和远剪裁面
mark

2 统一设备坐标系 NDC

可以理解为一个立方体,中心点在中间,\(x,y,z\)方向的范围\([-1,1]\)(OpenGL中,在有些文档中描述为CVV,傻傻的分不清楚了,但是表达的意思是相同的),注意的是不同的API定义的NDC不尽相同,DirectX定义\(z\)范围为\([0,1]\),本文主要使用OpenGl的NDC坐标范围,不过整个推导过程相同。
|center|

3 设定

  1. 转换过程推导以OpenGl为准,也就是采用右手坐标系,观察方向位沿Z轴负方向
  2. 涉及的符号为不带符号数,比如下文中近邻面\(z\)坐标\(n\)大于远邻面\(f\)

4.平行投影

设观察空间中,视椎体的为\([l,r]\times[b,t]\times[f,n]\) ,其中$l < r \quad and \quad b < t \quad and \quad f < n \( ![|center|](http://ohzzlljrf.bkt.clouddn.com/blog/20161213/231230467.png) 平行视椎体 和NDC都是立方体,所以可以通过平移\)T(t)\(和缩放\)S(s)$ 实现 , 其过程如下图所示
\(T(t)\)将视椎体中心移动到坐标系中心,平移矩阵如下:

\[ T(t) = \begin{bmatrix} 1 & 0 & 0 &-\frac{l+r}{2}\\ 0 & 1 & 0 &- \frac{t+b}{2} \\ 0&0& 1& -\frac{n+f}{2} \\ 0&0&0&1 \end{bmatrix} \]

\(S(s)\) 将平移后视椎体的\((x,y,z)\)转换到\([-1,1]\)区间,

\[ S(s) = \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & 0\\ 0 & \frac{2 }{t-b} & 0 & 0 \\ 0&0& \frac{2}{n-f}& 0 \\ 0&0&0&1 \end{bmatrix} \]

所以转换矩阵

\[M_{oth} = S(s) T(t) \\ \\ = \begin{bmatrix} \frac{2}{r-l} & 0 & 0 & \frac{r+l}{r-l} \\ 0 & \frac{2 }{t-b} & 0 &\frac{t+b }{t-b} \\ 0&0& \frac{2}{n-f}& \frac{n+f}{n-f} \\ 0&0&0&1 \end{bmatrix} \]

5.透视投影

透视投影的特征就是投影线都会经过视点,也就是摄像机中心,一般在计算中会将视椎体的近平面\(z = n\)作为成像平面。投影矩阵可以直接通过投影关系以及视锥体和NDC区间的关系建立方程求教获得,可以参考Mathematics for 3D Game Programming and Computer Graphics 第五章 。不过这里采用另外一种方式,先将透视投影的视椎体转换为平面投影的视椎体,然后再利用平行投影的视椎体获得透视投影矩阵

5.1 透视关系

mark
假设空间中一点的坐标为\(P(p_x,p_y,p_z)\) ,其在$z = n \(上的投影点位\)q(q_x , q_y,n)$ , 根据比例关系可知:
$$
\left {
\begin{array}{lr}
q_x = \frac {n} {p_z} p_x \
q_y = \frac {n} {p_z} p_y \
q_z = n
\end{array}
\right.
$$

5.2 深度关系

上述过程可以实现将空间中点转换到2D图像中,但点\(q(q_x , q_y,n)\)\(z\) 保持为\(n\) , 实际上\(z\) 应该保持\([n,f]\)的区间,另一方面在光栅化过程中对\(\frac{1}{z}\)进行插值,所以\(z\)的变换函数应该是\(\frac{1}{z}\)的线性函数,假设\(z\)的变换函数为

\[q_z = \frac{a}{p_z} + b \]

\(z\)的区间映射关系\([n,f] \rightarrow [n,f]\)以得:

\[ \left \{ \begin{array}{lr} n = \frac{a}{n} + b \\ f = \frac{a}{f} + b \end{array} \right. \]

计算可得:

\[\left \{ \begin{array}{lr} a = -nf \\ b = n + f \end{array} \\ \right. \]

也就是说转换函数为

\[q_z = -\frac{nf}{p_z} + (n+f) \]

5.3 透视视锥体转换到平行视锥体

通过上面的推导,透视投影视椎体转换为平行投影视椎体的过程可以表达为:
$$
\left {
\begin{array}{lr}
q_x p_z = n p_x \
q_y p_z = n p_y \
q_z p_z = (n+f)p_z - nf \
p_z = p_z
\end{array}
\right.
$$
用齐次坐标表达以及转换过程:

\[\begin{bmatrix} q_x p_z \\ q_y p_z \\q_z p_z\\p_z \end{bmatrix} = \begin{bmatrix} q_x \\ q_y \\q_z \\1 \end{bmatrix} = \begin{bmatrix} np_x \\ np_y \\(n+f)p_z - nf \\ p_z \end{bmatrix} = \\ \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 &n+f & -fn \\ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} p_x \\ p_y \\p_z\\1 \end{bmatrix} \\ = M_{per \rightarrow oth} \begin{bmatrix} p_x \\ p_y \\p_z\\1 \end{bmatrix} \]

结合平行投影转换矩阵,获得透视投影转换矩阵:

\[M_{pre} = M_{oth}M_{per \rightarrow oth} \]

即:

\[ M_{pre} = \begin{bmatrix} \frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2 n}{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} \]

总结

上文即笔者总结的透视变换的数学推导过程,毕业后第一次写这样的文章,无非是想把这个过程完全理清楚是怎么回事。之前看的时候感觉没什么问题啊,但是在写的时候还是遇到一些问题,比如:

  1. Canonical view volume(CVV) 与 Normalized device Coordinaate(NDC)的关系,参考了几本书中的描述,其实都有点混淆,包括RTR中也会同时出现这两个概念,不过最终还是没弄明白怎么个区分方法,暂且当做一个概念吧
  2. \(z\)投影前后的计算公式,好几本书都是直接给出结论的,最后还是在Mathematics for 3D Game Programming and Computer Graphics中找到具体的流程,也可以参考另外一篇PPT

总之,本文会有很多描述不清晰或者弄错的地方,遇到的请帮忙指教。

posted @ 2016-12-14 00:31  RubbyZhang  阅读(4652)  评论(0编辑  收藏  举报