OpenGL實(shí)例教程10:透視投影
為什么需要透視投影?
模型都是3D的,但屏幕是2D的。如何將3D空間投影到2D平面,還能保持深度的視覺效果?在OpenGL中,采用透視投影矩陣作用頂點(diǎn)來實(shí)現(xiàn),即完成縮放、選擇、位移之后,進(jìn)行透視投影的操作。就像下面的鐵軌,越遠(yuǎn)的地方,在2D屏幕上占比越小。

透視投影參數(shù)介紹
生成透視投影變換需要4個(gè)參數(shù):
寬高比:矩形區(qū)域的寬度和高度之間的比率
垂直視場(chǎng)角:相機(jī)的垂直角度,通過它來觀察世界
近/遠(yuǎn)Z平面:裁剪離相機(jī)太近/遠(yuǎn)的物體

寬高比:
標(biāo)準(zhǔn)化空間的X,Y坐標(biāo)都是-1到1之間(這里的數(shù)值是抽象的概念,將代表精度的分配)
電腦屏幕往往都寬度大于高度
標(biāo)準(zhǔn)化后,X,Y坐標(biāo)都是-1到1,但刻度含義不同
垂直視場(chǎng)角:
屏幕大小是固定不變的
左圖:值大,顯示范圍大,分配給物體的屏幕區(qū)域就小(模擬縮?。?/p>
右圖:值小,顯示范圍小,分配給物體的屏幕區(qū)域就大(模擬放大)

近/遠(yuǎn)Z平面:
標(biāo)準(zhǔn)空間Z坐標(biāo)是-1到1之間,需要映射到近平面到遠(yuǎn)平面之間的距離
透視矩陣
需要一個(gè)矩陣,能完成透視投影的變化:

矩陣的推導(dǎo)過程如下:
1、寬高比( ar:aspect ratio)計(jì)算如下:
寬高比(ar) =屏幕寬/ 屏幕高
為方便計(jì)算,高度設(shè)為2,這意味著寬度正好是ar的兩倍。如果把相機(jī)放在原點(diǎn),從相機(jī)背后看這個(gè)區(qū)域,會(huì)看到:

2、現(xiàn)在讓從“側(cè)面”看看,通過垂直視場(chǎng)角計(jì)算相機(jī)到投影平面的距離(由角度alpha表示):

3、計(jì)算Y的投影坐標(biāo):

4、同樣的方法可以計(jì)算X的投影坐標(biāo):

5、將X,Y的投影坐標(biāo)映射到標(biāo)準(zhǔn)化坐標(biāo)[-1,1]:

6、現(xiàn)在需要一個(gè)矩陣,第一行為(a,b,c,d),能滿足下面的運(yùn)算:

可以選擇‘b’和‘d’為0,但無法找到合適的‘a(chǎn)’和‘c’。OpenGL采用的解決方案是將轉(zhuǎn)換分為兩步:
1、與投影矩陣相乘;

2、與Z值做除法(GPU自動(dòng)完成)。
每個(gè)頂點(diǎn)Z的值都可能不同,所以不能把它放到變換矩陣中(uniform變量),在步驟6中,將自動(dòng)除以Z,那么所有的頂點(diǎn)Z值都將變?yōu)?,即都丟失了原始值。為了解決這個(gè)問題,將用W保存Z值。
7、將Z的投影坐標(biāo)映射到標(biāo)準(zhǔn)化坐標(biāo)[-1,1],并且需要考慮近/遠(yuǎn)平面的影響:
需要選擇矩陣第三行的值,以便在系統(tǒng)自動(dòng)除以w后,任何在可視范圍內(nèi)的Z值(即NearZ <= Z <= FarZ)將被映射到[-1,1]范圍。
由一般函數(shù)表示(變換矩陣第三行將起到等效的作用):??(??)=?????+??
經(jīng)過透視除法后:??+??/??
當(dāng)Z等于近平面時(shí),結(jié)果一定是-1,當(dāng)Z等于遠(yuǎn)平面時(shí),結(jié)果一定是1。因此:

8、現(xiàn)在需要選擇矩陣的第三行作為向量(a b c d),它需要滿足:

可以將` a `和` b `設(shè)置為零。然后A值可以變成` c `, B值可以變成` d `(因?yàn)橐阎猈是1)。
因此,最終的變換矩陣為:

透視投影代碼實(shí)現(xiàn)
直接調(diào)用庫即可,無需自己實(shí)現(xiàn),庫的主要代碼如下:
Opengl應(yīng)用程序代碼
運(yùn)行效果
