我們知道在3D畫面渲染過程中對於模型的計算的一部分被稱為Transforming and Lighting(T&L)階段,其中Lighting表示光照,而Transforming就是指的坐標變換,這兩部分的計算也是3D場景中計算最重要基礎的一步。
空間坐標變換主要的工作就是將處於局部坐標系的模型轉換到用戶屏幕所在的屏幕坐標系內。
而這個過程的計算上主要是來自線性代數中的知識,我們知道在線性代數中,線性的變換是可以用矩陣來表示的,而通過將向量[x,y,z,w]同變換矩陣相乘即可完成相應的變換,這正是我們實現空間坐標變換的數學基礎,在3D圖形學中,空間坐標變換一般分為三個步驟——世界變換、視角變換、投影變換,而完成這些變換就是由矩陣運算來完成的。
世界變換
我們知道所有模型都是獨立創建的,他們擁有自己獨立的一個局部坐標系來描述模型內部各個面片頂點之間位置的關系,當我們將這些模型放在一起來組建游戲場景的時候,邏輯上他們就處在了同一個坐標系內來描述模型與模型之間位置與角度的關系,這個坐標系我們所說的世界坐標系,而將模型中的每一個頂點從局部坐標系轉換到世界坐標系的過程,我們稱之為世界變換。
世界變換是通過將模型中每一個頂點乘以世界變換矩陣來完成的,通常情況下這個世界變換矩陣是通過一系列變換矩陣的結合形成的一個包含了所有變換內容的矩陣來完成計算的,包括平移、旋轉、縮放等等變換。
在3D圖形學里的矩陣變換同2D圖形學里一樣,只是多了一維坐標,一般的變換矩陣如下圖所示:
單獨平移矩陣和縮放矩陣如下圖所示,也比較好理解,其中Tx,Ty,Tz分別表示在各個坐標軸上平移的距離,Sx,Sy,Sz分別表示在各個坐標方向上縮放的倍數。
旋轉矩陣在理解上需要一點點推導,以2維空間下圍繞原點旋轉為例,大家可以畫一個草圖來幫助推導,設點(x,y)與原點的連線同X軸的角度為b,以此方向繼續旋轉a度,至點(x’,y’),我們可知旋轉軌跡所在圓的半徑R=x/cosb,R=y/sinb。而x’=R*cos(a+b),y’=R*sin(a+b),根據合角公式拆開,再將前面的式子帶入,可得x’=xcosa-ysina;y’=xsina+ycosa。
3維空間下以此相推可分別得出圍繞X軸方向旋轉、圍繞Y軸方向旋轉、圍繞Z軸方向旋轉的變換矩陣:
另外3維空間下圍繞任意軸旋轉的旋轉變換矩陣是通過平移矩陣和圍繞各個軸旋轉的矩陣復合而得出的。
在世界坐標系里的任何一個模型的狀態都可以通過若干中變換矩陣的組合來表明它的唯一狀態,通過矩陣相乘來得到最終的變換矩陣,需要注意的是因為所有的變換矩陣都是相對坐標系的原點完成的,所以變換矩陣相乘時候的順序關系很重要,相互顛倒會產生完全不同的變換矩陣。
視角變換
通過世界變換,我們將所有的模型都轉換到一個統一的世界坐標系中,但是在游戲中我們的觀察點不可能總是世界坐標系的原點,面向着Z軸的正方向。攝像機和模型是同樣可以游離於場景中的任何地點,面向任意角度的,所以這就需要通過視角變換來實現。
一個視角變換通常是由一次平移變換和三次旋轉變換來完成的,平移矩陣負責將相機從默認的世界坐標系的原點平移到正確的位置,三次旋轉分別負責圍繞三個坐標軸的旋轉,將相機調整至正確的朝向。
說的很抽象,但實際上可以理解為將轉換到世界坐標下的各個模型再轉換到以攝像機為原點的攝像機坐標系下,當然在游戲中是不需要手動生成這個矩陣的,我們只需要提供相機的位置,朝向等等參數,API會幫我們生成正確的視角矩陣。
投影變換
投影變換的工作就是將攝影空間中的三維物體投影到二維的平面上,邏輯上也就是用戶的屏幕區域。這種三維到二維的變換過程就是投影變換,即從取景空間到投影空間的變換。
投影變換分為兩種基本的投影變換:正交投影和透視投影
正交投影中,投影向量和觀察平面垂直,物體坐標沿觀察坐標系的Z軸平行投影到觀察平面上,觀察點和觀察平面間的距離不會影響物體的投影大小。工程設計中的頂視圖、前視圖和側視圖就是典型的正交投影,正交投影沒有透視關系,可以利用正交投影來完成D3D渲染2D游戲畫面。
而透視投影實現的是一個縮放、透視的投影。透視投影的特點是:距離攝像機越遠的物體在投影平面上的成像越小。更像人眼所能看到的現實世界中的透視關系。
下面我們來根據透視投影的幾何關系來推導一下透視投影下的投影矩陣的生成:
在游戲中,當以透視的方法從攝像機來觀察場景的時候,會在場景內形成一個金字塔形狀的可見區域,又因為遠近兩個裁剪面的存在,所以實際上可見區域是一個截體,透視投影矩陣的作用是將這個取景截體轉換成一個立方體(將近攝像機端拉伸),分別將X和Y坐標映射到投影平面的正確的位置上,同時保持深度信息不變,因為截體的近端比遠端小,所以靠近攝像機的對象將被放大,而遠離攝像機的對象,則會相對保持原樣。
到齊次裁剪空間的映射是通過一個4×4的投影矩陣實現的。在這個投影矩陣中,除了其他的變換功能外,還要保證變換后的點w坐標等於攝像機空間中的點的z坐標的負值,這樣,將變換后的點的坐標分量除以w坐標后,就可以生成裁剪空間中相應的三維點。
我們設圖中可視區中一點P(Px,Py,Pz),將P點同攝像機相連同投影面交於一點(x,y,z),這個點就是投影變換后P所應該在的點,遠近裁剪面到攝像機的距離分別是d和Zf。根據相似三角形,我們可以知道x=d*Px/Pz;y=d*Py/Pz,設投影平面的四個邊框的橫縱坐標位置分別是r,l,t,b(右左上下)。為了滿足取景截體到齊次空間的映射,我們還需要需要將投影后的x,y坐標映射到[-1,1]區間,而通常的,將z坐標映射到[0,1]區間,映射后的坐標為x’,y’,z’。根據兩個平面內坐標同平面的線性比例關系,我們繼續推導:
Z軸的線性關系相對簡單,但是因為在光柵化過程中為避免透視失真而進行的乘以z倒數的插值操作(顯卡的工作,為什么要這樣的具體原理還理解不夠透徹,以后補齊),所以這里要建立關於1/z的映射,這樣就可以對投影深度值進行線性插值了:
將所得的x’,y’,z’同Px,Py,Pz所對應的關系進一步整理,就可以得到最終的正確的投影矩陣了。這個投影矩陣也是D3D中所用的投影矩陣,雖然我們通常都是提供相機的fov,朝向,位置等參數利用API生成, 但是理解原理是非常重要的,關於正交投影的投影矩陣大家也可以利用類似的步驟推導出來。
寫的非常粗糙,只描述了一些關鍵步驟,權作筆記,畫圖和公式可真是耽誤了我好多好多時間啊,真累人……
