日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

投影矩阵的推导(转载)

發布時間:2024/9/19 综合教程 28 生活家
生活随笔 收集整理的這篇文章主要介紹了 投影矩阵的推导(转载) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自kanegohttp://www.cnblogs.com/kanego/articles/2346971.html

[譯] - 投影矩陣的推導

原帖地址:

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,所以不會有像透視投影那樣隨距離變化的特性。對于正投影,所有的物體的大小不會變化,而且不會隨著距離變化。

圖3:簡單的正投影應用(原文里的圖 轉帖者添加)

下面開始推導正投影矩陣。一個在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()結果一樣。

注:

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

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

本文版權歸作者 kanego 和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利.

總結

以上是生活随笔為你收集整理的投影矩阵的推导(转载)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。