今天來和大家研究一下BSP樹的應用。
首先簡單介紹一下BSP樹的相關內容。
BSP (Binary Space Partition)表示二叉空間分割。
使用這種方法可以使我們在運行時使用一個預先計算好的樹來得到多邊形從後向前的列表,它的複雜度為O(n)。
它的基本思想是基於這樣一個事實:任何平面都可以將空間分割成兩個半空間。
所有位於這個平面的一側的點定義了一個半空間,位於另一側的點定義了另一個半空間:
此外,如果我們在任何半空間中有一個平面,它會進一步將此半空間分割為更小的兩個子空間。
我們可以使用多邊形列表將這一過程一直進行下去,將子空間分割得越來越小,直到構造成一個二叉樹。
在這個樹中,一個進行分割的多邊形被儲存在樹的節點,所有位於子空間中的多邊形都在相應的子樹上。
當然,這一規則使用於樹中每一個節點。
為了簡單起見,我們選擇一個這樣一個平面投影,在它上面,所有多邊形都能映射為直線段。
下面我們從二維平面來解析一下BSP樹的應用。首先從多邊形B(圖中線段B)開始構造一個BSP樹。
多邊形B所在的平面將空間分割為兩個部分,使得多邊形D和E位於同一個半空間中,多邊形C在另一個半空間中。
在這個例子中, 多邊形A穿越了兩個半空間,這樣,它就不能十分明確的被分配到任何一個半空間中。
但是,如果我們將這個多邊形從它與分割平面相交的地方分為兩個部分一個命名為A1,
另一個命名為A2,這樣,A1就和D、E在同一個半空間中,A2和C在同一個半空間中。
表述了這一過程。
我們現在已經將問題分成了兩個子問題。我們可以在子樹中再次使用上述演算法。
例如,我們在左邊子樹中選擇E作為分割多邊形,在右邊子樹中選擇A2作為分割多邊形。
這樣,我們將建立下面的結構樹。
必須注意,任何給定的BSP樹都不是唯一的。
我們可以對同樣的多邊形找到多個有效二叉分割。依靠我們選擇來進行分割的多邊形的順序,可以得到不同的樹。
例如,在中,我們可以看到另一個樹,它也建立在前面我們討論的多邊形上。
我們檢查觀察者的位置和位於樹頂部的多邊形之間的關係。
很明顯,當這個多邊形將空間分割為兩個部分時,觀察者必須位於其中的一個半空間中。
當然,位於同一半空間中的多邊形要比另一半空間中的多邊形離觀察者更近。
基於這樣的事實,如果我們首先將較遠處半空間中的多邊形放置在最終的列表中,
然後放置根多邊形,再放置與觀察者在同一半空間中的多邊形,這樣就很容易得到多邊形從後向前的順序了。
我們對每一個子樹都重複同樣的過程,在每一個層級中選擇相應的順序,最終,就會得到正確的多邊型的順序。
這一演算法的一個優點就是無論觀察者位於情境中的什麼位置,
無論觀察者的朝向如何,它都可以很好的進行工作。
例如,在中,倘若攝像機在D點和E點,那麼他們的產生BSP樹的順序就是不一樣的。
但是他們對於各自的情況都是正確的。
這樣,如果我們預先為一個多邊形模型計算一個BSP樹,那麼在運行時,
我們只需要根據觀察者的位置調用這個樹,執行樹遍曆過程,就可以產生用於隱面消除的畫家演算法所需的從後向前的多邊形順序。
在這個演算法中,在樹的每一個節點處所作的判定,都依賴於觀察者位於該節點多邊形所產生的哪一個半空間中。
利用我們所討論過的事實,我們可以看到,如果將觀察者位置的座標代入給定多邊形的平面方程式中,
結果數值的符號如果是正號,就表示觀察者位於該多邊形的法向量所指向的半空間中,
負號表示位於另一個半空間中, 0值表示他位於這個多邊形所在的平面上。
最後一種情況,對於遍曆整個BSP樹的意圖來說,意味著半空間在螢幕上的投影不相交,
並且我們可以在這一階段的遍曆過程中選擇任何子樹的順序。
相同的計算也要在預先計算一個BSP樹時使用到。我們需要決定不同的多邊形應該被放置在哪個子樹中。
從可實現性的觀點出發,預先計算一個BSP樹的過程可以被描述成下面的形式:對多邊形集合,我們選擇一個多邊形。
進一步計算該多邊形的平面方程式。對剩餘的多邊形,我們用所說的方程式檢查它們的所有頂點。如果所有頂點都是負值,
那麼多邊形就放置在一個子樹中;如果都是正值,那麼多邊形就放置在另一個子樹中;
如果結果有正有負,那麼多邊形就被分為兩部分,分別放置在兩個子樹中。
一旦我們將所有多邊形分配到了正確的半空間中,我們就可以對子樹進一步調用同樣的方法來進行處理,
直到當前的子表只包含一個多邊形為止。
一個多邊形被任何平面所分割的問題可以當作一個裁剪問題來處理。
解決這一問題的演算法只與我們在裁剪問題時所討論的演算法又很小的差別。
唯一明顯的差別就是在二進位搜尋邊緣裁剪過程中,我們將使用分割多邊形的平面方程式來找到邊的中點的位置。
我們考查了樹的建立和遍曆之後,仍然有一些問題需要解決。
當我們構建一個樹時,我們可以選擇剩餘多邊形中的任何一個來分割空間。
選擇不同的多邊形會導致不同的樹的結構。因此,我們就應該考慮選擇哪個多邊形有助於演算法的效率。
有些多邊形會導致剩餘多邊形更多的分割。
每一個多邊形在通過渲染管道時都有一定的系統消耗,因此多邊形越少,效能就越好。
我們可以利用判據來選擇有較少分割的多邊形。
使用判據來平衡BSP樹,並不需要每一級中的子樹中的多邊形的數量都相同,
因為它不會影響已耗用時間。樹的遍曆總是假設至少每次都取一個多邊形,因此平衡不會影響效能——我們仍然不得不每次取每一個多邊形。
另一方面,一個平衡的樹可以以較少的迭代調用來執行遍曆。我們可以將平衡作為第二判據來使用。
總之,使用BSP樹來進行從後向前排序的最大優點就是演算法啟動並執行複雜性較低 。
這種方法也解決了多邊形的多重交疊和多邊形穿越問題。但是,通過使用一個預計算結構,我們已經失去了一定的靈活性。
如果多邊形的排列在運行時發生了改變, BSP樹就必鬚髮生相應的改變。由於計算量非常巨大,我們不能這樣做。
因此,這種演算法對於情境在運行時發生改變的情況就不能使用了。
應該注意,只有當多邊形經曆不同的變換設定時樹才會受到影響。如果所有的多邊形都使用同樣的變換,
那麼分割仍然是正確的,樹也將不會受到影響。這樣,情境中的一個動態物體,它在世界中移動或者是旋轉,
仍然可以使用同樣的BSP樹。如果物體中的一部分相對於其他物體發生了移動,那我們就要使用其它的演算法了。