BVH with SAH (Bounding Volume Hierarchy with Surface Area Heuristic)

 
- BVH with SAH (Bounding Volume Hierarchy  with Surface Area Heuristic) - 
 
 
0. Overview
包圍層次盒(BVH)是一種基於"物體「(object, 區別於「空間」,spatial )的場景管理技術,普遍應用於碰撞檢測、射線相交測試之類的應用場合中。
通常狀況下BVH的性能都比較不錯,起碼比基於格子(Grid)的場景管理技術要高。
 
BVH的數據結構其實就是一棵二叉樹(Binary Tree)。它有兩種節點(Node)類型:Interior Node 和 Leaf Node。 前者也是非葉子節點,即若是一個Node不是Leaf Node,它一定是Interior Node。Leaf Node 是最終存放物體/們的地方,而Interior Node存放着表明該劃分(Partition)的包圍盒信息,下面還有兩個子樹有待遍歷。
 
使用BVH須要考慮兩個階段的工做:構建(Build)和遍歷(Traversal)。
 
1. Build
構建工做考慮的是如何構造一棵能夠有效描述當前場景信息的二叉樹。這當中的關鍵是如何對(假定)毫無規律地散落在場景中的衆物體進行劃分(Partition),即決定哪些物體該劃分到左子樹上,哪些物體該劃分到右子樹上。咱們能夠把這個問題抽象成一個」劃分策略(Partition Strategy)「——咱們總會按照某種」策略「劃分場景的,待會再考慮具體有哪些策略。另外,因爲咱們是在3D空間中工做,爲了將問題簡化,用分而治之的角度看,咱們能夠首先創建一個」原則「(Principle):即決定在哪根軸(x,y,z)上進行劃分。」原則「(Principle)與」策略「(Strategy)的不一樣之處在於,無論用何種」策略「,老是遵照同一種」原則「。
 
1.1 Principle
決定在哪根軸(x,y,z)上進行劃分,取決於場景中的物體在各個軸上分佈的「散度」。若是這些物體沿着某根軸分佈得最爲「鬆散」(即落在該軸上靠一側最近的物體與另外一側最近的物體,兩者距離爲最大),那麼就沿該軸進行劃分。
 
1.2 Strategy
肯定了以哪根軸進行劃分,接下來就要考慮「怎麼劃分」。這時有多種策略能夠考慮: pbrt中應用到的有三種劃分策略:取中點劃分(SPLIT_MIDDLE),按等量劃分(SPLIT_EQUAL_COUNT),以及用表面積啓發式算法劃分(SPLIT_SAH, SAH=Surface Area Heuristic)。
 
1.2.1 SPLIT_MIDDLE
顧名思義,取中點劃分的意思就是在先前選取的軸上找到最靠兩側的物體的包圍盒,鏈接兩者包圍盒的重心獲得一條線段,取其中點做爲劃分點,中點以左劃分到左子樹,中點以右劃分到右子樹。順便提一下使用std::partition算法能夠快速實現這一目的。
 
這種劃分實現起來最爲簡單,但每每效果不是太好:由於物體的分佈每每不是均勻的。其中一種糟糕的狀況(a)是,某側子樹上可能會擁擠過多的物體,而另外一側子樹上卻太少。這對查找效率影響很大:想象一種極端狀況,對於有n個物體的場景,經過這樣的劃分可能會有n-1個物體落在了左子樹,而1個物體落在了右子樹。這種狀況下BVH的管理技術基本等於形同虛設,解決不了實際問題。
 
另外還有一種糟糕的狀況(b),就是包圍盒之間互相「重疊」(overlapped)的狀況。若是兩棵子樹對應的包圍盒「重疊」的越多,那麼一條射線穿過該區域時同時擊中兩子樹的機率也就越大,這就意味着兩棵子樹都得進行相交測試。若是全部的子樹都不得不進行相交測試,那便失去了「場景管理"本該具備的做用。
 
1.2.2 SPLIT_EQUAL_COUNT
按數量平分兩棵子樹,即左子樹擁有的物體數量與右子樹擁有的物體數量相等。使用std::nth_element算法能夠快速實現。
 
此種策略是對第一種」按中點劃分「策略的改進,對於處理(a)狀況有很大的改善。可是對於(b)狀況,依然一籌莫展。若是遇到(b)狀況出現,使用該策略性能也是很是低下的。
 
1.2.3 SPLIT_SAH
好東西老是留到最後面講。表面積啓發式算法(Surface Area Heuristic)應該是目前應付以上(a)(b)狀況最好的算法了,同時也是性能最高、成本最低的算法。該算法基於的理論是複雜度成本分析和機率論,這種同時涉足了數學與計算機科學的交叉理論使得它披上了一點高大上的光環。
 
從複雜度成本分析的角度看,假設場景中有1,2,...n個物體,若是不作場景管理的話,那就須要射線對每一個物體都作相交測試。假設對於第i個物體,其作射線相交測試的時間複雜度爲t(i),那麼整體的時間複雜度就爲t(1)+t(2)+...t(n) = ∑t(i)。這個值固然越小越好。t(i)是個相對值,表明所用的時間複雜度,並非真要求這個時間仍是咋地。能夠簡單設這個值爲單位1。 pbrt中,有一個簡單的假設是對每一個物體進行射線相交測試所用的時間複雜度都是相等的,皆爲1。因此∑t(i)能夠用n來代替。
 
