齊次坐標(biāo)在計(jì)算機(jī)圖形中的應(yīng)用

原文: CC老師
著作所屬權(quán)歸該作者所有,任何形式轉(zhuǎn)載請(qǐng)聯(lián)系作者并注明原文出處.

提示: 齊次坐標(biāo)是在學(xué)習(xí)OpenGL ES 初期百思不得其解的地方. 希望這篇文章能夠給你幫助.此文將蘋果由CoreAnimation 透視投影為引子.為什么需要用4*4矩陣來描述坐標(biāo)變換?

核心動(dòng)畫蘋果文檔-透視投影效果的設(shè)置

The sublayerTransform property defines additional transformations that apply only to the sublayers and is used most commonly to add a perspective visual effect to the contents of a scene.

Transforms work by multiplying coordinate values through a matrix of numbers to get new coordinates that represent the transformed versions of the original points. Because Core Animation values can be specified in three dimensions, each coordinate point has four values that must be multiplied through a four-by-four matrix, as shown in Figure 1-7. In Core Animation, the transform in the figure is represented by the CATransform3D type. Fortunately, you do not have to modify the fields of this structure directly to perform standard transformations. Core Animation provides a comprehensive set of functions for creating scale, translation, and rotation matrices and for doing matrix comparisons. In addition to manipulating transforms using functions, Core Animation extends key-value coding support to allow you to modify a transform using key paths. For a list of key paths you can modify, see CATransform3D Key Paths.

SublayerTransform屬性定義了僅應(yīng)用于子層的其他轉(zhuǎn)換,并且最常用于向場(chǎng)景內(nèi)容添加透視視覺效果。
轉(zhuǎn)換的工作原理是將坐標(biāo)值乘以一個(gè)數(shù)字矩陣,得到表示原始點(diǎn)轉(zhuǎn)換版本的新坐標(biāo)。因?yàn)楹诵膭?dòng)畫值可以在三維中指定,所以每個(gè)坐標(biāo)點(diǎn)有四個(gè)值,必須通過一個(gè)四乘四的矩陣相乘,如圖1-7所示。在核心動(dòng)畫中,圖形中的變換由CatTransform3D類型表示。幸運(yùn)的是,您不必直接修改這個(gè)結(jié)構(gòu)的字段來執(zhí)行標(biāo)準(zhǔn)轉(zhuǎn)換。核心動(dòng)畫為創(chuàng)建比例、平移和旋轉(zhuǎn)矩陣以及進(jìn)行矩陣比較提供了一套全面的功能。除了使用函數(shù)操縱變換之外,核心動(dòng)畫還擴(kuò)展了關(guān)鍵值編碼支持,允許您使用關(guān)鍵路徑修改變換。有關(guān)可以修改的關(guān)鍵路徑列表,請(qǐng)參見CatTransform3D關(guān)鍵路徑。

透視投影
  • 蘋果文檔關(guān)于單元矩陣,平移,縮放,圍繞x,y,z軸旋轉(zhuǎn)的矩陣


    矩陣變化

注意觀察,你會(huì)發(fā)現(xiàn)為什么透視投影中3D場(chǎng)景,x,y,z需要W分量了? 接下來我們帶著這疑惑看看蘋果官方文檔遺留下的問題進(jìn)行探討.

透視投影:


透視投影

為什么要將3D的笛卡爾坐標(biāo)轉(zhuǎn)換成四維齊次坐標(biāo),這樣有2個(gè)主要好處:

  1. 進(jìn)一步完成透徹變換
  2. 這樣可以使用線性變換來實(shí)現(xiàn)模型的平移.

如果使用四維坐標(biāo)系統(tǒng),就可以通過矩陣乘法完成所有的旋轉(zhuǎn),平移,縮放和投影的變換操作.

什么是齊次坐標(biāo)?

三維數(shù)據(jù)可以通過三維向量與3*3矩陣的乘法操作,來完成縮放和旋轉(zhuǎn)的線性變換.

在大多數(shù)3D工作中,我們參照的依據(jù)是幾何學(xué)中的三維空間(X, Y, Z)。
但在某些情況下,參照投影幾何更適用,除了 X, Y, Z 分量外,增加一個(gè) W 分量,這個(gè)四維空間叫做“投影空間”,在四維空間中的坐標(biāo)叫“齊次坐標(biāo)”。為了達(dá)到3D軟件的目的,“投影的” 和 “齊次的” 可以理解為 "4D"。

注意: 四元數(shù)和齊次坐標(biāo)非常類似,都是四維向量.通常也是通過(x,y,z,w)來表示,但是四元坐標(biāo)和齊次坐標(biāo)是不同的概念,并且適用領(lǐng)域也不一樣. 簡(jiǎn)單說,四元數(shù)與齊次坐標(biāo)沒有任何關(guān)系.

  • 齊次坐標(biāo)是計(jì)算機(jī)圖形學(xué)的重要手段之一,它既能夠用來明確區(qū)分向量和點(diǎn),同時(shí)也更易用于進(jìn)行仿射(線性)幾何變換.
  • 四元數(shù)本質(zhì)上是一種高階復(fù)數(shù),是一個(gè)四維空間,相對(duì)于復(fù)數(shù)的二維空間。

