引言
請(qǐng)不要質(zhì)疑你的眼睛,文章的題目就是“3D圖形學(xué)基礎(chǔ)理論”。可能有人要疑惑了,作為一個(gè) iOS 開(kāi)發(fā)者為什么要來(lái)學(xué)習(xí)什么 3D 圖像學(xué)相關(guān)的東西,莫非這是要轉(zhuǎn)行的節(jié)奏。開(kāi)玩笑,怎么可能呢? 作為一個(gè)對(duì)技術(shù)有追求的人,怎么可能轉(zhuǎn)行。接下來(lái)讓我告訴你,為什么要學(xué)習(xí)3D圖形學(xué)的一些基礎(chǔ)理論。
- 1、遠(yuǎn)的先不說(shuō),就拿 iOS來(lái)說(shuō)。iOS 中在做一些基本動(dòng)畫(huà)開(kāi)發(fā)的過(guò)程中,相信絕大多數(shù)開(kāi)發(fā)者都是用過(guò) Core Graphics 框架中的 CGAffineTransform 這個(gè)類,雖然只是普通的平面動(dòng)畫(huà),但其實(shí)現(xiàn)原理和 3D 圖形學(xué)中的矩陣很類似。有多少開(kāi)發(fā)者想過(guò)其中的各種動(dòng)畫(huà)效果諸如縮放、旋轉(zhuǎn)、平移等是如何做到的?
- 2、當(dāng)然看到CGAffineTransform這個(gè)類,自然很容易想到CATransform3D這個(gè)類,這里既然是3D動(dòng)畫(huà),肯定和3D圖形學(xué)有關(guān)了。
- 3、再說(shuō)一個(gè)很火的名詞 AR,Apple 已經(jīng)讓一部分開(kāi)發(fā)者早先接觸了 ARKit 。ARKit 在接下來(lái)的一段時(shí)間中必然會(huì)很火。其實(shí)簡(jiǎn)單用 ARKit 實(shí)現(xiàn)一個(gè) AR 的 Demo 很簡(jiǎn)單,因?yàn)?蘋(píng)果封裝的 ARKit 十分簡(jiǎn)單易用。學(xué)習(xí)ARKit重點(diǎn)在于理解 ARKit 中各個(gè)類的關(guān)系、運(yùn)行原理。其中運(yùn)行原理就涉及到 3D 圖像學(xué)相關(guān)的知識(shí)。
- 4、說(shuō)到AR,自然會(huì)想到VR,VR全景視頻、全景圖片自然也會(huì)涉及到3D場(chǎng)景。
- 5、除此之外,還有 OpenGL ,當(dāng)然這個(gè)屬于相對(duì)比較片底層的技術(shù)了。iOS 中的各種控件的底層再底層都是基于其實(shí)現(xiàn)的。AR、VR技術(shù)都和其脫不了干系。筆者目前所在的公司,就有一套公司自己的OpenGL繪圖引擎,基于高德地圖在地圖上繪制各種各樣的炫酷模型。
- 6、還有蘋(píng)果的3D游戲開(kāi)發(fā)框架ScenceKit,毫無(wú)疑問(wèn)會(huì)涉及。
除了上述所講到的這些,3D 圖像學(xué)在實(shí)際開(kāi)發(fā)中涉及了還有很多。所以還是有必要稍稍了解下。學(xué)一些大學(xué)的高數(shù)知識(shí)。
一、3D成像原理
三維(3D)這個(gè)術(shù)語(yǔ)表示顯示的物體具有三個(gè)維度:寬度、高度和深度。如放在書(shū)桌上的紙張是一個(gè)二維物體,因?yàn)樗鼪](méi)有讓人感覺(jué)到所謂的深度。而一罐可口可樂(lè)放在桌上卻是有一定的深度。
幾個(gè)世紀(jì)以來(lái),藝術(shù)家已經(jīng)知道如何讓一幅畫(huà)看上去有深度。本質(zhì)上來(lái)說(shuō),畫(huà)其實(shí)是一個(gè)二維物體,只是顯示在計(jì)算機(jī)屏幕上的二維圖像或畫(huà)板上的水墨,但是卻可以提供深度的錯(cuò)覺(jué)。
有這樣一個(gè)公式:2D + 透視 = 3D 通過(guò)下面這幅圖,就可以看懂這個(gè)公式。我們可以看到 12 條線段組成了一個(gè)三維立方體的圖像。
實(shí)際上為了真正的看到 3D 圖像需要用兩個(gè)眼睛觀察一個(gè)物體或者為每只眼睛分別提供某個(gè)特定物體的一副獨(dú)立而又唯一角度的圖像。實(shí)際上人的每一只眼睛看到的是一副獨(dú)立的二維圖像,非常類似于每個(gè)視網(wǎng)膜(位于眼睛的后半部分)上顯示了一副臨時(shí)照片。隨后大腦對(duì)這兩幅圖像進(jìn)行圖像組合,在腦海中形成一副合成的 3D 圖片。中所周知現(xiàn)在的iPhone基本都是雙攝像頭,蘋(píng)果之所以早在 iPhone7 Plus 就增加了雙攝,其實(shí)那時(shí)已經(jīng)是在為AR埋下伏筆了。因?yàn)橥搜垡粯樱瑸榱俗R(shí)別 3D 場(chǎng)景,AR 需要雙攝像頭的硬件設(shè)備。那些不在雙攝像頭的硬件上運(yùn)行AR場(chǎng)景的在筆者認(rèn)為是偽 AR ,因?yàn)楣P者認(rèn)為AR的核心是在于場(chǎng)景的識(shí)別和分析,而這一點(diǎn)就要依賴于雙攝;再說(shuō)一個(gè)典型的例子,VR 應(yīng)用的頭盔,一般都會(huì)分為左右屏,左右屏的實(shí)時(shí)圖片或視頻場(chǎng)景是有一定視角差的,正式基于此,佩戴頭盔的玩家才能體驗(yàn)到 3D 場(chǎng)景。
單憑透視本身就足以創(chuàng)建三維的外觀,但是如果長(zhǎng)時(shí)間盯著上面的立方體看的話,會(huì)產(chǎn)生線條錯(cuò)亂的幻覺(jué)。我們?nèi)绻檬终谧∫恢谎劬θタ船F(xiàn)實(shí)世界,仍然是三維的,也不會(huì)產(chǎn)生錯(cuò)亂的幻覺(jué),這是因?yàn)楝F(xiàn)實(shí)世界中有關(guān)。如果上面的立方體通過(guò)紋理貼圖、光照效果處理等就不會(huì)再產(chǎn)生錯(cuò)亂的感覺(jué)。
二、3D編程基本原則
2.1 坐標(biāo)系統(tǒng)
笛卡爾坐標(biāo)系統(tǒng)相信很多人都了解,被熟悉的主要有 2D 和 3D 笛卡爾坐標(biāo)系。關(guān)于這兩個(gè)坐標(biāo)系統(tǒng)不用做過(guò)多解釋,很容易理解。這里我主要想說(shuō)兩個(gè)概念坐標(biāo)裁剪和視口。
- 坐標(biāo)裁剪
窗口(電腦屏幕)是以像素為單位度量的。開(kāi)始在窗口繪制點(diǎn)、線或形狀之前,必須告訴編程框架如何把制定的坐標(biāo)翻譯為屏幕坐標(biāo)。我們可以通過(guò)指定占據(jù)窗口的笛卡爾控件區(qū)域完成這個(gè)任務(wù),這個(gè)區(qū)域就稱為裁剪區(qū)域。如下圖顯示了兩種常見(jiàn)的裁剪區(qū)域。
- 視口: 把繪圖左邊映射到窗口坐標(biāo)
裁剪區(qū)域的寬度和高度很少和窗口的寬度或高度相匹配(以像素為單位)。因此,坐標(biāo)系統(tǒng)必須從笛卡爾坐標(biāo)系映射到物理屏幕像素坐標(biāo)。這個(gè)映射就是通過(guò)視口的設(shè)置來(lái)指定的。視口就是窗口內(nèi)部用于繪制裁剪區(qū)域的客戶端區(qū)域。視口簡(jiǎn)單的把裁剪區(qū)域映射到窗口的一個(gè)區(qū)域。通常視口被定義為整個(gè)窗口,但這并非是嚴(yán)格的。如下面兩幅圖所示,視口分別被定義為裁剪區(qū)域的兩倍、與裁剪區(qū)域相同的大小。
2.2 從3D到2D(投影)
不管我們覺(jué)得自己的眼睛看到的三維圖像有多么真實(shí),但是屏幕上的像素實(shí)際上是二維的。所以我們要理解的第一個(gè)概念是投影。通過(guò)指定投影,可以指定在窗口的視景體,并制定如何對(duì)它進(jìn)行變換。投影主要分為兩種:正投影和透視投影。
如下圖所示,兩種投影方式,一種是平行投影也叫作正投影,正投影的特點(diǎn)是所有的投影線都是平行的,另外一種則是透視投影,透視投影的特點(diǎn)是投影線是相交于一點(diǎn)的,相交于這個(gè)點(diǎn)叫做投影中心。這一點(diǎn)在現(xiàn)實(shí)生活中可以得到很好的驗(yàn)證,想想此刻你順著平行的火車軌道望去,會(huì)發(fā)現(xiàn)隨著距離的增加,火車的軌道原來(lái)越靠近。在后面我會(huì)專門(mén)抽出一個(gè)模塊來(lái)說(shuō)一下透視投影的幾何原理,這里暫時(shí)知道即可。
三、向量
3.1 向量基本介紹
說(shuō)道這里就涉及到一些數(shù)學(xué)知識(shí)了,不要害怕,我會(huì)結(jié)合實(shí)際的空間來(lái)說(shuō),高等數(shù)學(xué)中關(guān)于向量和矩陣的知識(shí)并不是那么的難。實(shí)際上作為開(kāi)發(fā)者的我們也只要掌握一些基礎(chǔ)的便足夠。
3D 笛卡爾坐標(biāo)系中的一個(gè)點(diǎn),是通過(guò)三個(gè)值如(x,y,z)來(lái)表示的。這三個(gè)值組合起來(lái)實(shí)際上表示兩個(gè)重要的值:方向
和數(shù)量
。如下圖所示的(X,Y,Z)實(shí)際上表示了一個(gè)方向,方向是朝箭頭方向。一個(gè)向量的數(shù)量就是這個(gè)向量的長(zhǎng)度。對(duì)于 x 軸向量(1,0,0)來(lái)說(shuō),向量長(zhǎng)度是 1。我們把長(zhǎng)度為 1 的向量稱為單位向量。
OpenGL 中的 math3d 庫(kù)有這樣的兩個(gè)數(shù)據(jù)類型M3DVector3f 和 M3DVector4f 。前者是一個(gè)三維向量(x,y,z);后者是一個(gè)四維向量(x,y,z,w),典型情況下 w 值為 1.0 ,x、y、z 值通過(guò)除以 w 進(jìn)行縮放。明明就是 3D 圖形學(xué),又不是 4D 圖像學(xué),為何要使用 4 個(gè)分量來(lái)表示一個(gè)向量 ?之所以這樣做是因?yàn)?3D 頂點(diǎn)變化是要乘以一個(gè) 4 * 4 的變換矩陣。有個(gè)規(guī)則是必須用一個(gè)四分量向量乘以一個(gè) 4 * 4 的矩陣,后面講到矩陣時(shí)會(huì)詳細(xì)說(shuō)明。
3.2 向量的運(yùn)算
向量可以進(jìn)行加法、減法運(yùn)算,也可以簡(jiǎn)單的通過(guò)減法、減法進(jìn)行縮放。然而這里主要說(shuō)關(guān)于向量有趣的兩個(gè)運(yùn)算: 點(diǎn)乘和叉乘。
- 點(diǎn)乘
兩個(gè)三分量之間的點(diǎn)乘運(yùn)算將得到一個(gè)標(biāo)量(只有一個(gè)值),它表示兩個(gè)向量之間夾角對(duì)應(yīng)的三角函數(shù) Cos 值。 - 叉乘
兩個(gè)向量之間叉乘所得的結(jié)果是另外一個(gè)向量,這個(gè)新向量與原來(lái)兩個(gè)向量定義的平面垂直。和點(diǎn)乘不同,在進(jìn)行叉乘運(yùn)算的時(shí)候向量的順序非常重要,不同的叉乘順序會(huì)得到兩個(gè)方向相反的向量。
四、矩陣及其空間變化
4.1 理解場(chǎng)景變化
4.1.1 視覺(jué)坐標(biāo)
視覺(jué)坐標(biāo)是相對(duì)于觀察則而言的,無(wú)論進(jìn)行何種變換,都可以將它視為絕對(duì)的屏幕坐標(biāo)。這樣,視覺(jué)坐標(biāo)就表示一個(gè)虛擬固定的坐標(biāo)系,通常作為參考坐標(biāo)系使用。
4.1.2 兩種變換
在說(shuō)矩陣之前,先來(lái)說(shuō)一下3D場(chǎng)景中的一些變化。關(guān)于變化,主要有兩種變換視圖變換和模型變換。
- 視圖變換
所謂的視圖就是觀察者或相機(jī)的位置。視圖變換允許我們把觀察點(diǎn)放置在任何希望的位置,允許在任何方向上觀察。確定視圖變換就像在場(chǎng)景中放置照相機(jī)并讓它指定某個(gè)方向。
總的來(lái)說(shuō)在任何其他模型變換之前,必須先進(jìn)行視圖變換。這是因?yàn)閷?duì)視覺(jué)坐標(biāo)系而言,視圖變化就移動(dòng)了當(dāng)前的工作坐標(biāo)系,后續(xù)的一切變換隨后都是基于新調(diào)整的坐標(biāo)系進(jìn)行的。 - 模型變換
模型變換用于操作模型和其中的特定的對(duì)象。模型變換通常是現(xiàn)將模型對(duì)象移動(dòng)到需要的位置上,然后再對(duì)他們進(jìn)行旋轉(zhuǎn)和移動(dòng)。就拿先旋轉(zhuǎn)后平移和先平移后旋轉(zhuǎn)來(lái)說(shuō)得到的是兩種不同情況。如下圖所示,無(wú)論是先執(zhí)行旋轉(zhuǎn)還是平移,后一個(gè)操作(旋轉(zhuǎn)或平移)都是基于第一個(gè)操作結(jié)果產(chǎn)生的坐標(biāo)系進(jìn)行下一步操作。
4.2模型視圖矩陣
與其說(shuō)矩陣的幾何意義這么生澀難懂,不如說(shuō)的是矩陣在幾何中到底是有什么作用呢?一般來(lái)說(shuō),方陣可以描述任意的線性變換
。也就說(shuō),在幾何當(dāng)中,我們用矩陣表示幾何體的空間變換。比如我們?cè)诔绦蛑谐S玫钠揭啤⑿D(zhuǎn)、縮放等等
模型視圖矩陣是一個(gè) 4 * 4 矩陣,它表示一個(gè)變化后的坐標(biāo)系
,可以用來(lái)放置對(duì)象和確定對(duì)象的位置。頂點(diǎn)作為一個(gè)單列矩陣(也就是一個(gè)響亮)的形式來(lái)表示,并乘以一個(gè)模型視圖矩陣來(lái)獲得一個(gè)相對(duì)視覺(jué)坐標(biāo)系的經(jīng)過(guò)變換的新坐標(biāo)。
如下代碼所形成的矩陣計(jì)算所示,一個(gè)包含單個(gè)頂點(diǎn)數(shù)據(jù)的矩陣乘以模型視圖矩陣后得到新的視覺(jué)坐標(biāo)。頂點(diǎn)數(shù)據(jù)實(shí)際是4個(gè)數(shù)據(jù),其中包含一個(gè)附加值 w ,它表示一個(gè)縮放因子,默認(rèn)情況下是 1.0 ,一般情況下很少去改動(dòng)。
[x] [a b c d] [x0]
[y] [a b c d] [y0]
[z] * [a b c d] = [z0]
[w] [a b c d] [w0]
接下來(lái)我們就來(lái)詳細(xì)說(shuō)明,上面是矩陣計(jì)算是怎么做到:將一個(gè)頂點(diǎn)乘以一個(gè)矩陣來(lái)對(duì)它進(jìn)行變換。
4.2.1 矩陣構(gòu)造
矩陣的前三列的前三個(gè)元素只是方向向量,表示空間上 x y z 軸上的方向(在這里用向量來(lái)表示一個(gè)方向)。一般情況下這三個(gè)向量之前總是成 90 度夾角,并且通常為單位長(zhǎng)度。數(shù)學(xué)書(shū)中中稱之為標(biāo)準(zhǔn)正交(向量為單位長(zhǎng)度)和正交(向量不是單位長(zhǎng)度)。如下圖對(duì)矩陣進(jìn)行了標(biāo)注。另外要注意下圖的矩陣最后一行都為 0 ,只有一個(gè)元素為 1。
如果有一個(gè)包含不同坐標(biāo)系的位置和方向的 4 * 4 矩陣,然后用一個(gè)表示原來(lái)坐標(biāo)系的向量(表示為一個(gè)矩陣或向量)乘以這個(gè)矩陣,得到的結(jié)果是一個(gè)轉(zhuǎn)換到新坐標(biāo)系下的新向量。這就意味著,空間中任何位置和方向都可以由一個(gè) 4 * 4矩陣唯一確定。如果一個(gè)對(duì)象的所有向量乘以這個(gè)矩陣,那么我們將得到整個(gè)對(duì)象變換到的空間中的位置和方向。
4.2.2 單位矩陣
在講矩陣的變化之前,先簡(jiǎn)單說(shuō)下單位矩陣的概念。將一個(gè)向量乘以一個(gè)單位矩陣,就相當(dāng)于用這個(gè)向量乘以 1 ,不會(huì)發(fā)生任何變化。單位矩陣中除了一條對(duì)角線上的元素為 1,其他元素全為 0 。
4.3 矩陣變化操作
矩陣的變化操作主要分為縮放、平移、旋轉(zhuǎn)。為了更好的理解矩陣的變化操作,以及矩陣是怎么形成的,筆者就直接從縮放講起。把縮放講清除,之后的平移以及旋轉(zhuǎn)都是按照同樣的套路進(jìn)行推導(dǎo)。
4.3.1 縮放
為了更好的理解縮放,我先從 2D 環(huán)境說(shuō)起,之后在延伸到3D環(huán)境。
如果沿著坐標(biāo)軸進(jìn)行縮放,那么每一個(gè)坐標(biāo)軸都有縮放因子,所以2D環(huán)境下有兩個(gè)縮放因子Kx和Ky,那么基向量p和q根據(jù)縮放因子的影響,我們可以得到下面公式。
根據(jù)變化,可以得到在2D環(huán)境下的縮放矩陣。如下所示:
同理,通過(guò)2D環(huán)境下的縮放矩陣,我們可以得到3D環(huán)境下的縮放矩陣。
4.3.2 平移
一個(gè)平移矩陣僅僅是將頂點(diǎn)沿著 3 個(gè)左邊軸中的一個(gè)或者多個(gè)進(jìn)行移動(dòng)。這個(gè)應(yīng)該是很好理解的,這里就不做過(guò)多解釋。列如在 OpenGL的 math3d 庫(kù)中,我們就可以通過(guò)m3dTranslationMatrix44 函數(shù)使用矩陣直接做平移操作。
4.3.3 旋轉(zhuǎn)
關(guān)于旋轉(zhuǎn)操作的矩陣實(shí)際上推導(dǎo)起來(lái)稍稍有些麻煩,需要通過(guò)大量的圖解和注釋來(lái)說(shuō)明。筆者感覺(jué)沒(méi)必要進(jìn)行詳細(xì)的推導(dǎo),畢竟我們不是專業(yè)研究數(shù)學(xué)的,只要知旋轉(zhuǎn)矩陣形成過(guò)程和縮放以及平移的原理是一樣,只是推到起來(lái)會(huì)更麻煩些。這里我就簡(jiǎn)單的列出一些推到結(jié)果。當(dāng)然,有興趣的同學(xué)可以自行研究下。
五、關(guān)于CGAffineTransform的實(shí)現(xiàn)
在Core Graphics框架圖形繪制的時(shí)候,經(jīng)常會(huì)有對(duì)圖形進(jìn)行平移、縮放、旋轉(zhuǎn)這樣的要求。那么我們?cè)撊绾螌?shí)現(xiàn)呢?這就需要Core Graphics框架中的CGAffineTransform(矩陣)這個(gè)結(jié)構(gòu)體來(lái)進(jìn)行實(shí)現(xiàn)了。下面我們就對(duì)CGAffineTransform這個(gè)矩陣結(jié)構(gòu)體,進(jìn)行簡(jiǎn)單的說(shuō)明。
// CGAffineTransform結(jié)構(gòu)體樣式
struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
齊次坐標(biāo)概念
所謂的其次坐標(biāo)就是把一個(gè)圖形用一個(gè)三維矩陣表示,其中第三列總是(0,0,1),用來(lái)作為坐標(biāo)系的標(biāo)準(zhǔn)。也就是z軸,是不發(fā)生改變的。
|a b 0|
|c d 0|
|tx ty 1|
接下來(lái)就來(lái)看看二維空間中的點(diǎn)坐標(biāo)是如和借助齊次坐標(biāo)進(jìn)行仿射變化。具體運(yùn)算原理如下:
|a b 0|
[X,Y, 1] |c d 0| = [aX + cY + tx bX + dY + ty 1] ;
|tx ty 1|
運(yùn)算原理就是如此簡(jiǎn)單。CGAffineTransform的平移、旋轉(zhuǎn)、縮放操作,都是借助這個(gè)公式進(jìn)行計(jì)算的,只不過(guò)平移、旋轉(zhuǎn)、縮放只不過(guò)是其中的一些特殊情況而已。
CGAffineTransform的平移、旋轉(zhuǎn)、縮放變換。
- 平移變換
條件: a = d = 1 ,b = c = 0
|1 0 0|
[X,Y, 1] |0 1 0| = [X + tx , Y + ty , 1] ;
|tx ty 1|
坐標(biāo)由 [X,Y, 1] 變成了 [X + tx , Y + ty , 1],與原坐標(biāo)相比,z軸沒(méi)發(fā)生任何的改變,x 軸方向平移了 tx 個(gè)單位, y 軸方向平移了 ty 個(gè)單位。平移對(duì)應(yīng)Core Graphics框架中的CGAffineTransformMakeTranslation(CGFloat tx,CGFloat ty)
API。
- 縮放變換
條件: b = c = 0 ,tx = ty = 0。
|a 0 0|
[X,Y, 1] |0 d 0| = [aX , dY ,1] ;
|0 0 1|
坐標(biāo)由[X,Y, 1]變?yōu)?[aX , dY ,1] ,X軸擴(kuò)大了 a 倍,Y 軸擴(kuò)大了 d 倍。縮放對(duì)應(yīng)Core Graphics框架中的 GAffineTransformMakeScale(CGFloat sx, CGFloat sy)
API。
- 旋轉(zhuǎn)變換
條件 : tx=ty=0,a=cos?,b=sin?,c=-sin?,d=cos?
|cos? sin? 0|
[X,Y, 1] |-sin? cos? 0| = [Xcos? - Ysin? , Xsin? + Ycos? , 1] ;
|tx ty 1|
其中 ? 是旋轉(zhuǎn)的角度,逆時(shí)針為正,順時(shí)針為負(fù)。旋轉(zhuǎn)對(duì)應(yīng)Core Graphics框架中的 CGAffineTransformMakeRotation(CGFloat angle)
API。
六、關(guān)于CATransform3D實(shí)現(xiàn)
回想一下前面所說(shuō)的矩陣的相關(guān)知識(shí),如下圖是 3D 仿射變化矩陣,和我們前面在矩陣那一塊講的結(jié)果一致。
先來(lái)看一下這個(gè)結(jié)構(gòu)體長(zhǎng)什么樣。
//CATransform3D基本結(jié)構(gòu)體
struct CATransform3D{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
下面的代碼是 CATransform3D 實(shí)現(xiàn) 3D 效果的簡(jiǎn)單使用。
-(CATransform3D)getTransForm3DWithAngle:(CGFloat)angle{
CATransform3D transform =CATransform3DIdentity;//獲取一個(gè)標(biāo)準(zhǔn)默認(rèn)的CATransform3D仿射變換矩陣
transform.m34=1.0/-2000;//透視效果
transform=CATransform3DRotate(transform,angle,0,1,0);//獲取旋轉(zhuǎn)angle角度后的rotation矩陣。
return transform;
}
上面最重要的是m34這個(gè)屬性,CATransform3DRotate獲取的旋轉(zhuǎn)如果之前聯(lián)合的transform不支持透視,那在x、y軸上做旋轉(zhuǎn)是只有frame放大縮小的變化,我們需要的是在旋轉(zhuǎn)的時(shí)候要使得離視角近的地方放大,離視角遠(yuǎn)的地方縮小,就是所謂的視差來(lái)形成3D的效果。
根據(jù)前面的講解,通過(guò)上圖不難看到 m34 實(shí)際上影響了 z 軸方向的translation(移動(dòng)) ,所以實(shí)際開(kāi)發(fā)中為了實(shí)現(xiàn) 3D 效果,我們只需要簡(jiǎn)單控制 m34 這個(gè)參數(shù)即可。除了 m34 這個(gè)參數(shù)之外,另外幾個(gè)參數(shù)各有其用,有興趣的可以看下這篇文章。另外, 要知道,m34= -1/D, 默認(rèn)值是0,也就是說(shuō)D無(wú)窮大,這意味layer in projection plane(投射面)和 layer in world coordinate 重合了。D越小透視效果越明顯。所謂的D,是eye(觀察者)到投射面的距離。
結(jié)語(yǔ)
本文顯示介紹了 3D 成像原理、3D編程基本原則,之后介紹了向量和矩陣,矩陣這一塊對(duì)平移、旋轉(zhuǎn)、縮放進(jìn)行了簡(jiǎn)單的推到。最后基于前面所講的這些基礎(chǔ)知識(shí)和 iOS 中的CGAffineTransform、CATransform3D做了簡(jiǎn)單的關(guān)聯(lián)和解釋。
該篇文章僅僅只能作為 3D 圖像學(xué)的簡(jiǎn)單入門(mén),對(duì)于向接觸 AR、VR等相關(guān) 3D 方向的開(kāi)發(fā)者來(lái)說(shuō),這些都是工作必備的知識(shí)。歡迎指正!!!!!