Perspective Projection
頂點數據經過模型變換、相機變換轉換到觀察空間,之后渲染系統引入視椎體的概念,並通過投影變換將視椎體轉換到統一設備坐標系中,方便剪裁和后續窗口映射工作。
投影變換其實就是將不同對的視錐體映射到標准設備坐標的過程,投影變換過程中實際上並未實際計算頂點的NDC坐標,而是在后面齊次除法中進行,不過投影變換的整個過程與之息息相關,應該說是作為一個目標。

1 視錐體
一般而言,常用的視錐體有兩種, 如下圖所示。視錐體一般由6個剪裁平面決定,包括近剪裁面和遠剪裁面

2 統一設備坐標系 NDC
可以理解為一個立方體,中心點在中間,\(x,y,z\)方向的范圍\([-1,1]\)(OpenGL中,在有些文檔中描述為CVV,傻傻的分不清楚了,但是表達的意思是相同的),注意的是不同的API定義的NDC不盡相同,DirectX定義\(z\)范圍為\([0,1]\),本文主要使用OpenGl的NDC坐標范圍,不過整個推導過程相同。

3 設定
- 轉換過程推導以OpenGl為准,也就是采用右手坐標系,觀察方向位沿Z軸負方向
- 涉及的符號為不帶符號數,比如下文中近鄰面\(z\)坐標\(n\)大於遠鄰面\(f\)
4.平行投影
設觀察空間中,視椎體的為\([l,r]\times[b,t]\times[f,n]\) ,其中$l < r \quad and \quad b < t \quad and \quad f < n \(  平行視椎體 和NDC都是立方體,所以可以通過平移\)T(t)\(和縮放\)S(s)$ 實現 , 其過程如下圖所示
\(T(t)\)將視椎體中心移動到坐標系中心,平移矩陣如下:
\(S(s)\) 將平移后視椎體的\((x,y,z)\)轉換到\([-1,1]\)區間,
所以轉換矩陣
5.透視投影
透視投影的特征就是投影線都會經過視點,也就是攝像機中心,一般在計算中會將視椎體的近平面\(z = n\)作為成像平面。投影矩陣可以直接通過投影關系以及視錐體和NDC區間的關系建立方程求教獲得,可以參考Mathematics for 3D Game Programming and Computer Graphics 第五章 。不過這里采用另外一種方式,先將透視投影的視椎體轉換為平面投影的視椎體,然后再利用平行投影的視椎體獲得透視投影矩陣。
5.1 透視關系

假設空間中一點的坐標為\(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\)的變換函數為
由\(z\)的區間映射關系\([n,f] \rightarrow [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.
$$
用齊次坐標表達以及轉換過程:
結合平行投影轉換矩陣,獲得透視投影轉換矩陣:
即:
總結
上文即筆者總結的透視變換的數學推導過程,畢業后第一次寫這樣的文章,無非是想把這個過程完全理清楚是怎么回事。之前看的時候感覺沒什么問題啊,但是在寫的時候還是遇到一些問題,比如:
- Canonical view volume(CVV) 與 Normalized device Coordinaate(NDC)的關系,參考了幾本書中的描述,其實都有點混淆,包括RTR中也會同時出現這兩個概念,不過最終還是沒弄明白怎么個區分方法,暫且當做一個概念吧
- \(z\)投影前后的計算公式,好幾本書都是直接給出結論的,最后還是在Mathematics for 3D Game Programming and Computer Graphics中找到具體的流程,也可以參考另外一篇PPT
總之,本文會有很多描述不清晰或者弄錯的地方,遇到的請幫忙指教。