齊次坐標(biāo)在2D場(chǎng)景中應(yīng)用

想象投影儀在一個(gè)屏幕上投影一張2D的圖片,這時(shí)我們就能非??焖俚睦斫釾,Y分量的意義所在.


圖1

看到這張圖,我們就可以感受到投影儀與屏幕之間的距離,而這個(gè)距離就是w分量.


圖2

w分量就是投影儀與屏幕的距離在開發(fā)者角度就是觀察者與屏幕直接的距離.

圖3

那么w分量有什么作用了?
首先我們來到這樣的場(chǎng)景中,如果我們移動(dòng)投影儀的位置,就是調(diào)整觀察者的位置.來增加或減少w分量,那么投影出的2D圖片會(huì)發(fā)生什么變換? 是不是如果投影儀靠近屏幕,2D圖片縮小; 如果投影儀遠(yuǎn)離屏幕,2D圖片就會(huì)放大; 此時(shí)通過調(diào)整觀察者的位置,來實(shí)現(xiàn)放大與縮小的目的.W分量,會(huì)影響投影出來的圖片大小;

齊次坐標(biāo)在3D場(chǎng)景的應(yīng)用

在 3D 場(chǎng)景下的 W 分量和 2D 場(chǎng)景是一樣的.都是當(dāng) w 增大,坐標(biāo)被拉伸; W 縮小,則坐標(biāo)被壓縮. W 對(duì)于 3D 坐標(biāo)可以實(shí)現(xiàn)縮放變換.

通常,我們?cè)趫D形開發(fā)中,都會(huì)建議無論什么時(shí)候?qū)?D坐標(biāo)轉(zhuǎn)換為4D坐標(biāo)時(shí),讓 w = 1; 那么為什么會(huì)給出這樣的建議了? 因?yàn)楫?dāng)縮放坐標(biāo)為1時(shí),坐標(biāo)不會(huì)放大或者縮小.保持原有的大小;所以當(dāng)w = 1,不會(huì)影響X,Y,Z分量的值;

所以,在3D開發(fā)過程中,我們會(huì)認(rèn)為坐標(biāo)中w = 1 是正確的. 因?yàn)槿绻秩臼褂肳>1的坐標(biāo),則你的每個(gè)3D圖形都會(huì)放大,反之,W<1的坐標(biāo)中,3D物體會(huì)變小.如果渲染時(shí),W = 0,則你的程序會(huì)崩潰,為什么? 因?yàn)橛?jì)算透視除法時(shí),除數(shù)為0; 如果 W < 0, 則渲染的圖形會(huì)上下水平翻轉(zhuǎn).

但是在數(shù)學(xué)的角度, w = 1 不做強(qiáng)制要求. 使用齊次坐標(biāo)時(shí),w = 1 的目的僅僅是為了用于計(jì)算計(jì)算機(jī)圖形學(xué)中的投影轉(zhuǎn)換.

所以,你可以看到蘋果文檔中,關(guān)于旋轉(zhuǎn),平移,縮放等的w = 1;


矩陣變化

數(shù)學(xué)原理

圖3

假設(shè),在屏幕3米處設(shè)置一個(gè)投影儀,投影出一個(gè)點(diǎn)(15,21)在2D圖像中,相應(yīng)的投影坐標(biāo)中的向量為(X,Y,W) = (15,21,3);

如果此時(shí),你推動(dòng)投影儀靠近屏幕,直到投影儀與屏幕之間的距離為1米;那么越靠近屏幕投影,投影的圖像越小. 投影儀靠近了3倍,因此圖像則縮小了3倍; 如果我們將x,y,w分量都除以3,則得到一個(gè)新的向量 w = 1;

圖4

圖5

此時(shí)投影出來的點(diǎn)在坐標(biāo)中的位置改變成(5,7,1);

這就是系統(tǒng)如果將坐標(biāo)從不規(guī)范的齊次坐標(biāo)轉(zhuǎn)換成一個(gè)規(guī)范齊次坐標(biāo)的方法:所有分量除以w,2D和3D場(chǎng)景下同樣適用.通過向量乘以W的倒數(shù),來實(shí)現(xiàn)向量的所有分量除以w.

例如,如下3D場(chǎng)景下的計(jì)算

圖5
  • 代碼實(shí)現(xiàn):
//齊次坐標(biāo)
vec4 vertex1(10,20,30,5);
//將坐標(biāo)規(guī)范成w = 1
vec4 vertex2 = (1.0/vertex1.w) * vertex1;

齊次坐標(biāo)在計(jì)算機(jī)圖形學(xué)的應(yīng)用

齊次坐標(biāo)實(shí)現(xiàn)3D坐標(biāo)中的轉(zhuǎn)換矩陣

