OpenGL學習之路(二)


1 引子

在上一篇讀書筆記中,我們對書本中給出的例子進行詳細的分析。首先是搭出一個框架;然后填充初始化函數,在初始化函數中向OpenGL提供頂點信息(緩沖區對象)和頂點屬性信息(頂點數組對象),並啟用頂點數組對象;最后填充繪制函數,首先清空顏色緩存,然后調用glDrawArray來繪制基本圖形。例子中使用的坐標都是二維坐標,所以畫出來的圖形是二維圖形(這里是兩個三角形),而我們知道OpenGL最主要是用來進行三維圖形的渲染的,所以有必要在學習OpenGL相關API之前對三維變換做一個簡要的介紹。其實這一部分應該屬於紅寶書中第五章的內容,這里我們將其提前了,在讀書筆記(二)就拿出來介紹——這是我們三維渲染的最基本的知識點,也是最關鍵的知識點,理解起來也有一定的難度。本次讀書筆記主要講述平移、旋轉、縮放變換的變換矩陣,投影變換將在下一篇讀書筆記再做記錄。本篇讀書筆記主要是自己對一些數學概念的理解和記錄,僅供參考,如有不同理解的,大家可以一起討論哈!

2  點、坐標系與向量

討論三維變換之前,得先了解點、向量和坐標系這些基本數學概念。這部分內容可能比較抽象,下面記錄的是我對這些概念的一些理解。

2.1 位置的相對性

在日常生活中,我們在向別人描述一個陌生的地方的時候,通常會選擇一個他熟悉的地方作為一個參考點。例如:我們向老外介紹河北的一座古城邯鄲,老外知道北京,我們就會說邯鄲在北京往西南走300km;如果老外知道石家庄,那我們也可以告訴他,邯鄲在石家庄往南走100km。這說明,位置是一個相對的概念,要描述一個位置,首先要選擇參考點;參考點的選擇是任意的,所選取的參考點不同,位置的描述也就不同。

在幾何中,位置用“點”這一概念來描述,即點是一個只有位置沒有大小的量。描述一個點和描述一個位置是一回事,剛才已經說了位置是一個相對的概念,所以首先就要用到參考點。我們以最簡單的一維數軸為例來說明描述點的位置,如下圖所示:

對於數軸上同一點AA,要描述AA點的位置,先要選取任意一個參考點,如果選擇的參考點是O1O1,則AA點在O1O1點右邊l1l1的地方;如果選擇的參考點是O2O2,則AA點在O2O2點左邊l2l2的地方。通過數軸和參考點,我們就將數軸上的幾何點用抽象的數字表達出來了。

2.2 坐標系與向量

從圖上可以看出,數軸上的點只能沿着數軸方向進行變化,即它是一維的。如果點在一個平面上或一個空間中變化,那么數軸這一工具是無法描述的。這時就要引入二維坐標系和三維坐標系來描述點的位置。介紹坐標系之前,首先介紹一下向量的概念。

在我們還是十七八歲學習高一幾何的時候,我們就已經接觸到了向量——既有大小,又有方向的量,用一個有向線段來表示。說白了,向量定義了一個方向、一個長度和一個單位長度。如上圖中,O1AO1A和AO2AO2就是兩個向量,大小分別為l1l1和l2l2,方向為水平向右。

一個平面上,有無數這樣的向量。但是關於向量,有一個非常重要的法則——使用平行四邊形法則來對任何一個向量進行分解。平行四邊形法則來自於物理學中力的分解與合成,后被引入數學中加以抽象來描述向量的分解與合成。所謂平行四邊形法則,指的是任何一個平面向量都可以用一個不共線的兩個向量表示。於是,平面中無數的向量就可以用兩個不共線的向量來表示。由這兩個向量及它們的公共起點構成的數學結構就是二維坐標系,用坐標系就可以描述二維平面上的任意點,當然也可以描述二維平面上的任意向量,這兩個向量就是線性代數中的基向量。我們知道,在數學中,向量是位置無關的(即自由向量),只要大小相等,方向相同的兩個向量就是同一個向量(這和物理學中的力不一樣)。所以要描述二維空間中的點,還需要一個參考點,於是就定義了這兩個向量的公共起點作為參考點——即我們熟知的坐標原點。坐標軸向量和坐標原點就構成了坐標系,可以用坐標系來描述其中的任何向量和任一點。

