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上的投影,那么:
所以,在二維直角坐標系中,如果二維向量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點的坐標,那么
於是,點PP可以表示為
所以,要想表示一個三維的點,可以用四維坐標來表示,例如剛才的PP可以表示為P=(x1y1z11)P=(x1y1z11),這就是齊次坐標。對頂點來說,齊次坐標才是其真正的表示方式。向量可以表示為v=(x1y1z10)v=(x1y1z10)。
3 線性變換與齊次坐標
3.1 概述
代數中的線性變換的概念很抽象,涉及到向量空間、線性映射之類的概念,在這里不做過多解釋,如下想了解可以度娘或必應。給一個通俗點的解釋,三維線性變換就是將點/向量的坐標值做一個運算,使其坐標值發生改變,這在幾何中的反映就是幾何體的形狀被改變了。在計算機圖形學中,線性變換一般是指平移、旋轉、縮放、投影(正交投影和透視投影)以及這些基本變換的綜合運算。通過剛才的描述,我們知道一下幾點信息:幾何中的點或向量由四個坐標值確定,而坐標值是由坐標系確定的,坐標系又是由三個不共面的向量和坐標原點構成。也就是說,對於同一點,在不同的坐標系下,描述它的坐標值是不一樣的,而變換就是建立這兩種不同描述之間的聯系——所以在以前我們稱之為坐標變換。例如:在坐標系O1−i1j1k1O1−i1j1k1坐標系下,某一點可以描述為PP點可以用四元祖(x1,y1,z1,o1)(x1,y1,z1,o1)描述,
在另一個坐標系為O2−i2j2k2O2−i2j2k2,可以用另一個有序元組描述它,設為(x2,y2,z2,o2)(x2,y2,z2,o2)
那么怎么建立(3)(3)和(2)(2)之間的聯系呢?還是之前我們說的,任意一個三維向量都可以表示用三個不共面的向量表示,所以i2,j2,k2i2,j2,k2可以用i1,j1,k1i1,j1,k1線性表出:
即:
於是,我們就可以寫出從(x1y1z1o1)T(x1y1z1o1)T變換到(x2y2z2o2)T(x2y2z2o2)T的變換表達式為:
其中,將
稱為坐標變換矩陣。接下來主要就是講解怎么求基本的坐標變換(仿射變換)矩陣。
3.2 縮放
縮放應該是所有線性變換中最簡單的變換了。執行縮放操作,例如將一個向量縮放為原來的ss倍,相當於原點不變,xx、yy、zz三個坐標軸縮放為原來的ss倍。根據3.1介紹的,縮放操作的變換矩陣為:
3.3 平移
所謂平移,就是在坐標系中的三個坐標軸保持不變,原點沿着平移向量移動到新位置。假設平移向量為vp=(xpypzp0)vp=(xpypzp0)同樣,根據可以得到,平移操作的變換矩陣為:
3.4 旋轉
最后來推導最難的旋轉變換矩陣。與平移、旋轉矩陣的不同,旋轉矩陣就不那么直觀了。下面,我們來具體看一下旋轉矩陣的推導,這個推導是執行三次向量的平行四邊形法則進行分解得到,整個分解過程如下圖所示:
三次分解由不同的顏色表示出來了,分別是紅色、淺藍色和紫色。
已知條件:ii、jj和kk是三維笛卡爾坐標系的基向量,原點為OO,旋轉軸為uu,也是單位向量,向量i′i′為xx方向的基向量ii繞旋轉軸uu旋轉θθ后的新向量——旋轉后坐標系xx軸的基向量。
我們的目的:將向量i′i′用基向量ii、jj和kk表示出來。
第一步向量分解:將i′i′分解為沿着旋轉軸uu的向量OA→OA→和垂直於uu的向量OB→OB→,則:
且:
第二步向量分解:將ii分解為沿着旋轉軸uu的向量OA→OA→和垂直於uu的向量OC→OC→,則
且:
第三步向量分解:建立OB→OB→與OC→OC→之間的聯系,將向量OB→OB→分解為沿着OC→OC→方向的向量OD→OD→和垂直於OB→OB→的向量OE→OE→,則
根據66可得:
另外,注意到OE→OE→和OC→OC→垂直,uu是旋轉軸,則uu與平面OEBDOEBD垂直,所以uu與OEOE垂直,則OE→OE→在向量uu和向量OC→OC→的叉乘向量上,假設 OF→=u×OC→OF→=u×OC→,於是:
所以現在求出kk就可以了,由叉乘定義:|OF→|=|u||OC→|sin(90)=|OC→|=|OB→||OF→|=|u||OC→|sin(90)=|OC→|=|OB→|,所以:k=sinθk=sinθ,最后得到
其余兩個變換后的基向量i′i′和j′j′也可以由ii、jj和kk表示出來,最終得到齊次旋轉矩陣為
4 總結
最后總結一下,在這篇博文中我們講述了點及其相對性,接着介紹了向量的概念,由平行四邊形法則引出坐標系的概念,然后介紹了點在坐標系下的表示,最后介紹了坐標變換和變換矩陣的概念,給出了三種基本變換——平移變換、旋轉變換和縮放變換的變換矩陣。這些矩陣綜合運用,就構成了三維空間中復雜的變換了,三維變換是三維圖形繪制的基礎,也是學習OpenGL時較難理解的知識點之一。