天天看點

Unity3D - Shader - 模型、世界、觀察、裁剪空間坐标轉換

原文連結:https://blog.csdn.net/biezhihua/article/details/78926849

一個頂點要經過多個坐标空間的轉換才能夠被畫到螢幕上。

模型空間 -> 螢幕空間

模型空間

模型空間(model space),也成為對象空間(object space)或局部空間(local space)。 每個模型都有自己的模型空間,當它旋轉或移動時,模型空間也會随之移動。

Unity時左手坐标系,是以+x,+y,+z+x,+y,+z軸分别對應模型的右、上、向前。此外,模型空間的原點和坐标軸通常是由美術人員在模組化軟體中确定好的。

世界空間

世界空間(world space)是一個宏觀的特殊坐标系,其代表了我們關心的最大坐标系。在Unity中模型如果沒有父節點,那麼它就在世界空間内。

将頂點坐标從模型空間變換到世界空間,成為模型變換(model transform)。

想要模型變換必須知道變換矩陣。通過之前的知識我們知道,變換矩陣必須知道模型空間坐标軸在世界空間中的表示和其原點位置。而這些資訊可以在Unity中Inspector的面闆中的Transform中檢視到。

Transform中的Position是該模型在世界空間中平移的位置,而Rotation是模型在世界空間中旋轉的值,Scale則是模型在世界空間中縮放的值。

而變換順序又是先縮放、再旋轉、最後平移的方式,我們可以得到如下變換矩陣:

Mmodel=⎡⎣⎢⎢⎢⎢100001000010PositionxPositionyPositionz1⎤⎦⎥⎥⎥⎥⎡⎣⎢⎢⎢0000000000000001⎤⎦⎥⎥⎥⎡⎣⎢⎢⎢⎢Scalex0000Scaley0000Scalez00001⎤⎦⎥⎥⎥⎥

Mmodel=[100Positionx010Positiony001Positionz0001][0000000000000001][Scalex0000Scaley0000Scalez00001]

從右往左依次是縮放矩陣、旋轉矩陣、平移矩陣,其中旋轉矩陣請參看之前的知識(每個軸的旋轉所使用的矩陣都不同)。最後的結果就是變換矩陣M_{model}了。

最後就可以通過該矩陣對模型空間中的頂點進行變換了:

Pworld=MmodelPmodel

Pworld=MmodelPmodel

觀察空間

觀察空間(view space)也被稱為錄影機空間(camera space)。和其他空間不同的是觀察空間使用的是右手坐标系,也就是是說,+x+x軸指的是右方,+y+y軸指的是左方,+z+z軸則是錄影機的後方。

頂點變換的後一步就是從世界空間變換到觀察空間中,這個變換叫做觀察變換(view transform)。

得到觀察變換矩陣有兩種方法,一種是計算觀察空間的三個坐标軸在世界空間下的表示,然後建構變換矩陣;另一種是想象平移整個觀察空間,其核心就是将錄影機想象移動到與世界坐标重合的位置,再對z軸分量取反。

我們依舊可以從錄影機的Transform資訊中拿到錄影機在世界空間的變換過程。

最終變換矩陣為:

Mmodel=⎡⎣⎢⎢⎢1000010000−100001⎤⎦⎥⎥⎥⎡⎣⎢⎢⎢⎢Scalex0000Scaley0000Scalez00001⎤⎦⎥⎥⎥⎥⎡⎣⎢⎢⎢0000000000000001⎤⎦⎥⎥⎥⎡⎣⎢⎢⎢⎢100001000010PositionxPositionyPositionz1⎤⎦⎥⎥⎥⎥

Mmodel=[1000010000−100001][Scalex0000Scaley0000Scalez00001][0000000000000001][100Positionx010Positiony001Positionz0001]

從右往左依次是平移矩陣、旋轉矩陣、縮放矩陣,最後是取反矩陣(因為錄影機是右手坐标系)。

最後就可以通過該矩陣對世界空間中的頂點進行變換了:

Pview=MviewPworld

Pview=MviewPworld

裁剪空間

頂點還需要從觀察空間轉換到裁剪空間(clip space,也叫作齊次裁剪空間),其矩陣是裁剪矩陣(clip matrix),也叫作投影矩陣(projection matrix)。

視椎體(view frustum)會決定對渲染圖元的裁剪。

視椎體是決定錄影機可以看到的區域,由6個平面組成,稱為裁剪平面,其中還有兩個近裁剪平面(near clip plane)和遠裁剪平面(far clip plane),其決定了錄影機可以看到的深度範圍。

視椎體還有兩種類型:透視投影(perspective projection)和正交投影(orthographic projection)。

在這個步驟中,會使用投影矩陣把頂點轉換到裁剪空間中。

透視投影矩陣:

Mfrustum=⎡⎣⎢⎢⎢⎢⎢⎢⎢cotFOV2Aspect0000cotFOV20000−−Far+NearFar−Near−100−2∗Near∗FarFar−Near0⎤⎦⎥⎥⎥⎥⎥⎥⎥

Mfrustum=[cotFOV2Aspect0000cotFOV20000−−Far+NearFar−Near−2∗Near∗FarFar−Near00−10]

Pclip=MfrustumPview

Pclip=MfrustumPview

一個頂點和上述矩陣相乘後,就可以由觀察空間變換到裁剪空間。這個矩陣的本質實際上是對頂點(x,y,z)(x,y,z)的各個分量,做了不同程度的縮放與平移。

此外,裁剪矩陣會改變空間的旋向性,之前觀察空間是右手坐标系,變換後是左手坐标系,離錄影機越遠zz值越大。

正交投影

正交投影矩陣如下:

Mortho=⎡⎣⎢⎢⎢⎢⎢⎢1Aspect∗Size00001Size=0000−−Far+NearFar−Near000−Near+FarFar−Near1⎤⎦⎥⎥⎥⎥⎥⎥

Mortho=[1Aspect∗Size00001Size=0000−−Far+NearFar−Near−Near+FarFar−Near0001]

Pclip=MorthoPview

Pclip=MorthoPview

和投影矩陣不同的本質在于最後一行的分量不一樣。同樣,正交投影也會改變空間的旋向性。

螢幕空間

裁剪後需要進行真正的投影,需要把視椎體投影到螢幕空間空(screen space),最後會得到像素位置。

将頂點從裁剪空間投影到螢幕空間,來生成2D坐标。

第一步,需要進行齊次除法(homogeneous diision)

,就是使用齊次坐标系中的ww分量去除以x,y,zx,y,z分量,在OpenGL中這一步得到的坐标也被乘坐歸一化的裝置坐标(Normalized Device Coordinated, NDC).

把坐标從齊次裁剪坐标中轉化到NDC中,最後的裁剪空間會變換到一個立方體中。分量範圍在[-1, 1]。

在Unity中,螢幕左下角是(0,0),右上角是(pixelWidth,pixelHeight),由于立方體内的坐标都是[-1,1],是以映射過程就是一個縮放的過程。

齊次除法和螢幕映射可以總結為下面的公式:

screenx=clipx∗pixelWidth2∗clipw+pixelWidth2screeny=clipy∗pixelWidth2∗clipw+pixelHeight2

screenx=clipx∗pixelWidth2∗clipw+pixelWidth2screeny=clipy∗pixelWidth2∗clipw+pixelHeight2

此外,從裁剪空間到螢幕空間的轉換是由底層幫我們完成的。

總結

頂點着色器的最基本任務就是把頂點坐标從模型空間轉換到裁剪空間中。