三維坐標系和二維坐標系是類似的,使用兩次平行四邊形法則,從而將任意一個三維向量表示為三個不共面的三維向量(基向量)來表示,這三個向量移到一起的公共起點定義為三維坐標系的坐標原點。二維和三維笛卡爾坐標系就是基向量垂直的二維和三維坐標系,也是應用最為廣泛的坐標系,也稱為平面直角坐標系空間直角坐標系

下面,我們來看看向量的表示方法。同樣在我們懵懵懂懂的青春歲月里,我們就已經知道向量有兩種表示方法:第一種是符號表示法,如a,ba,b等;另一種是坐標表示法,這里對坐標表示做較詳細的說明。剛才已經說了,任意一個二維向量都可以用兩個不共線的向量來表示,假設兩個基向量為ii和jj,且長度為1。則對任一個向量a=xai+yaja=xai+yaj,這樣,向量aa可用一個有序對(xa,ya)(xa,ya)來唯一表示,這就是向量的坐標表示。三維乃至NN維向量的坐標表示都是一樣的。在這里,博主還是想強調一下,向量的坐標並不是該向量在坐標軸上的投影,只有笛卡爾坐標是向量在基向量上的投影。所以,在普通坐標系下,一個向量的坐標不是很好求,但在直角坐標系下,就變得很好求了——求投影,這也是笛卡爾坐標系應用的如此廣泛的原因。下面我們來看看,什么是投影,其實高一數學中也已經接觸到了,如下圖所示:

假設cc為向量aa在向量bb上的投影,那么:

 

c=acos<a,b>(1)(1)c=acos<a,b>

所以,在二維直角坐標系中,如果二維向量aa長度為ll,該向量與xx軸和yy軸的夾角分別為αα和ββ,則我們很容易得到該向量的坐標表示為=(lcosα,lcosβ)T=(lcos⁡α,lcos⁡β)T;同樣地,對三維空間向量bb,其長度為LL,與xx軸、yy軸和zz軸的夾角分別為αα、ββ和γγ,則其坐標表示為b=(Lcosα,Lcosβ,Lcosγ)Tb=(Lcos⁡α,Lcos⁡β,Lcos⁡γ)T。

2.3 點的表示

剛才我們定義了坐標系——坐標原點和三個不共面的向量組成,並且三維空間中的任意向量都可以由這三個向量唯一表示,但我們沒有講點怎么由坐標系來定義。設在三維笛卡爾坐標系中,坐標原點為OO,三個基向量分別為ii,jj,kk,我們要求PP點的坐標,那么

 

OP=x1i+y1j+z1kOP→=x1i+y1j+z1k

於是,點PP可以表示為

 

P=x1i+y1j+z1k+OP=x1i+y1j+z1k+O

所以,要想表示一個三維的點,可以用四維坐標來表示,例如剛才的PP可以表示為P=(x1y1z11)P=(x1y1z11),這就是齊次坐標。對頂點來說,齊次坐標才是其真正的表示方式。向量可以表示為v=(x1y1z10)v=(x1y1z10)。

3 線性變換與齊次坐標

3.1 概述

代數中的線性變換的概念很抽象,涉及到向量空間、線性映射之類的概念,在這里不做過多解釋,如下想了解可以度娘或必應。給一個通俗點的解釋,三維線性變換就是將點/向量的坐標值做一個運算,使其坐標值發生改變,這在幾何中的反映就是幾何體的形狀被改變了。在計算機圖形學中,線性變換一般是指平移、旋轉、縮放、投影(正交投影和透視投影)以及這些基本變換的綜合運算。通過剛才的描述,我們知道一下幾點信息:幾何中的點或向量由四個坐標值確定,而坐標值是由坐標系確定的,坐標系又是由三個不共面的向量和坐標原點構成。也就是說,對於同一點,在不同的坐標系下,描述它的坐標值是不一樣的,而變換就是建立這兩種不同描述之間的聯系——所以在以前我們稱之為坐標變換。例如:在坐標系O1i1j1k1O1−i1j1k1坐標系下,某一點可以描述為PP點可以用四元祖(x1,y1,z1,o1)(x1,y1,z1,o1)描述,

 

P=(x1y1z1o1)⎛⎝⎜⎜⎜i1j1k1O1⎞⎠⎟⎟⎟=(i1j1k1o1)⎛⎝⎜⎜⎜x1y1z1o1⎞⎠⎟⎟⎟(2)(2)P=(x1y1z1o1)(i1j1k1O1)=(i1j1k1o1)(x1y1z1o1)

在另一個坐標系為O2i2j2k2O2−i2j2k2,可以用另一個有序元組描述它,設為(x2,y2,z2,o2)(x2,y2,z2,o2)

 

