入門三維開發必須得瞭解的基礎知識

入門三維開發必須得瞭解的基礎知識

在這裏插入圖片描述

世界座標到屏幕座標的過程

  • 首先讓我們用文字來描述一下空間的一個點是經過怎樣的蹂躪最後才變成屏幕上的一個點的,感受下這中間經歷過的可怕歷程

  • 總的來說,空間中的一個點,先要轉換成以相機爲原點的相機座標,再轉換成齊次裁剪空間的投影座標,然後變換爲範圍在[-1,1]的歸一化座標,這個歸一化座標再轉成屏幕的座標

  • 在這個過程中涉及到了很多座標系和矩陣變換,我們只需要認準一點,就是一個座標系變成另一個座標系都可以用一個變換矩陣來表示

  • 現在第一步,由世界座標變爲相機座標,它的變換矩陣爲mc,這個矩陣的意義就在於世界座標的任何一點,經過mc矩陣變換後,就能變成相機座標

  • 那麼相機座標是啥呢,相機座標就是以相機爲原點的座標系

  • 第二步,由相機座標變爲齊次裁剪空間座標,它的變換矩陣爲mp,經常稱之爲投影矩陣(這個矩陣主要根據相機的參數fov,near,far,aspect等等計算得出),齊次裁剪空間座標的意義在於有了它就能非常快速地計算物體是否在視錐體內,因爲不在視錐體內的東西由於看不到,沒必要浪費性能去計算它們

  • 第三步,由齊次裁剪空間座標變爲歸一化的設備座標(NDC),這個變化的特點就是值域變爲[-1,1]了,這樣的好處就是屏蔽了各種空間的大小帶來的不便,方便後續的計算

  • 第四步,由歸一化的設備座標變爲屏幕座標,同樣地這樣的變換也有一個矩陣來表示,我們得到了點的屏幕座標,就可以開始渲染了

  • 上面的過程我們可以數一數總共出現了世界座標系,相機座標系,齊次裁剪空間座標系,歸一化設備座標,屏幕座標系,這幾個座標系的xyz軸方向都得仔細去了解下,其實主要就是z軸,它的正方向有不同習慣,xy軸的正方向大家都比較統一,屏幕座標也有以左上角和以左下角爲原點的區別

  • 因爲出現了這麼多座標系,各個軸的方向不同、原點不同,就會導致我們需要進行一大堆的換算,因此要學習三維,沒有一定的數學基礎真的玩不了,這時多麼懷念當初的數學知識,特別是線性代數啊

  • 實際上因爲我舉例的是一個點,如果這個點在某個模型上呢,那麼最開始還要多加一個模型座標系和由模型座標到世界座標的變換過程,然後渲染時需要紋理,紋理又有一個uv座標系,想想實在太可怕了

  • 最後總結爲

變換矩陣mm
變換矩陣mc
變換矩陣mp
歸一化
變換矩陣
模型座標
世界座標
相機座標
投影座標
歸一化的設備座標
屏幕座標
  • 上面好像有好多變換矩陣啊,這些變換矩陣怎麼來的,其實這就涉及到線性代數和齊次座標了,簡單點說線性代數可以幫助我們完成各種變換(位移,旋轉,縮放),而齊次座標就是將這三種變換都統一爲矩陣乘法
  • 要哭了,又多了線性代數和齊次座標,這輩子最大的過錯就是沒好好學數學,那麼不妨再讓你奔潰一下,三角函數你也必須得槓桿的纔行
  • 說了這麼多,就是建議你先複習下三角函數,然後好好學習線性代數(線性變換,矩陣乘法等),再去百度下齊次座標,接下來纔開始進入三維世界,進行各種座標變換(別走啊,快回來)

座標系

  • 左手座標系(z軸正方向爲屏幕外射向屏幕內,與右手座標系相反),右手座標系(與我們平常在課本中看到的三維座標系一致,z軸正方向爲屏幕內射向屏幕外)
  • 在unity中除了相機座標系是使用右手座標系外,其餘都是左手座標系
  • 而webgl則基本是右手座標系

模型座標系(本地座標系)

  • 一般以模型的中心爲原點,模型上的各點座標是相對於模型座標系的
  • 在其他資料中,模型座標也會被稱爲本地座標,這裏只要知道它們說的都是同一個東西即可
  • 通過模型轉換,可以將模型座標系上的點的座標轉換爲世界座標系的座標

世界座標系

  • 世界座標系分爲左右手座標系,unity採用左手座標系,opengl採用右手座標系
  • 一般情況下,世界座標系的原點(0,0,0)轉換後會在屏幕的中點
  • 通過視圖轉換,可以將世界座標系上的點的座標轉換爲相機座標系的座標

相機座標系

  • 一般以相機位置爲原點,也有分爲左右手座標系,不過在unity中相機空間(也叫觀察空間)採用的是右手座標系(坑吧,unity世界空間中使用左手座標系,爲啥就不能搞成一致的呢)
  • 通過投影轉換,可以將相機座標系上的點的座標轉換爲齊次裁剪空間座標系的座標

齊次裁剪空間座標系

  • 齊次裁剪空間,又叫規則觀察體(Canonical View Volume),之所以要引入這個空間,就是爲了把不在這個空間的物體裁剪剔除
  • 那麼怎麼知道物體在不在這個空間呢,就是將相機空間中的一點(x,y,z,1)經過投影矩陣(又叫裁剪矩陣)變換後,判斷新座標(x’,y’,z’,-z)各分量(x’,y’,z’)是否在[-w,w]中(w指的是(x’,y’,z’,-z)的第四個分量-z),以及w是否在[near,far]中,如果是這個點就是在齊次裁剪空間內
  • 在這裏插入圖片描述
  • 如果對上面的(x’,y’,z’,-z)各分量都除以w分量,就得到(x’/-z,y’/-z,z’/-z,1),這個空間就稱爲NDC(歸一化設備空間)
  • 你可以理解NDC爲一個單位立方體,這是個左手座標系(unity和opengl是一樣的),即z軸射向屏幕的爲正方向,在unity和opengl下z分量爲[-1,1],而在DirectX中是[0,1],xy軸的值域都在[-1,1]

歸一化設備空間座標系

  • 如果對齊次裁剪空間的(x’,y’,z’,-z)各分量都除以w分量,就得到(x’/-z,y’/-z,z’/-z,1),這個空間就稱爲NDC(歸一化設備空間)
  • 你可以理解NDC爲一個單位立方體,這是個左手座標系(unity和opengl都是一樣的,爲什麼呢,因爲投影矩陣會改變空間的自旋性,而unity和opengl在裁剪空間都是右手座標系,自旋後就都是左手座標系了),即z軸射向屏幕的爲正方向,在unity和opengl下z分量爲[-1,1],而在DirectX中是[0,1],xy軸的值域都在[-1,1]

屏幕座標系

  • 屏幕座標系中DirectX以屏幕左上角爲原點,向右爲x軸正方向,向下爲y軸正方向,而opengl則以屏幕左下角爲原點,向右爲x軸正方向,向上爲y軸正方向

uv座標系

  • uv座標系主要是用於紋理圖,紋理圖說白了其實就是一張2d圖
  • uv座標系以紋理圖片的左下角爲原點,向右爲u,向上爲v
  • 由於紋理圖的尺寸可能千奇百怪,因此uv座標範圍通常都被歸一化到[0,1]範圍內

視錐體

  • 相機主要有兩種模式,正交投影和透視投影,其中透視投影就跟我們眼睛看到的一樣,會有近大遠小的效果,而正交投影則無論遠近,看到的都是一樣大小
  • 不同的視錐體需要不同的處理過程,對於透視投影的視錐體來說,判斷一個頂點是否處於一個金字塔內部(透視投影的視椎體看起來就是一個金字塔)是比較麻煩的,因此需要一種更加通用、方便和整潔的方式來進行裁剪,這就需要將頂點轉換到一個裁剪空間中
  • 在這裏插入圖片描述

矩陣

投影矩陣(裁剪矩陣)

  • 裁剪矩陣會改變空間的旋向性,空間從右手座標系變換到了左手座標系,如下圖(其中lrtbn是left right top bottom near的簡寫)
  • 在這裏插入圖片描述
  • 投影矩陣會把所有頂點座標從eye coordinates(觀察空間/相機空間,eye space或view space)變換到裁剪座標(clip coordinated,屬於裁剪空間,clip space)。然後,這些裁剪座標被變換到標準化設備座標(normalized device coordinates, NDC,即座標範圍在-1到1之間),這一步是通過用用裁剪座標的w分量除裁剪座標實現的
  • 透視投影矩陣,其中r表示爲截面寬度的一半,t表示截面高度的一半,n表示near,f表示far,都爲正數
  • 在這裏插入圖片描述
  • 正交投影矩陣
  • 在這裏插入圖片描述
  • 詳細可以看這篇文章:OpenGL投影矩陣(Projection Matrix)構造方法 - lxycg - 博客園

mvp矩陣

  • mvp矩陣其實就是模型矩陣,視圖矩陣,投影矩陣三個矩陣相乘,注意順序:mvp矩陣=投影矩陣*視圖矩陣*模型矩陣

  • 頂點在空間中的變換:

    • 模型空間 → 模型矩陣 → 世界空間→ 視圖矩陣 → 視圖空間→ 投影矩陣 → 裁剪空間
  • 我們拿到點在模型座標上的位置後,通過mvp矩陣就能得到此點的齊次裁剪空間座標

  • 視圖矩陣實際上是記錄了相機的變換的逆矩陣,在實際生活中我們是認爲物體不動,相機在動,但相對來說,也可以認爲相機不動,物體在相反的動,視圖矩陣就描述了這種相反的過程

  • 這裏有篇文章詳細介紹了這塊的內容: WebGL model view projection - Web API 接口參考 | MDN

線性代數

  • 以前學線代也就是根據公式計算計算,根本不知道線代究竟有什麼用,等接觸到了圖像變換的時候,才知道原來圖片的旋轉,縮放,平移,錯切,翻轉都是通過線代實現的,這個時候後悔當初沒好好學也不要緊,從現在開始找百度先生好好學習吧
  • 矩陣相乘舉例
  • 在這裏插入圖片描述
  • 注意矩陣乘法不滿足交換律,即AB!=BA;也不滿足消去律,即AB=AC,A!=O(O表示零向量)時,B!=C
  • 還有不是任意兩個矩陣都可以相乘的,比如m*n矩陣只能和n*x矩陣相乘(m*n表示m行n列),例如2*3矩陣可以和3*1矩陣乘,但不能和2*2矩陣相乘

線性運算

  • 矩陣的加減法和矩陣的數乘合稱矩陣的線性運算
  • 矩陣加法滿足如下運算律
    • A+B=B+A
    • (A+B)+C=A+(B+C)
  • 矩陣數乘滿足如下運算律
  • 在這裏插入圖片描述

轉置矩陣

  • 矩陣的轉置滿足以下運算律
  • 在這裏插入圖片描述

齊次座標

  • 齊次座標是用來升維的,比如二維的(x,y)可以用三維的(x/w,y/w,w)來表示
  • 在我們的空間計算中w通常爲1,於是我們的二維(x,y)就可以用三維的(x,y,1)表示
  • 齊次座標的一個典型例子就是統一了平移,縮放,旋轉,都可以用矩陣乘來表示
  • 我們知道旋轉和縮放都是通過矩陣乘,而平移卻是矩陣加,這使得對於平面的變換無法用統一的表示方法,於是引入了齊次座標,這個齊次座標可以用三維來表示二維,例如二維中的(X,Y),可以變成齊次座標(X/w,Y/w,w),當我們選擇w等於1時,就有(X,Y)轉成齊次座標(X,Y,1),有人可能會問,這麼做有啥用,實際上這麼做就是爲了解決上面說到的變換(位移,縮放,旋轉)用矩陣表示方式的不統一,試想一下,如果我們可以用矩陣乘就表示位移,縮放,旋轉那該有多好,這樣就不用再考慮它是平移就用矩陣加,是縮放旋轉就用矩陣乘了,都統一爲用矩陣乘,至於爲何可以這樣請查看下文的矩陣變換
  • 這裏也有篇文章可以詳看: 寫給大家看的“透視除法” —— 齊次座標和投影 - 簡書

仿射變換

矩陣變換

  • 這部分的內容跟我們大學學習的線性代數就有很大關係了

  • 先以二維爲例來說明吧,我們知道,在二維平面中的任何向量(用a表示)都可以由兩個基本的單位向量(用i和j來表示)來表示,因此向量的變換(平移,縮放,旋轉)自然也都可以轉化爲這兩個單位向量的變換,比如我們想要向量a順時針旋轉90度,那麼就可以看成是單位向量順時針旋轉90度,而向量a是可以通過單位向量得到的,這樣子我們便可以通過單位向量得到順時針旋轉90度的需要的矩陣

  • 我們假定通過矩陣v變換後就能得到順時針旋轉90的效果

  • 那麼 單位向量*矩陣v=向量a*矩陣v

  • 單位向量我們一般都用i(1,0),j(0,1)表示,我們可以將i,j表示爲矩陣

    • [1]
  • 矩陣乘法只有結合律沒有交換律,因此順序很重要,比如abc=a(bc),ab!=ba

  • 如果一個物體要先通過矩陣v1變換,再通過矩陣v2變換,那麼我們可以把v1和v2相乘得到的矩陣作爲物體的總的變換矩陣

  • 我們可以想象一下,一個物體先平移再繞原點旋轉和物體繞原點旋轉再平移所得到的效果是不一樣的

二維矩陣變換

在這裏聲明一下,由於各自採取的座標系不同(左右手座標系)和歸一化([-1,1],[0,1])不同,矩陣變換公式並不是一模一樣的,但原理上大致一樣,因此使用矩陣公式時請不要盲目套用,一定要先清楚自己所處的座標系等相關信息

  • 上面的齊次座標肯定有人會疑惑,這是來幹嘛的,其實引入這個主要是因爲縮放和旋轉都可以用矩陣乘得到,而位移卻是矩陣加,爲了讓這三種變換都統一爲矩陣乘,於是才需要齊次座標,接下來你看看下面的推導過程公式應該就會理解了
  • 因爲我喜歡用列來表示點座標矩陣,如
  • 在這裏插入圖片描述
  • 而有些人可能喜歡行(x,y,1)表示
  • 這兩種表示都可以,只是在矩陣乘法上有點小區別,用列的話需要右乘,而行的話需要左乘
  • 下面的例子用的都是右乘
  • AB叫做A左乘B,或者叫做B右乘A

縮放

在這裏插入圖片描述

旋轉

在這裏插入圖片描述

位移

在這裏插入圖片描述

三維矩陣變換

縮放

在這裏插入圖片描述

位移

在這裏插入圖片描述

旋轉

  • 三維的旋轉矩陣就比較複雜一點了,因爲可以分別繞x軸y軸z軸旋轉,不過通過上面的二維的旋轉已經可以類比得到規律:繞x軸旋轉說明x座標沒變化,把yoz當成一個平面,繞x軸旋轉也相當於在平面繞原點o旋轉,這裏面有個特殊情況是繞y軸旋轉的時候
  • 在這裏插入圖片描述

透視投影矩陣變換

平移、縮放和旋轉的順序

  • 世界座標變換裏對平移縮放旋轉的順序非常重要,要先縮放、後旋轉、再平移
  • 這三種變換按各種順序執行,結果是不同的
  • 當一個物體剛剛放入世界座標系中,它的本地座標系原點和座標軸和世界座標系的原點和座標軸都是重合的(這裏先不考慮左右手座標系,暫定世界座標和本地座標都是一樣的標準)
  • 而我們知道
  • 縮放並不會改變座標軸的方向和原點,因此經過縮放後兩個座標系還是重合的
  • 旋轉會導致兩個座標系的座標軸不再重合,但原點還是重合的
  • 平移會導致兩個座標系的原點不再重合,但座標軸方向仍然一致
  • 看了上面,你應該知道爲何要先縮放了吧,因爲縮放後兩個座標系還是重合的,之所以平移要在旋轉之後,是因爲平移會改變原點的位置,而旋轉卻能保持原點不變,任何保持原點不變的變換都需要放在平移之前