三維數(shù)據(jù)可以通過三維向量與 3*3 矩陣的乘法操作,來完成縮放和旋轉(zhuǎn)的線性變換. 但是對(duì)于三維笛卡爾坐標(biāo)的平移操作是無法通過與 3*3 矩陣的乘法操作來完成. 我們還需要一個(gè)額外的向量,將(0,0,0)移動(dòng)到另外一個(gè)位置,這一步叫做仿射變換(affine transformation),它不屬于線性變換. 線性變換的規(guī)則,就是它總是將(0,0,0)映射到(0,0,0).因?yàn)榧尤肓诉@個(gè)額外的運(yùn)算過程,我們將無法在利用線性變換的各種優(yōu)勢(shì). 例如將多個(gè)變換過程合成一次變換.

所以我們找到了一個(gè)方法,就是通過線性變換來表達(dá)平移過程,就是將數(shù)據(jù)置于四維坐標(biāo)空間中,仿射變換就回歸到一種簡(jiǎn)單的線性變換. 也就是我們可以直接使用4*4矩陣的乘法來完成模型的移動(dòng)操作.

透視投影

齊次坐標(biāo)在處理矩陣變化是,第四維的W分量通常不會(huì)發(fā)生變換. 從3D轉(zhuǎn)化到4D,只需要將w = 1,并且經(jīng)過變換矩陣處理后,W 分量的值任然為1. 這意味著我們可以忽略W分量即可轉(zhuǎn)換回3D坐標(biāo). 但是需要注意的投影矩陣則會(huì)影響W 分量

齊次坐標(biāo)實(shí)現(xiàn)透視投影

在3D世界,物體距離相機(jī)越遠(yuǎn)看起來就越小,這個(gè)現(xiàn)象叫做透視. 比如下圖,在鏡頭中,如果貓距離相機(jī)足夠近,遠(yuǎn)處的大山看起來比貓小.


圖6

下面看一個(gè)透視例子,通過投影矩陣變換到齊次坐標(biāo)。


圖7

注意投影矩陣是怎樣用 Z 分量改變 W 分量的。
經(jīng)過投影矩陣透視變換后,每一個(gè)向量即經(jīng)過了“透視除法”。透視除法只是將齊次坐標(biāo)中的 W 分量轉(zhuǎn)換為1的專用名詞

繼續(xù)上面的例子,透視除法這步如下:


圖8

完成透視除法后,W分量就沒用了,我們就得到了一個(gè)完全符合3D透視投影規(guī)則的3D坐標(biāo)。

注意: 在OpenGL固定管線中通常使用gluPerspective 或 gluFrustum 方法。在 OpenGL 中,在頂點(diǎn) shader 作用了每一個(gè)頂點(diǎn)后,自動(dòng)進(jìn)行透視除法。這就是頂點(diǎn) shader 中 main 方法輸出的 gl_position 變量,是4維向量,而不是3維向量。

齊次坐標(biāo)影響光照平行光

齊次坐標(biāo)中的一個(gè)屬性,是允許有一個(gè)無限遠(yuǎn)的點(diǎn)(或無限長(zhǎng)的向量),在3D坐標(biāo)中這個(gè)是不允許的。當(dāng) W=0 時(shí),這點(diǎn)表示無限遠(yuǎn)的一個(gè)點(diǎn)。如果你嘗試將一個(gè) W=0 的齊次坐標(biāo)轉(zhuǎn)換為一個(gè)普通的 W=1的齊次坐標(biāo),這會(huì)導(dǎo)致4次除0操作.此時(shí)代碼會(huì)發(fā)生崩潰;

圖9

這意味著,不能將 W=0 的齊次坐標(biāo)轉(zhuǎn)換到 3D 坐標(biāo)。
那么這樣的一個(gè)屬性有什么用處了?

平行光可以認(rèn)為是一個(gè)無限遠(yuǎn)處的點(diǎn)光源。當(dāng)一個(gè)點(diǎn)光源在無限遠(yuǎn)的位置,光線就會(huì)變成平行的,并且所有光線都在同一方向,這就是平行光的基本定義。例如太陽光.

所以在傳統(tǒng)的3D圖形中,平行光可以通過改變點(diǎn)光源位置向量中的 W 分量來表示,當(dāng) W= 1時(shí),是一個(gè)點(diǎn)光源;當(dāng) W= 0 時(shí),是一個(gè)平行光。

例如我們?cè)趯?shí)現(xiàn)光照shader ,可以需要做如下判斷

if (lightPosition.w == 0.0) {    
  //directional light code here
} else {
  //point light code here
}

總結(jié):

齊次坐標(biāo)有一個(gè)額外的維度叫 W 分量,用來縮放X, Y, Z三個(gè)分量的值。平移和透視投影的矩陣變換只能在齊次坐標(biāo)中使用,所以在3D計(jì)算機(jī)圖形學(xué)中,當(dāng) W=1時(shí),X, Y, Z 分量被稱為“正確的”。任何齊次坐標(biāo),只要 W 不為0,都可以通過將每一個(gè)分量除以 W 來轉(zhuǎn)換到 W=1的向量。當(dāng) W=0 時(shí),這個(gè)坐標(biāo)表示無窮遠(yuǎn)的一個(gè)點(diǎn)(或者表示無限長(zhǎng)的一個(gè)向量),通常用于表示平行光的方向。

文章參考于

Explaining Homogeneous Coordinates & Projective Geometry

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容