再假設這樣一種劃分方式:將場景劃分爲兩個區域A和B,物體散落在AB兩區中。射線有可能會擊中A區,也可能會擊中B區。在遍歷前咱們固然沒法斷言射線究竟會擊中哪一個區。但毫無疑問,擊中哪一個區,就要遍歷散落在該區內全部的物體,∑t(i) in A or B。
 
射線究竟會擊中A區仍是B區,雖然沒法斷言,卻能夠」猜想「。這就用到機率論的理論了。假設擊中A區的機率爲p(A),擊中B區的機率爲p(B)。那麼綜合以上的分析,就會獲得整體的時間複雜度爲
 
cost(A,B) = p(A) *  ∑t(i) in A  + p(B) *  ∑t(j) in B
                = p(A) *  n in A  + p(B) *  m in B
其中n爲A區下的物體個數,m爲B區下的物體個數
 
我我的的一點理解,以爲這玩意難道不就是數學中的指望麼?(書中卻是沒提這茬)。同理,這個值越小越好,也就是說所求得的指望值越低越好(總體上覆雜度的平均值降到最低,即是最優解。這是我的的一點揣測)。
 
那麼,p(A)和p(B)怎麼算呢?這時就要用表面積估算了。這根植於一個樸素的想法:若是某物的表面積越大,那麼它被射線擊中的可能性也就越大。舉一個簡單的例子,假設空間中有一個6面立方體,一條射線從中穿過。問擊中其中一個面的機率是多少(1/6)?擊中其餘五個面呢(5/6)?這種狀況下實際上能夠簡單把表面積的比率(ratio)看做是被射線擊中的機率。面積比越大,被擊中的機率天然越大。我見到過圖形學中不少算法,都有相似的作法。
 
具體到這個算法中,表面積是經過節點的包圍盒的表面積(即長方體的表面積)求算的。仍然考慮一個父節點(C)下帶有左(A)右(B)子節點(子樹)這種狀況。父節點C的表面積爲S(C),左子節點A的表面積爲S(A),右子節點B的表面積爲S(B)。那麼擊中父節點下的左子節點A的機率爲p(A|C) = S(A)/S(C),擊中父節點下的右子節點B的機率爲p(B|C) = S(B)/S(C)。
 
 
注意S(A)/S(C)+S(B)/S(C) 是有可能大於S(C)的,由於S(A)與S(B)可能會發生」重疊「,這固然是咱們不喜歡的狀況,緣由上面已經講過。因此S(A)/S(C)+S(B)/S(C)越小(越接近S(C))咱們越喜歡。
 
在劃分一個節點表明的空間區域時,能夠經過不一樣的切法將該空間劃分紅兩個子區域。切法能夠平均等距地一刀一刀地切,也能夠耍點小手段帶點」智能「使其」自適應「。總之每次劃分,都會獲得兩個子區域A和B。那麼相應也會算出一個cost(A,B)來。比較全部劃分方案下所得的cost(A,B),取值最小的方案就是成本最低的劃分方案,也做爲劃分該節點的最終/優方案。以下圖所示,scheme1和scheme2就是兩種不一樣的劃分方案。
 
 
反思sah這種算法,想一想爲何它可以有效應付糟糕狀況(a)和(b)?個人理解是它綜合考慮了」分佈「(體如今因子∑t(i)=n)和」重疊「(體如今因子S(A)/S(C)=p(A|C))兩種狀況,兩者的乘積最小,表明檢測它所花的成本最小(咱們固然喜歡某個區域內需待檢測的物體越少越好,且該區域與其餘區域發生的」重疊「也越小越好了)。但這只是個人胡思亂想,沒有數學證實能夠支持這一分析。
 
sah的作法並不能徹底作到」不重疊「或者使劃分後的分佈就很「均勻」,但它每作一次劃分,選取的都是當前情形下最優的方案。所以稱它是一種「啓發式」(Heuristic)算法。
 
1.3 Compact BVH
構建好一棵BVH後能夠進一步優化。樹的結構是經過指針尋址下一個子節點的,與連續空間的數組存放數據的方式相比,不管內存的整齊程度仍是遍歷的速度都遜色很多。那能不能把這棵BVH轉換成一個數組呢?答案是確定的,並且也不難。按深度優先順序把遍歷的節點包裝一下(加點offset信息)依次放入數組中,就把這棵BVH「壓平」到一個數組中。這樣遍歷起這個數組那速度可就快多了。
 
 
 
2. Traversal
遍歷BVH差很少是件直截了當的事情。只不過這裏注意下若是作了Compact BVH優化的話,實際上是對一個數組進行遍歷,這時要經過算好offset的值來找到對應的節點(或是葉子)。
 
pbrt介紹了一種更加快速判斷射線與包圍盒相交的算法,但我沒有細看。這裏標記一下,留做之後研究。
 
另外要考慮的一個問題是,當發現射線與某個子節點相交的話,那麼有無必要再檢測下與另外一子節點是否相交?答案是要的。由於兩個節點沒法保證徹底「不重疊」,以下圖所示,頗有可能在檢測另外一子節點時發現了更近(closer)的交點。
 
 
還有一個問題是,當須要判斷射線是否與子節點相交時,應該先檢測左子節點呢仍是右子節點?答案取決於射線有可能會先與誰相交。若是射線經過的方向是從左到右,那就應該先檢測左子節點,反之就應該先檢測右子節點。由於上面講過兩棵子節點都要檢測(由於可能「重疊」),經過這種方法能夠提升檢測效率。由於若是不重疊的話,當判斷到另一棵子節點時就會當即返回了(不重疊的話就不可能有比當前相交點更近的值)。 以下圖所示。
 
 
 
 
 
 
  ---
(完)
相關文章
相關標籤/搜索