P=(x2y2z2o2)⎛⎝⎜⎜⎜i2j2k2O2⎞⎠⎟⎟⎟=(i2j2k2O2)⎛⎝⎜⎜⎜x2y2z2o2⎞⎠⎟⎟⎟(3)(3)P=(x2y2z2o2)(i2j2k2O2)=(i2j2k2O2)(x2y2z2o2)

那么怎么建立(3)(3)和(2)(2)之間的聯系呢?還是之前我們說的,任意一個三維向量都可以表示用三個不共面的向量表示,所以i2,j2,k2i2,j2,k2可以用i1,j1,k1i1,j1,k1線性表出:

 

i2=T11i1+T21j1+T31k1+0O1i2=T11i1+T21j1+T31k1+0O1

 

j2=T12i1+T22j1+T32k1+0O1j2=T12i1+T22j1+T32k1+0O1

 

k2=T13i1+T23j1+T33k1+0O1k2=T13i1+T23j1+T33k1+0O1

 

O2=T14i1+T24j1+T34k1+T44O1O2=T14i1+T24j1+T34k1+T44O1

 即:

 

(i2j2k2O2)=(i1j1k1O1)⎛⎝⎜⎜⎜T11T21T310T12T22T320T13T23T330T14T24T34T44⎞⎠⎟⎟⎟(i2j2k2O2)=(i1j1k1O1)(T11T12T13T14T21T22T23T24T31T32T33T34000T44)

於是,我們就可以寫出從(x1y1z1o1)T(x1y1z1o1)T變換到(x2y2z2o2)T(x2y2z2o2)T的變換表達式為:

 

⎛⎝⎜⎜⎜x2y2z2o2⎞⎠⎟⎟⎟=(i1j1k1O1)⎛⎝⎜⎜⎜T11T21T310.0T12T22T320.0T13T23T330.0T14T24T34T44⎞⎠⎟⎟⎟⎛⎝⎜⎜⎜x1y1z1o1⎞⎠⎟⎟⎟(x2y2z2o2)=(i1j1k1O1)(T11T12T13T14T21T22T23T24T31T32T33T340.00.00.0T44)(x1y1z1o1)

其中,將

 

T=⎛⎝⎜⎜⎜T11T21T310.0T12T22T320.0T13T23T330.0T14T24T34T44⎞⎠⎟⎟⎟T=(T11T12T13T14T21T22T23T24T31T32T33T340.00.00.0T44)

稱為坐標變換矩陣。接下來主要就是講解怎么求基本的坐標變換(仿射變換)矩陣。

3.2 縮放

縮放應該是所有線性變換中最簡單的變換了。執行縮放操作,例如將一個向量縮放為原來的ss倍,相當於原點不變,xx、yy、zz三個坐標軸縮放為原來的ss倍。根據3.1介紹的,縮放操作的變換矩陣為:

 

Ts=⎛⎝⎜⎜⎜s0000s0000s00001⎞⎠⎟⎟⎟Ts=(s0000s0000s00001)

3.3 平移

所謂平移,就是在坐標系中的三個坐標軸保持不變,原點沿着平移向量移動到新位置。假設平移向量為vp=(xpypzp0)vp=(xpypzp0)同樣,根據可以得到,平移操作的變換矩陣為:

 

Tp=⎛⎝⎜⎜⎜⎜100001000010xpypzp1⎞⎠⎟⎟⎟⎟Tp=(100xp010yp001zp0001)

3.4 旋轉

最后來推導最難的旋轉變換矩陣。與平移、旋轉矩陣的不同,旋轉矩陣就不那么直觀了。下面,我們來具體看一下旋轉矩陣的推導,這個推導是執行三次向量的平行四邊形法則進行分解得到,整個分解過程如下圖所示:

三次分解由不同的顏色表示出來了,分別是紅色、淺藍色和紫色。

已知條件:ii、jj和kk是三維笛卡爾坐標系的基向量,原點為OO,旋轉軸為uu,也是單位向量,向量ii′為xx方向的基向量ii繞旋轉軸uu旋轉θθ后的新向量——旋轉后坐標系xx軸的基向量。

我們的目的:將向量ii′用基向量ii、jj和kk表示出來。

第一步向量分解:ii′分解為沿着旋轉軸uu的向量OAOA→和垂直於uu的向量OBOB→,則:

 

i=OA+OB(4)(4)i′=OA→+OB→

且:

 

OA=uxu=u2xi+uxuyj+uxuzk(5)(5)OA→=uxu=ux2i+uxuyj+uxuzk

第二步向量分解:ii分解為沿着旋轉軸uu的向量OAOA→和垂直於uu的向量OCOC→,則

 

i=OA+OCi=OA→+OC→

且:

 

OC=iuxu=(1u2x)iuxuyjuxuzk(6)(6)OC→=i−uxu=(1−ux2)i−uxuyj−uxuzk

第三步向量分解:建立OBOB→與OCOC→之間的聯系,將向量OBOB→分解為沿着OCOC→方向的向量ODOD→和垂直於OBOB→的向量OEOE→,則

 

OB=OD+OE(7)(7)OB→=OD→+OE→

根據66可得:

 

OD=|OB|cosθOC|OC|=cosθOC=cosθ(iuxu)=(1u2x)cosθiuxuycosθjuxuzcosθk(8)(8)OD→=|OB→|cos⁡θOC→|OC→|=cos⁡θOC→=cos⁡θ(i−uxu)=(1−ux2)cos⁡θi−uxuycos⁡θj−uxuzcos⁡θk

另外,注意到OEOE→和OCOC→垂直,uu是旋轉軸,則uu與平面OEBDOEBD垂直,所以uu與OEOE垂直,則OEOE→在向量uu和向量OCOC→的叉乘向量上,假設 OF=u×OCOF→=u×OC→,於是:

 

OE=kOF=ku×OC=ku×(iuxu)=ku×iOE→=kOF→=ku×OC→=ku×(i−uxu)=ku×i

所以現在求出kk就可以了,由叉乘定義:|OF|=|u||OC|sin(90)=|OC|=|OB||OF→|=|u||OC→|sin(90)=|OC→|=|OB→|,所以:k=sinθk=sin⁡θ,最后得到

 

OE=sinθu×(iuxu)=sinθ⎛⎝⎜iux1juy0kuz0⎞⎠⎟=uzsinθjuysinθk(9)(9)OE→=sin⁡θu×(i−uxu)=sin⁡θ(ijkuxuyuz100)=uzsin⁡θj−uysin⁡θk

(8)(8)和(9)(9)代入(7)(7)得:

 

OB=(1u2x)cosθi(uxuycosθuzsinθ)j(uxuzcosθ+uysinθ)k(10)(10)OB→=(1−ux2)cos⁡θi−(uxuycos⁡θ−uzsin⁡θ)j−(uxuzcos⁡θ+uysin⁡θ)k

最后,將(5)(5)和(10)(10)代入(4)(4)可得

 

i=(cosθ+u2x(1cosθ))i+(uxuy(1cosθ)+uzsinθ)j+(uxuz(1cosθ)uysinθ)k+0Oi′=(cos⁡θ+ux2(1−cos⁡θ))i+(uxuy(1−cosθ)+uzsin⁡θ)j+(uxuz(1−cos⁡θ)−uysin⁡θ)k+0O

其余兩個變換后的基向量ii′和jj′也可以由ii、jj和kk表示出來,最終得到齊次旋轉矩陣為

 

Mr=⎛⎝⎜⎜⎜⎜cosθ+u2x(1cosθ)uyux(1cosθ)+uzsinθuzux(1cosθ)uysinθ0uxuy(1cosθ)uzsinθcosθ+u2y(1cosθ)uzuy(1cosθ)+uxsinθ0uxuz(1cosθ+uysinθuyuz(1cosθ)uxsinθcosθ+u2z(1cosθ)00001⎞⎠⎟⎟⎟⎟Mr=(cos⁡θ+ux2(1−cos⁡θ)uxuy(1−cos⁡θ)−uzsin⁡θuxuz(1−cos⁡θ+uysin⁡θ0uyux(1−cos⁡θ)+uzsin⁡θcos⁡θ+uy2(1−cos⁡θ)uyuz(1−cos⁡θ)−uxsin⁡θ0uzux(1−cos⁡θ)−uysin⁡θuzuy(1−cos⁡θ)+uxsin⁡θcos⁡θ+uz2(1−cos⁡θ)00001)

4 總結

最后總結一下,在這篇博文中我們講述了點及其相對性,接着介紹了向量的概念,由平行四邊形法則引出坐標系的概念,然后介紹了點在坐標系下的表示,最后介紹了坐標變換和變換矩陣的概念,給出了三種基本變換——平移變換、旋轉變換和縮放變換的變換矩陣。這些矩陣綜合運用,就構成了三維空間中復雜的變換了,三維變換是三維圖形繪制的基礎,也是學習OpenGL時較難理解的知識點之一。

標簽:  OpenGL


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM