[譯] – 投影矩陣的推導

來源:互聯網
上載者:User

[譯] - 投影矩陣的推導

原帖地址:

http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Projection-Matrices.htm

譯文:

矩陣變換作為3d圖形程式員的基本知識,投影矩陣是其中很複雜的內容。平移和縮放是容易理解的,旋轉矩陣只需要掌握了基本的三角幾何知識,但是投影矩陣不一樣。如果你看過投影矩陣的形式,你會發現你很難很快知道它是怎麼來的。而且,我在網上沒有發現很多有關推導投影矩陣的資源。本文就是講述如何推導投影矩陣。

對於新接觸3d圖形學的人來說,推導投影矩陣需要有一定的數學基礎,但不是必須的。你可以直接使用最後的公式,如果你使用一種圖形API,如Direct3D,通常你不需要關心,因為API已經提供了計算投影矩陣的功能。一旦你理解了如何推導它,這對你沒有壞處。這篇文章為了那些需要瞭解推導投影矩陣細節的人的。

簡介:什麼是投影

電腦顯示器是一個2d表面,為了顯示3d物體,你需要把3d的物體轉化成2d的圖片,這個過程就是投影。舉一個簡單例子,最簡單的把3d物體變到2d表面上的方法是去掉z座標。對於1個立方體,如1。

 

圖1:去掉z座標投影到xy平面

當然,圖1方法很簡單,大多數情況不適用。這裡不會投影到一個平面上,相反,這裡講的投影會把物體變換到一個規範的是視空間(canonical view volume這個是叫什嗎?)。對於規範的視空間的座標,不同圖形API可能不同。作為討論起見,這裡使用Direct3D的,即(-1, -1, 0)到(1, 1, 1)。一旦物體的座標轉換到了規範的視空間裡面,其中的x、y座標就用於映射到螢幕空間,z座標一般用於z-buffer。

注意圖1使用了左手座標系。這也是Direct3D的形式,本文將一直使用左手座標系。對於右手座標系,本文講述的知識都是適用的。

現在可以開始講投影變換了。這裡主要講述2中最普遍的形式:正投影和透視投影。

正投影

正投影是一種簡單的投影形式,要求所有的投影射線垂直於投影面。正投影最終的規範視空間是一個AAB(axis-aligned box),如2。

 

圖2:正投影

可以看出,規範的視空間是由6個面組成的:

左:x = l

右:x = r

下:y = b

上:y = t

近:z = n

遠:z = f

由於正投影的視錐(view volume)和規範視空間(canonical view volume)都是AAB,所以不會有像透視投影那樣隨距離變化的特性。對於正投影,所有的物體的大小不會變化,而且不會隨著距離變化。

下面開始推導正投影矩陣。一個在view volume中的點的x座標在[l, r],這需要變換到canonical view volume中的[-1, 1]。

l <= x <= r

0 <= x-l <= r-l

0 <= (x-l)/(r-l) <= 1

0 <= 2(x-l)/(r-l) <= 2

-1 <= 2(x-l)/(r-l) - 1 <= 1

-1 <= (2x-r-l)/(r-l) <= 1

最後你需要得到px+q的形式,所以分解成:

-1 <= 2x/(r-l) - (r+l)/(r-l) <= 1

所以得到了在canonical view volume中的x座標:

x' = 2x/(r-l) - (r+l)/(r-l)

同理得到在canonical view volume中的y座標:

y' = 2y/(t-b) - (t+b)/(t-b)

最後來推導z'的公式。在view volume中的點的z座標在[n, f],需要變換到canonical view volume中的[0, 1]。

n <= z <= f

0 <= z-n <= f-n

0 <= (z-n)/(f-n) <= 1

0 <= z/(f-n) - n/(f-n) <= 1

得到z'的運算式:

z' = z/(f-n) - n/(f-n)

總結上面的x', y'和z',

x' = 2x/(r-l) - (r+l)/(r-l)

y' = 2y/(t-b) - (t+b)/(t-b)

z' = z/(f-n) - n/(f-n)

如果寫成矩陣形式:

 

在Direct3D中一個函數D3DXMatrixOrthoOffCenterLH()正好提供了這個功能(注意到形式有些不同,是行/類矩陣的區別)。“LH”表示的是左手座標系,但是“OffCenter”表示的又是什麼呢?

第一,在Camera空間,如果Camera被放置在原點,並且方向沿著z軸;第二,如果r = -l,t = -b,並且定義x軸上的寬度w和y軸上的高度h,那麼

 

上面的矩陣和Direct3D中的D3DXMatrixOrthoLH()計算的結果一致。

如果把正投影的矩陣分解成如下:

 

注意變換形式是:p'(canonical view volume) = P0 * P(view volume)。

通過這個分解,可以這樣來理解正投影矩陣,首先,吧view volume沿z軸把近平面移到原點,其次,縮放使得view volume變換到canonical view volume。

透視投影

透視投影因為可以產生距離的錯覺(遠方的物體看起來更小),所以可以產生更真實的效果,被廣泛使用。它和正投影不同的地方是,透視投影的view volume是一個錐體,如4:

 

圖4:透視投影

可以看出view frustum的近平面由(l, b, n)延伸到(r, t, n)。

步驟一:對於view frustum中的一個點(x, y, z),把它投影到近平面z = n。因為 投影點在近平面上,所以x座標的範圍在[l, r],y座標的範圍在[b, t]。如 圖5

步驟二:使用在正投影中學習的知識,把在近平面上x的[l, r]隱射到[-1, 1],y的[b,  t]隱射到[-1, 1]。

 

圖5

第一步:得到投影點

 

 

所以得到投影點(x*n/z, y*n/z, n)。

第二步:把第一步中得到的投影點,運用正投影中學習的知識隱射。

 

代入x = x*n/z 和 y = y*n/z,

 

乘以z,

 

把(x, y, z)隱射到(x'z, y'z, z'z),所以需要求z'z

假設z'z = pz + q,而z座標的隱射是[n, f]到[0, 1],所以得到:

0 = pn + q

f = pf + q

解方程得:

p = f/(f-n)

q = -fn/(f - n)

所以,

z'z = fz/(f-n) - fn/(f-n)

總結在一起,

 

寫成矩陣形式:

 

上面的矩陣可以使得,p * (x, y, z, 1) = (x'z, y'z, z'z, z)。這個也是和Direct3D中的D3DXMatrixPerspectiveOffCenterLH()是一樣的(注意行/列區別)。同正投影中,如果滿足一定的條件,r = -l,t = -b,則有下面的矩陣形式:

 

這個就和Direct3D中的D3DXMatrixPerspectiveLH()結果一樣。

最後,有必要說一下牽扯到寬高比的矩陣表示形式。

6:

 

圖6

cot(a/2) = n / (h/2) = 2n/h

假設r = w/h,即寬高比

2n/w = 2n/(rh) = (1/r) * cot(a/2)

則有以下形式:

 

這個形式就和Direct3D中的D3DXMatrixPerspectiveFovLH()結果一樣。

註:

本文原本準備翻譯,後來沒耐心了,話說最近我做事一直都沒什麼耐心了,所以沒怎麼按照原文翻譯,而是把重要的列出來。

上面說的一些推導公式有些不用那麼繁瑣,但是總的來看,很值得一讀。

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/G_cofa/archive/2010/10/08/5926092.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.