2013-11-05 68 views
3

所以,我試圖實施截錐體撲殺。這裏的事情是,在我能做到這一點之前,我需要了解一些事情。查看截錐體撲滅問題

首先其中,是平面的交點:

我的理解是一個平面可以通過3點來定義;我們稱它們爲p0, p1, and p2

鑑於此,我們知道這架飛機的正常可如下計算:

(僞代碼)

vec3 edge0 = p1 - p0; 
vec3 edge1 = p2 - p0; 

vec3 normal = normalize(cross(edge0, edg1)) // => edge1 X edge2/length(edge1 X edge2); 

現在,讓我們說我們有一個函數,它主要是告訴我們,無論是否某個點以某種方式「穿過」飛機。

(moar僞代碼)

bool crossesPlane(vec3 plane[3], vec3 point) 
{ 
    vec3 normal = getNormal(plane); // perform same operations as described above 
    float D = dot(-normal, plane[ 0 ]); // plane[ 0 ] is arbitrary - could just as well be the 2nd or 3rd point in the array 

    float dist = dot(normal, point) + D; 

    return dist >= 0; // dist < 0 means we're on the opposite side of the plane's normal. 
} 

這背後的邏輯推理是,由於視圖錐臺包含六個不同的平面(近,遠,左,上,右,下) ,我們希望抓住這六個平面中的每一個,並且基本上將它們「傳遞」到對於單個點(對於該點來說是一個點,六個測試)的函數crossesPlane()

如果這六個電話中的一個crossesPlane()回報false,然後我們要剔除有問題的點,從而有效地導致點被截錐被淘汰,當然還有點不會被渲染。

問題

  • 這是一個正確的做法,以正確撲殺視圖錐臺?
  • 如果是這樣,將給出一個給定的多邊形的頂點的任意列表,並使用這種方法在每個頂點上執行這個測試,是一個有效的方法去實現它?
  • 儘管AABB可以用來替代剔除測試中的多邊形/網格,但是它們仍然常用於此場景,它們仍然被認爲是「常規」goto方法嗎?

注意

如果有任何值得D3D和OpenGL這間提的實現差異,這將是肯定的讚賞。

+0

通常我們做的同質變換檢查,對視錐的飛機,從而使比較的對象1,-1等 –

+1

@MarkPing前:真正用於測試各個頂點,而不是像或的AABB邊界的形狀因爲這些形狀在同質空間中不再是球形的矩形。因此,AFAIK在視圖空間測試更爲常見。 – cdoubleplusgood

回答

3
  • 是的,這實質上是用於平截頭體剔除點的正確方法。
  • 不,對每個頂點單獨執行此測試並不是剔除任意多邊形的有效方法。考慮一個與截頭體相交的單個非常大的三角形的情況:它的所有頂點都可能在截頭體之外,但三角形仍然與截頭體相交併應該被渲染。
  • AABB可以用於平截頭體剔除,並且通常是一個不錯的選擇,但是您仍然必須處理AABB的所有頂點都位於平截體以外但與平截體相交的情況。邊界球體使得內部/外部測試稍微簡單一些,但是它們所包含的對象周圍往往有鬆散的界限。然而這通常是合理的折衷。
2

您的方法通常是正確的。
通常使用AABB或邊界球而不是測試任意形狀的每個頂點。
但是,對於AABB,有些情況下所有角落都在平截頭體之外,但盒子仍與截錐體相交。一個保守的解決方案是如果所有的角落都位於至少一個平面的外側,則僅拒絕箱子。
AABB有一個常見的優化:對於平截頭體的每個平面,只需檢查「最近」和「最遠」角而不是全部6個角。對於這一點,並視錐一般撲殺一個很好的資源是這樣的:
http://www.lighthouse3d.com/tutorials/view-frustum-culling/

編輯: 這是一個更加文章如何找到並不完全是一個一個平面的外側,但還是不相交的AABB視錐:
http://www.iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm