WebGL座標系基礎(二)

希沃ENOW大前端html

公司官網:CVTE(廣州視源股份)前端

團隊:CVTE旗下將來教育希沃軟件平臺中心enow團隊git

本文做者: github

前言

本文假設讀者已經對向量、矩陣有必定的瞭解。對此不瞭解的讀者不妨先看一下這篇文章:《乘風破浪的WebGL系列-仿射變換數學基礎》web

在上一篇文章:《WebGL 座標系基礎(一)》中,咱們介紹了WebGL 中常見的幾種座標系以及他們之間的關係。本期將更加「硬核」一些,從數學的角度,推導上期講到的各個變換矩陣。segmentfault

基礎概念

列向量

在下面的推導中,咱們統一使用列向量來表示一個座標,所謂列向量就是一個N*1 矩陣。例如座標(x, y, z) 能夠表示爲: Screen_Shot_2021-03-06_at_23.26.41.pngmarkdown

爲何要用這樣的 N1 矩陣來表示座標?其實就是由於咱們是經過一個個的矩陣來表示各類各樣的變換,而把座標變成 N1 矩陣,就能讓其與變換矩陣運算,從而變換咱們的座標。工具

齊次座標

上面用 N*1 矩陣表示的座標,咱們稱之爲 N 維座標,若是咱們再加一維,變成 N+1 維,就稱之爲齊次座標,對應的 N+1 維矩陣就是齊次矩陣。oop

爲何要引入齊次座標的概念?常見的說法是經過齊次座標新增長的維度來區分點與向量,新增維度的值爲0則表明向量,不爲0則表明點。post

關於爲何新增的維度能用於區分點與向量,能夠看一下這篇文章:齊次座標理解

不過我的認爲,齊次座標更加巧妙的一點是可以把平移轉換變成矩陣相乘的運算。

下面咱們會知道,旋轉、縮放等變換都是經過矩陣乘法進行的,而且變換的組合(例如先縮放再旋轉)也是經過變換矩陣相乘求出。可是惟獨平移變換是經過矩陣加法進行。假設一個座標分別往x,y,z 方向平移 Tx,Ty,Tz,那麼用矩陣加法來表示就是:

Screen_Shot_2021-03-07_at_00.06.58.png

等式的右邊就是咱們須要得到的平移變換以後的座標,因爲常量 Tx,Ty,Tz 的存在,咱們顯然沒法經過簡單的矩陣乘法獲得這樣的座標,那麼咱們要如何經過乘法獲得同樣的座標呢?只須要加一維便可。

Screen Shot 2021-03-09 at 10.05.09.png

此外還記得上一期談到的份量 w 嗎?他其實就是齊次座標帶來的額外的一維,因此齊次座標的引入也方便咱們模擬透視效果。

總的來講,齊次座標的引入具備三個做用:

  1. 區分向量和點
  2. 使平移變換能經過矩陣乘法運算實現
  3. 方便模擬透視效果

基本變換

在齊次座標下,仿射變換均可以套用如下的形式:

Screen Shot 2021-03-09 at 10.07.26.png 可見每個份量都符合仿射變換的定義。

平移變換

根據平移變換的定義,對一個點(x, y, z)平移,即對其三個份量分別加上一個常數:

Screen_Shot_2021-03-07_at_16.44.29.png 套入上面提到的矩陣模板,即a=1,b=0,c=0,顯然平移矩陣能夠寫成:

Screen_Shot_2021-03-07_at_16.46.23.png

縮放變換

縮放變換意味着一個點的各個份量均爲原來的 S 倍,以 x 軸份量縮放 Sx 倍爲例:

Screen_Shot_2021-03-07_at_16.50.35.png 套入上面的矩陣模版,即a=Sx,b=0,c=0,Tx=0,顯然縮放矩陣能夠寫成:

Screen_Shot_2021-03-07_at_16.52.52.png

旋轉變換

以上兩個矩陣的推導都很是直觀,相比起來旋轉矩陣的推導就略顯複雜。 首先咱們定義,這裏所說的旋轉是指將點P 繞座標原點逆時針旋轉 θ 度。

Screen_Shot_2021-03-07_at_16.59.26.png 爲了推導的方便咱們先使用極座標表示。 在極座標下,P點的座標爲(r, α)P 旋轉 θ 度後的座標爲(r, α + θ)。 再將極座標轉回直角座標,有:

Screen_Shot_2021-03-07_at_17.07.54.png

P點原來的極座標與直角座標的轉換關係代入,有:

Screen_Shot_2021-03-07_at_17.10.03.png 上面的推導是二維的,可是咱們能夠很容易的將上面的旋轉等同於在 xyz 座標系中,繞座標軸 z 旋轉,由於是繞座標軸 z 旋轉,因此旋轉先後點 Pz 份量保持不變,x,y份量的變化與上面的推導結果一致,所以繞 z 軸旋轉的結果爲:

Screen_Shot_2021-03-07_at_17.19.26.png

代入咱們的矩陣模板,可得繞z 軸旋轉的旋轉矩陣:

Screen_Shot_2021-03-07_at_17.21.00.png

同理可得繞 x 軸,y 軸的旋轉矩陣,這裏就不列出來,讀者能夠本身寫一下,答案能夠參考:

LearnOpenGL

須要注意的是,更多時候咱們須要繞任意軸旋轉,儘管繞任意軸旋轉能夠經過以上三軸旋轉的組合實現,但會出現萬向節死鎖的問題,一個更好的方式是一步到位,求解出一個繞任意軸旋轉的矩陣,可是這個矩陣會比較複雜而且也沒法完全避免萬向節死鎖問題。

這樣的矩陣我先貼出來,因爲並不是本期重點因此略去了推導過程,有興趣的童鞋能夠看一下這篇:三維空間繞任意軸旋轉矩陣的推導

Screen_Shot_2021-03-07_at_17.33.09.png 其中 (Rx,Ry, Rz) 表明旋轉軸的向量。

要徹底解決該問題須要使用四元數,有興趣的讀者能夠找另外的資料學習,(不妨看看這篇四元數與三維旋轉),此處就再也不展開了。

模型變換矩陣

簡單回顧一下模型變換:用於將模型座標系轉換到世界座標系的變換,也就是將咱們的小車模型安放在世界座標系的某一處。

而要實現模型變換,顯然一個很好的方式就是藉助於矩陣這一強大的數學工具。咱們將模型的某一個頂點的座標用上文提到的列向量來表示,那麼只要將咱們的模型變換矩陣左乘該列向量,就能獲得變換以後的頂點座標。

模型變換是上文提到的三個基本變換組合而成,咱們也知道矩陣乘法不符合交換律,所以基本變換的組合順序相當重要,具體來講,模型變換有如下公式: Screen Shot 2021-03-09 at 10.12.37.png 其中 T 是平移變換矩陣,R 是旋轉變換矩陣,S是縮放變換矩陣。之因此有這樣的順序,咱們能夠從兩個角度來理解。

定性理解

咱們在推導旋轉矩陣的時候,實際上是約定了頂點是繞座標原點旋轉,若是模型的原點與世界座標原點重合,那麼頂點繞模型原點與繞座標原點旋轉是同樣的。然而若是咱們先平移,讓兩個原點不重合,那麼在應用旋轉矩陣的時候,頂點依舊繞座標原點旋轉,但咱們通常仍是但願頂點能繞模型原點旋轉,這就不符合咱們的期待。因此須要先進行旋轉變換,再平移。縮放變換相似的,一樣隱含着以座標原點爲中心的條件,因此也是要先縮放再平移。

至於縮放與旋轉的次序,咱們在定義縮放矩陣的時候,是針對當前的座標定義的各個份量的縮放比例,若是此時通過旋轉,座標已經發生了改變,那麼再使用以前的縮放比例就會有問題。而旋轉則沒有相似的問題,由於他定義的是任何一個點須要繞座標原點旋轉某個角度,這樣的定義適用於全部座標,不存在座標已經改變致使原定義不適用的問題。

數學理解

這裏我舉平移與旋轉,旋轉與縮放做爲例子。

假如先平移再旋轉

勘誤:此處的矩陣相乘應爲點乘

Screen_Shot_2021-03-07_at_23.02.09.png 注意變換以後的座標的後半部分,從結果來看,再也不以原來的方向平移,平移的方向也旋轉了。

假如先旋轉再縮放

Screen_Shot_2021-03-08_at_22.12.21.png

從變換後的座標可見,Sx 不只做用於原來的x份量,也做用於原來的 y 份量,Sy 也有相似的狀況。同時咱們發現,若是 Sx,Sy,Sz 的值一致,那麼旋轉與縮放的順序就再也不重要,結果都同樣。

視圖變換矩陣

這個矩陣就是將點從世界座標系轉換到觀察(相機)座標系的矩陣。在上一期咱們知道,咱們會在世界座標系中放置一個相機(觀察點),而且相機有方向。這就很像咱們在模型變換裏面將物體放置在世界座標系中作過的事情。咱們先經過平移變換將相機放在某一處,再經過旋轉變換將相機朝向某一個方向。設 P1 是頂點在觀察座標系中的座標,P0 是在世界座標系的座標,那麼就有: Screen_Shot_2021-03-08_at_19.59.19.png

同時,根據矩陣兩條的性質:

  1. 矩陣左乘逆矩陣等於單位矩陣
  2. 單位矩陣左乘矩陣等於原矩陣

咱們很容易就有如下的推導過程:Screen_Shot_2021-03-08_at_20.13.32.png

所以只須要求出相機的平移矩陣以及旋轉矩陣的逆矩陣,就能組合起視圖變換矩陣,將頂點在世界座標系中的座標 P0,轉換成在相機座標系中的座標 P1

已知相機的座標是(ex, ey, ez),那麼根據前文的知識,很容易就能得出平移矩陣。而平移矩陣的逆矩陣也很容易就能看出來,這裏就不詳細推導了。

Screen_Shot_2021-03-08_at_20.25.48.png

下面咱們來推導如下旋轉矩陣。

首先定義相機座標系的三個基向量 Ux, Uy, Uz,其中Ux在世界座標系的三個軸x, y, z的份量分別是:Uxx, Uxy, UxzUyUz同理。這樣,將一個頂點在相機座標系中的座標 P1 轉成世界座標系的座標P0的變換矩陣 R 就能用Ux,Uy, Uz的份量表示出來:

Screen_Shot_2021-03-08_at_22.20.20.png

關於如何得出這個矩陣,能夠回憶一下旋轉矩陣,但這一次咱們不是旋轉頂點,而是先旋轉座標系,再將頂點從在旋轉後坐標系中的座標,轉成在旋轉前座標系的座標。簡單起見,可先從二維旋轉入手。

咱們須要的是這個變換矩陣的逆矩陣,而因爲咱們旋轉以後的相機座標系的三軸是相互垂直的,因此矩陣是正交矩陣,正交矩陣的逆矩陣等於矩陣的轉置矩陣。因而逆矩陣 R-1 即爲:

Screen_Shot_2021-03-08_at_22.23.57.png

將矩陣代入以前的結果

Screen_Shot_2021-03-08_at_22.31.17.png

最後的問題就是,咱們要如何求出這幾個基向量在世界座標系的份量。

首先咱們會經過兩個點(均爲世界座標系的點),以及相機頭頂的方向向量來定義相機的位置與方向:

  1. 相機的位置點 e (ex, ey, ez)
  2. 相機看向的點 T (Tx, Ty, Tz)
  3. 攝像機上方方向向量 u (ux, uy, uz)

很符合咱們的現實世界是否是?

接着咱們會定義觀察的方向爲 Uz,那麼根據向量加減法, Uz 顯然等於:

Screen_Shot_2021-03-08_at_22.46.04.png Screen_Shot_2021-03-08_at_22.48.40.png 第二個等式表明須要歸一化處理。 有了 Uz 以後再將其與上方方向向量 u 進行叉乘再歸一化,獲得 Ux。同理,再利用 Uz 與 Ux 叉乘並歸一化,獲得 Uy。 至此整個視圖變換矩陣就獲得了。

投影變換矩陣

上期提到,投影分正交投影和透視投影,下面會分別推導。

正交投影

在正交投影中,咱們使用一個長方體來定義可視範圍:

1f5f8ecaca6348fc9d931249874d0489_tplv-k3u1fbpfcp-zoom-1.png

咱們須要把模型中的一個點 P, 投影到近平面中,成爲座標 P'。P' (x', y', z') 座標具備如下特色:

  • x' 在 -1, 1之間
  • y' 在 -1, 1之間
  • z' 在 -1, 1之間

這樣意味着通過變換以後一步到位來到來規範化的設備座標系(NDC)。

根據這一特色,咱們以 x 爲例,推導 x 與 x' 的關係: Screen_Shot_2021-03-09_at_00.26.53.png

其中 l 爲左平面位置,r 爲右平面位置。運用相似的方式也能得出 y' 與 y,z' 與 z 的關係。代入矩陣中便可獲得正交變換矩陣:

Screen_Shot_2021-03-09_at_00.31.32.png

其中t、b、n、f 分別對應上平面,下平面,近平面,遠平面的位置。

透視投影

8cb3e9827d2a4cb38432cfe7b0ab814b_tplv-k3u1fbpfcp-zoom-1.jpg

相比起來透視投影會複雜一些。因爲透視投影的可視範圍是一個錐體,所以咱們會須要用到類似三角形的知識,回憶一下:

Screen_Shot_2021-03-09_at_00.34.50.png

假設有以上的座標關係,那麼在n上的那個交點 p' 的 x 座標 x1 能夠這麼求出:

Screen_Shot_2021-03-09_at_00.36.33.png

一樣的,x', y', z' 均在 -1 到 1之間。接下來咱們先推導x,y的值。以 x 爲例,近平面上的,x1通過歸一化後的值爲:

Screen_Shot_2021-03-09_at_01.03.02.png

上面的公式咱們在推導正交變換的時候已經見過。可是與正交不一樣,x並不等於x1,可是咱們能夠經過類似三角形原理求出:

Screen_Shot_2021-03-09_at_01.07.58.png 其中n是近平面的位置。這裏的負號是由於投影座標系和相機座標系的 z 軸相反。y' 的狀況同理。 所以咱們有:

Screen_Shot_2021-03-09_at_01.16.24.png 接下來咱們求解 z 與 z‘ 的關係。已知當 z 爲近平面時,裁剪空間中的 z 爲 -1,z 爲遠平面時則爲1。因而有:

Screen_Shot_2021-03-09_at_01.31.27.png

Screen_Shot_2021-03-09_at_01.32.12.png 因此:

Screen_Shot_2021-03-09_at_01.34.06.png

從上面的關係中能夠看到,x' 和 y' 都帶來一個與 z 相關的常量,回憶一下上期降到的 w 份量,那個常量即爲 w 份量,可見 z 越大,離近平面越遠,越小。

結合起來,咱們的矩陣能夠寫成:

Screen_Shot_2021-03-09_at_01.40.47.png

從矩陣也能夠看出,通過變換以後原來爲1的齊次座標會變成與z相關的-z。

總結

本期咱們推導了常常用到的各類矩陣,本人也是現學現賣,不免會有一些錯漏,還請你們在評論區指出。

參考資料

  1. 掘金小冊《WebGL 入門與實踐》
  2. LearnOpenGL
  3. 交互式計算機圖形學——基於WEBGL的自頂向下方法(第7版)
  4. 知乎:爲何directX裏表示三維座標要建一個4*4的矩陣?
  5. OpenGL矩陣變換的數學推導
  6. webgl 開發第一道坎:矩陣與座標變換
  7. 計算機圖形學視圖矩陣推導過程
相關文章
相關標籤/搜索