實時渲染中的座標系變換(2):3D變換基礎
上一篇 寫了些實時渲染中常見2D座標系變換相關的東西。到這一篇,可以推一推3D座標系的變換公式了。回到上一篇也提過的圖形學常考面試題:
請問在常見的3D渲染管線裡,從製作好mesh,到這個mesh渲染到顯示屏上,中間經歷了哪幾個座標系變換?
Well,答案是:object space -> world space -> camera space -> clip space -> screen space。
這一篇不會把這些東西都寫完。本篇主要還是梳理3D座標系變換的基礎,分析左手系右手系的變換,梳理object space 到 camera space 的變換流程,並對應地在Unity/UE4中做一些驗證。
常用3D座標系:Unity/Unreal
上一篇 提到,常用2D座標系存在“x右y上” 和 “x右y下” 兩個。同理地,常用的3D座標系也存在兩個:左手系和右手系。——為什麼明明在數學上可以統一的東西,落實到應用上卻會存在兩個標準,平添不少麻煩?我猜是當年那些人為了爭奪“氣宗”/“劍宗”誰是“正統”而遺留下來的歷史問題吧。
3D左手系如下圖所示,比如Direct3D。(一個約定俗成的慣例是:X軸為紅色、Y軸為綠色、Z軸為藍色)
左手系(如Direct3D。X: Red, Y: Green, Z: Blue)
3D右手系如下圖所示,比如OpenGL:
右手系(如OpenGL。X: Red, Y: Green, Z: Blue)
Unity和Unreal都是左手系,但是也有一些區別。Unity的3D座標系設定,可以參考Unity 的viewport右上角:
Unity 3D Axis,左手系
UE4的3D座標系設定,參考UE4的viewport左下角:
Unreal 3D Axis,左手系
Unreal式左手系的常見3D座標系變換
下面推導一下常見3D座標系變換,以UE4的座標系來進行。之後再分析Unity和右手系裡。
3D座標系的常見變換是 平移/旋轉/縮放。跟 2D座標系變換 的一個區別是,沒有“錯切變換”這個型別。當然實際上,類似錯切變換的效果是可以在3D裡構建出來的,比如相機的投影變換,就可以認為是錯切變換的一個變體。另外,根據3D變換是否改變物體形狀,可以將3D座標系變換分為兩類:剛性變換(包括平移/旋轉),和非剛性變換(包括縮放,投影變換,和一些骨骼蒙皮變換,等)。
平移
列向量表示法
行向量表示法
縮放
列向量表示法
行向量表示法
跟2D座標系變換同理地,這裡的縮放,除了用來表示放大縮小外,還可以用來表示映象(當
時)
旋轉
在UE4的3D座標系中,從z軸正方向往下看,並且確保x軸在視線中向右(也就是up vector為y軸負方向)時,得到的 x-y 2D座標系其實就是 上一篇 提到過的“x右y下”座標系。在這個座標系內,繞z軸
順時針
旋轉
角的旋轉矩陣是
。擴充套件到3維空間(即增加一個z軸),齊次座標的旋轉矩陣為:(
從z軸往下看,由x軸正方向朝向y軸正方向的旋轉
)
列向量表示法
行向量表示法
同理可以得出另外兩個軸的旋轉矩陣,如下:
從x軸正方向看,由y軸正方向、朝向z軸正方向的旋轉(旋轉角記作
;把y當作橫軸,z當作縱軸,此時y-z構成的是一個“y右z下” 的2D座標系,可套用上一篇 推導的旋轉矩陣)
列向量表示法
行向量表示法
從y軸正方向看,由z軸正方向、朝向x軸正方向的旋轉(旋轉角記作
;把z當作橫軸,x當作縱軸,此時z-x構成的是一個“z右x下”的2D座標系,可套用上一篇 推導的旋轉矩陣)
列向量表示法
行向量表示法
順帶補充一個 齊次座標系 相關的潛規則:
在表示齊次座標系時,並不是一股腦地”末尾增加一個1“就行了,而是要區分一下是”點/point“ 還是”向量/vector“
:
一個3維空間點
的齊次座標表達方式,是”末尾加1“,即
一個三維空間向量
的齊次座標表達方式,是”末尾加0“,即
之所以會有這個區分,是因為 向量代表的只是一個方向資訊,跟具體在3維空間中什麼位置是無關的。因此對一個向量施加平移變換,是沒有意義的。透過對向量的齊次座標末尾加0,消除了平移變換的影響。如果對一個向量施加平移變換,會是如下這個符合預期的”平移無效“的結果:
Unity式左手系的常見3D座標變換
平移、縮放變換公式,跟上述UE4的變換矩陣相同
旋轉:因為都是左手系,所以在Unity座標系中
從x軸正方向看,看到的是“y右z下” 2D座標系
從y軸正方向看,看到的是“z右x下” 2D座標系
從z軸正方向看,看到的是“x右y下” 2D座標系
因此繞x/y/z軸的旋轉矩陣,跟UE4相同
右手系(如OpenGL)的常見3D座標變換
平移、縮放變換公式,跟上述UE4的變換矩陣相同
旋轉:因為是右手系,所以前面的所有“#右#下” 2D座標系,到這裡都變成了“#右#上”。因此前面的這些旋轉公式,可以直接拿過來使用,只不過
旋轉方向,從“順時針” 變成了“逆時針”
。
下面梳理一下本篇開頭的問題裡,從Object Space到 Camera Space的座標系變換(Camera Space之後的變換,涉及到投影矩陣,下一次再寫)
Object Space -> World Space
Object Space,是使用Blender/Max/Maya等DCC工具建模時,使用的座標系。
World Space,是將製作完成的模型擺放到 Unity/Unreal 等引擎的場景中時,使用的座標系。
所以將模型製作完成,並把模型擺放到場景裡面去以後,其實已經進行了一次座標系變換,那就是 Object Space 到 World Space。
如果使用的是 Unity或Unreal,那 World Space 都是 左手系,見前面的兩張viewport截圖。
在這種前提下,
如果 DCC工具的座標系(即Object Space)也是左手系
,那事情是比較清晰的:
ObjectSpace到WorldSpace,是兩個左手系之間的變換,其變換是可以可以用一系列平移/旋轉 來完成的。
比如下圖的兩個左手系 3D 座標系之間的變換:
兩個左手系之間的座標系變換
至於這個座標系變換該怎麼計算:記第一個左手系的原點為
,3個單位向量為
。記第二個左手系的原點和單位向量,在第一個座標系中的表達方式為
。那麼使用如下3個步驟,可以將座標系2變換到座標系1:
第一步,對座標系2進行平移操作,使得
與
重合,變換矩陣記作
(使用列向量表示法對應的變換矩陣);
第二步,對座標系2進行旋轉操作,使得
與
重合(這個旋轉不再是繞x/y/z軸進行,需要使用到3D空間中、繞任意軸旋轉的變換公式,這個下一篇講),變換矩陣記作
;
第三步,對座標系2進行旋轉操作,因為
與
已經重合了,所以此處只要繞
軸進行旋轉,使得
即可。變換矩陣記作
。
在列向量表示法下,使用上述3個步驟的級聯變換矩陣(
),可以將座標系2變換到座標系1。具體來說(注意 point 和 vector 的齊次座標的區別):
,用齊次座標展開是
,用齊次座標展開是
同理,
,
對於3D座標系1(
)中的某個點
,記其座標為
,則其幾何含義其實是:
,用矩陣可以表示為(注意都是列向量):
把變換矩陣
加進來,配合前面的推導,可得:
結合上述,可得
,即:
。
因此,對3D座標系1中的任意點
,需要求其在座標系2中的座標
時,實際上的求解過程就變成了:已知
。
對上式做一個變換,即可得
。
從座標系1到座標系2的變換矩陣就是 : #FormatImgID_65#
。
然後來梳理一下左右手系之間的變換。
這種變換,在Object Space 到 World Space的轉換過程中,是真的會出現的。舉例來說,Blender裡的座標系就是右手系,如下圖:
Blender建模時使用的是右手系,模型匯入Unity/UE4等左手系引擎時,會有一個左右手系的座標變換
其實,這方面UE4和Blender的預設處理是:不處理…… 舉個例子,在blender中製作這樣一個cube模型,延x軸拉長,並且6個面給不同的材質,賦予6種顏色(x+: red, x-: magenta, y+: yellow, y-: green, z+: blue, z-: cyan):
Blender box mesh:x/y/z 正方向的3種顏色
Blender box mesh:x/y/z 負方向
這個模型匯入到UE4以後,形狀沒變化,但是y軸方向的顏色反了:y軸的正負方向,從 黃色/綠色,變成了 綠色/黃色。
UE4 blender mesh:x/y/z 正方向
UE4 blender mesh:x/y/z負方向
究其原因,就是因為中間這個右手繫到左手系的轉換被忽略了,到了UE4裡,直接用blender中的右手系座標數值,在左手系中進行了渲染和顯示,其座標系的差異見下圖:
左:UE4左手系;右:Blender右手系;不做處理而直接使用模型時,y軸會被反向
那麼應該怎麼處理呢?參考上圖,答案基本上已經呼之欲出了,那就是在從Blender匯入UE4時,先把模型沿y軸做一個映象,把”右手系“變成”左手系“(目前在常用DCC工具的匯出設定裡基本都可以找到類似的設定)。做完這一步之後,Object Space 到 World Space 的操作,就是標準的左手系之間的座標變換,前面已經論述過了。
World Space -> Camera Space
這一步比較直觀,因為同一個引擎(比如Unity/Unreal)裡,World Space 和 Camera Space都同為 左手系或者右手系,因此使用上面推導“Object Space->World Space”時講的辦法,即可以完成 World Space 到 Camera Space 的座標系變換。
3D基礎變換效果示例
模型擺放到 Unity/Unreal 的場景中時,已經被賦予了一個 transform 屬性,包含這個模型在 world space 的平移/旋轉/縮放。有的時候,可以透過程式碼來修改這個 transform 屬性,製作一些物體移動/旋轉/縮放的效果。
除此之外,在材質中,還可以對模型的每個頂點進行操作、修改其位置。這步操作,在Unity中是直接寫 vertex shader,在UE4中則是調節材質中的”WorldPositionOffset“屬性。
比如在UE4中使用如下的簡單材質,即可以讓一個有一些網格的模型動起來。
材質
模型
上一篇:裝修瓷磚怎麼挑選?