座標變換

NDC座標轉爲屏幕座標

  • 我們知道投影座標系的原點在中心,值域爲[-1,1],而屏幕座標原點在左上角,y軸方向向下,假設屏幕分辨率爲w*h,於是我們可以得到投影座標系統的點(x,y)轉爲屏幕座標後是 (w/2*(x+1),h/2*(1-y)),注意這是屏幕座標以左上角爲原點的情況

  • 這個計算原理也很簡單,就是由於座標系的不同,首先爲了確保正方向一致,我們要繞x軸進行翻轉,於是原來點(x,y)就變成了(x,-y),接着由於值域[-1,1]映射的是屏幕座標值域的[0,w]和[0,h],於是(x,-y)變成(w/2*x,-h/2*y),然後由於屏幕座標原點與投影座標原點的相對位置(即屏幕座標在x軸y軸上分別位移w/2,h/2得到投影座標原點),於是座標分別相加w/2,h/2,即(w/2*x+w/2,-h/2*y+h/2),最後化簡一下爲(w/2*(x+1),h/2*(1-y))

  • 假設(X,Y)爲屏幕座標,(x,y)爲投影座標,運用到我們上面說到的矩陣運算就是如下公式,這時你會發現矩陣運算有多好用了吧,這裏的結果跟我們口述推導的(w/2*(x+1),h/2*(1-y))結論是一致的

  • 在這裏插入圖片描述

  • 當我們把左邊的矩陣合成一個矩陣,就得到了ndc轉爲以左上角爲原點的屏幕座標的轉換矩陣(3*3),如下

    //屏幕左上角爲原點的變換矩陣,第二行第二列爲負號主要是因爲兩個座標系的y軸方向剛好相反
    w/2  0.0   w/2
    0.0  -h/2  h/2
    0.0  0.0   1.0
    
  • 如果有些非要以屏幕左下角爲原點,那麼轉爲屏幕座標後是(w/2*(x+1),h/2*(1+y))

  • 其對應的轉換矩陣如下

    //屏幕左下角爲原點的變換矩陣
    w/2  0.0  w/2
    0.0  h/2  h/2
    0.0  0.0  1.0
    
  • 這裏提醒一下,由於NDC座標是歸一化的,因此在相機的aspect不爲1的情況下,x軸和y軸方向上的單位向量的大小不是一樣的

NDC座標轉爲UV座標

  • 這個轉換在投影時有妙用,可用於將一張圖片投影在模型物體上的計算

  • 設備歸一化座標的值域是[-1,1],而uv座標的值域是[0,1],也就是從設備歸一化座標到uv座標是先繞原點縮小1/2,然後再向上向右平移1/2,於是可得到變換矩陣,如下

    //uv左下角爲原點的變換矩陣
    0.5  0.0  0.5
    0.0  0.5  0.5
    0.0  0.0  1.0
    
  • 上面的uv座標是以左下角爲原點的,假如是以左上角爲原點的,那麼就相當於繞x軸翻轉了一下,即y變爲-y,x保持不變,於是可得如下矩陣

    //uv左上角爲原點的變換矩陣
    0.5  0.0   0.5
    0.0  -0.5  0.5
    0.0  0.0   1.0
    

參考

(1條消息)D3D中的世界矩陣,視圖矩陣,投影矩陣_diaoqu4574的博客-CSDN博客
https://blog.csdn.net/diaoqu4574/article/details/102223247

關於Opengl各種矩陣變換(MVPW)的自我理解
http://www.360doc.com/content/14/0826/17/13726687_404788406.shtml

旋轉變換(一)旋轉矩陣 - 莫水千流 - 博客園
https://www.cnblogs.com/zhoug2020/p/7842808.html

(1條消息)“爲什麼DirectX裏表示三維座標要建一個4*4的矩陣?”_weixin_34311757的博客-CSDN博客
https://blog.csdn.net/weixin_34311757/article/details/86322479?depth_1-

寫給大家看的“透視除法” —— 齊次座標和投影 - 簡書

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章