2011-12-16 113 views
3

我正在創建一個基於軟件的3D渲染器來學習概念和數學。這很有趣,我有一個很好的旋轉立方體在一個網格頂部作爲一種地板。網格/樓層使用線段進行渲染。我有一個使用簡單的查看轉換定位和定位的虛擬相機。觀察平面任意設置在與「眼睛」相距n的位置,或者在z = -n處。我應該如何處理剪切到觀看平面的3D點的投影?

除了一件事以外,一切正常(從對象到世界到相機空間,剔除,項目,剪輯,渲染)。渲染網格時,線段端點可能會跨越虛擬相機的查看平面。我想渲染可見的部分,以便剪切到查看平面。剪輯的端點投影到查看平面。投影如下:

p'(x) = -n * p(x)/p(z) 
p'(y) = -n * p(y)/p(z) 

所有可能顯示的點將有p(z) ≤ -n。被剪切到觀看平面的點有p(z) = -n。因此,我有效:

p'(x) = p(x) 
p'(y) = p(y) 

對於這樣一個點;一個正交投影。

這裏的值可以很容易地位於查看平面上的窗口之外,這會導致視口轉換將這些點發送出OS窗口的界限。其效果是我看到雜亂的線條週期性地飛來飛去。這太糟糕了。

簡直就像說OpenGL那樣做(我只是使用OpenGL!),我錯過了什麼?

謝謝(如果你做到了這一點!)。

下面是顯示異常的截圖。網格的右上角不在視野內。朝向網格左側角落的線段位於相機後面,因此被裁剪。終點經歷了(錯誤的)正投影,並在左場結束。

我沒有做任何視錐體剔除(還)。也許我應該?

enter image description here

+0

我遵循你的邏輯,但對我來說,你似乎不應該有一個直線正投影這些點! – 2011-12-16 06:32:06

+0

這個問題混合了一些問題1)你混合了在窗口之外和觀點之後的話題。 2)你提到了正射投影,但這看起來是一個與透視投影有關的問題。 – ideasman42 2016-12-28 04:41:38

回答

0

您應該能夠擺脫這些點,你的屏幕空間以外的項目,而不需要看你的視錐體積。所以在你做截錐體篩選之前,你的屏幕空間裁剪算法是什麼樣的?看看這些算法:http://en.wikipedia.org/wiki/Line_clipping,看看你是否可以受益。

無論哪種方式,我認爲你應該考慮讓你的渲染器能夠處理操作系統窗口之外的點。使用上述剪切算法,您可以剔除完全落在窗口外的線段,並且將只有一個點位於外部的線段或兩個點位於外部的線段截斷,但該線段將穿過屏幕空間。

0

剛剛看過這個相同的話題,我發現沒有任何東西需要聰明才能執行此操作。

首先,它可能定義一個近平面和遠平面,然後用這些平面剪切片段(see example)。

雖然這工作正常,但我想避免在投影之上進行額外的計算。 對於熟悉投影矩陣的人來說,這可能是顯而易見的,我不得不仔細檢查以確認它能正常工作。

事實證明,您可以使用簡單的邏輯執行近/遠線剪輯。

  1. 將該位置乘以透視矩陣以獲得4D向量。
  2. 比較第4個分量與近/遠的剪輯距離。
  3. 如果需要的話,剪切段。

這可以通過在計算完整投影之前計算矢量的第四個分量來優化。

這也意味着您不需要在裁剪之後再次重新計算XYZ組件。

例如:這將4D向量乘以4x4矩陣。

pub fn mul_m4v4(m: &[[f64; 4]; 4], v: &[f64; 4]) -> [f64; 4] { 
    [ 
     v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0] + m[3][0] * v[3], 
     v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1] + m[3][1] * v[3], 
     v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2] + m[3][2] * v[3], 
     v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3] * v[3], 
    ] 
} 

由於這是一個三維位置,我們可以假設第四個分量是1.0。

pub fn mul_m4v3_as_v4(m: &[[f64; 4]; 4], v: &[f64; 3]) -> [f64; 4] { 
    [ 
     v[0] * m[0][0] + v[1] * m[1][0] + v[2] * m[2][0] + m[3][0], 
     v[0] * m[0][1] + v[1] * m[1][1] + v[2] * m[2][1] + m[3][1], 
     v[0] * m[0][2] + v[1] * m[1][2] + v[2] * m[2][2] + m[3][2], 
     v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3], 
    ] 
} 

爲了避免完整的計算,分出一個單獨的函數來獲得第四個組件。

pub fn mul_project_m4_v3_zfac(m: &[[f64; 4]; 4], v: &[f64; 3]) -> [f64; 4] { 
    v[0] * m[0][3] + v[1] * m[1][3] + v[2] * m[2][3] + m[3][3] 
} 

這裏是一個commit,它實現瞭如上所述的限幅。

注意:矩陣是列主要的(像OpenGL)。