投影矩阵的推导(转载)
轉(zhuǎn)載自kanegohttp://www.cnblogs.com/kanego/articles/2346971.html
[譯] - 投影矩陣的推導(dǎo)
原帖地址:
http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Projection-Matrices.htm
譯文:
矩陣變換作為3d圖形程序員的基本知識,投影矩陣是其中很復(fù)雜的內(nèi)容。平移和縮放是容易理解的,旋轉(zhuǎn)矩陣只需要掌握了基本的三角幾何知識,但是投影 矩陣不一樣。如果你看過投影矩陣的形式,你會發(fā)現(xiàn)你很難很快知道它是怎么來的。而且,我在網(wǎng)上沒有發(fā)現(xiàn)很多有關(guān)推導(dǎo)投影矩陣的資源。本文就是講述如何推導(dǎo) 投影矩陣。
對于新接觸3d圖形學(xué)的人來說,推導(dǎo)投影矩陣需要有一定的數(shù)學(xué)基礎(chǔ),但不是必須的。你可以直接使用最后的公式,如果你使用一種圖形API,如 Direct3D,通常你不需要關(guān)心,因?yàn)锳PI已經(jīng)提供了計(jì)算投影矩陣的功能。一旦你理解了如何推導(dǎo)它,這對你沒有壞處。這篇文章為了那些需要了解推導(dǎo) 投影矩陣細(xì)節(jié)的人的。
簡介:什么是投影
計(jì)算機(jī)顯示器是一個(gè)2d表面,為了顯示3d物體,你需要把3d的物體轉(zhuǎn)化成2d的圖片,這個(gè)過程就是投影。舉一個(gè)簡單例子,最簡單的把3d物體變到2d表面上的方法是去掉z坐標(biāo)。對于1個(gè)立方體,如下圖1。
圖1:去掉z坐標(biāo)投影到xy平面
當(dāng)然,圖1方法很簡單,大多數(shù)情況不適用。這里不會投影到一個(gè)平面上,相反,這里講的投影會把物體變換到一個(gè)規(guī)范的是視空間(canonical view volume這個(gè)是叫什么?)。對于規(guī)范的視空間的坐標(biāo),不同圖形API可能不同。作為討論起見,這里使用Direct3D的,即(-1, -1, 0)到(1, 1, 1)。一旦物體的坐標(biāo)轉(zhuǎn)換到了規(guī)范的視空間里面,其中的x、y坐標(biāo)就用于映射到屏幕空間,z坐標(biāo)一般用于z-buffer。
注意圖1使用了左手坐標(biāo)系。這也是Direct3D的形式,本文將一直使用左手坐標(biāo)系。對于右手坐標(biāo)系,本文講述的知識都是適用的。
現(xiàn)在可以開始講投影變換了。這里主要講述2中最普遍的形式:正投影和透視投影。
正投影
正投影是一種簡單的投影形式,要求所有的投影射線垂直于投影面。正投影最終的規(guī)范視空間是一個(gè)AAB(axis-aligned box),如下圖2。
圖2:正投影
從圖中可以看出,規(guī)范的視空間是由6個(gè)面組成的:
左:x = l
右:x = r
下:y = b
上:y = t
近:z = n
遠(yuǎn):z = f
由于正投影的視錐(view volume)和規(guī)范視空間(canonical view volume)都是AAB,所以不會有像透視投影那樣隨距離變化的特性。對于正投影,所有的物體的大小不會變化,而且不會隨著距離變化。
圖3:簡單的正投影應(yīng)用(原文里的圖 轉(zhuǎn)帖者添加)
下面開始推導(dǎo)正投影矩陣。一個(gè)在view volume中的點(diǎn)的x坐標(biāo)在[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坐標(biāo):
x' = 2x/(r-l) - (r+l)/(r-l)
同理得到在canonical view volume中的y坐標(biāo):
y' = 2y/(t-b) - (t+b)/(t-b)
最后來推導(dǎo)z'的公式。在view volume中的點(diǎn)的z坐標(biāo)在[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'的表達(dá)式:
z' = z/(f-n) - n/(f-n)
總結(jié)上面的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中一個(gè)函數(shù)D3DXMatrixOrthoOffCenterLH()正好提供了這個(gè)功能(注意到形式有些不同,是行/類矩陣的區(qū)別)。“LH”表示的是左手坐標(biāo)系,但是“OffCenter”表示的又是什么呢?
第一,在Camera空間,如果Camera被放置在原點(diǎn),并且方向沿著z軸;第二,如果r = -l,t = -b,并且定義x軸上的寬度w和y軸上的高度h,那么
上面的矩陣和Direct3D中的D3DXMatrixOrthoLH()計(jì)算的結(jié)果一致。
如果把正投影的矩陣分解成如下:
注意變換形式是:p'(canonical view volume) = P0 * P(view volume)。
通過這個(gè)分解,可以這樣來理解正投影矩陣,首先,吧view volume沿z軸把近平面移到原點(diǎn),其次,縮放使得view volume變換到canonical view volume。
透視投影
透視投影因?yàn)榭梢援a(chǎn)生距離的錯(cuò)覺(遠(yuǎn)方的物體看起來更小),所以可以產(chǎn)生更真實(shí)的效果,被廣泛使用。它和正投影不同的地方是,透視投影的view volume是一個(gè)錐體,如下圖4:
圖4:透視投影
從圖中可以看出view frustum的近平面由(l, b, n)延伸到(r, t, n)。
步驟一:對于view frustum中的一個(gè)點(diǎn)(x, y, z),把它投影到近平面z = n。因?yàn)?投影點(diǎn)在近平面上,所以x坐標(biāo)的范圍在[l, r],y坐標(biāo)的范圍在[b, t]。如 圖5
步驟二:使用在正投影中學(xué)習(xí)的知識,把在近平面上x的[l, r]隱射到[-1, 1],y的[b, t]隱射到[-1, 1]。
圖5
第一步:得到投影點(diǎn)
所以得到投影點(diǎn)(x*n/z, y*n/z, n)。
第二步:把第一步中得到的投影點(diǎn),運(yùn)用正投影中學(xué)習(xí)的知識隱射。
代入x = x*n/z 和 y = y*n/z,
乘以z,
把(x, y, z)隱射到(x'z, y'z, z'z),所以需要求z'z
假設(shè)z'z = pz + q,而z坐標(biāo)的隱射是[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)
總結(jié)在一起,
寫成矩陣形式:
上面的矩陣可以使得,p * (x, y, z, 1) = (x'z, y'z, z'z, z)。這個(gè)也是和Direct3D中的D3DXMatrixPerspectiveOffCenterLH()是一樣的(注意行/列區(qū)別)。同正投影中, 如果滿足一定的條件,r = -l,t = -b,則有下面的矩陣形式:
這個(gè)就和Direct3D中的D3DXMatrixPerspectiveLH()結(jié)果一樣。
最后,有必要說一下牽扯到寬高比的矩陣表示形式。
如圖6:
圖6
cot(a/2) = n / (h/2) = 2n/h
假設(shè)r = w/h,即寬高比
2n/w = 2n/(rh) = (1/r) * cot(a/2)
則有以下形式:
這個(gè)形式就和Direct3D中的D3DXMatrixPerspectiveFovLH()結(jié)果一樣。
注:
本文原本準(zhǔn)備翻譯,后來沒耐心了,話說最近我做事一直都沒什么耐心了,所以沒怎么按照原文翻譯,而是把重要的列出來。
上面說的一些推導(dǎo)公式有些不用那么繁瑣,但是總的來看,很值得一讀。
本文版權(quán)歸作者 kanego 和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利.
總結(jié)
以上是生活随笔為你收集整理的投影矩阵的推导(转载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 树莓派 docker homeassis
- 下一篇: 电脑与ps4共用音箱方案ps4怎么接电脑