3D遊戲引擎中常見的三維場景管理方法

  對於一個有不少物體的3D場景來講,渲染這個場景最簡單的方式就是用一個List將這些物體進行存儲,並送入GPU進行渲染。固然,這種作法在效率上來講是至關低下的,由於真正須要渲染的物體應該是視椎體內的物體。除此以外,從裁剪算法和碰撞檢測等算法的效率來講,使用這種數據結構也是至關低效的。比較好的方式是使用具備層次結構的空間數據結構存儲待渲染的物體,如BVH(包圍體層次結構)、BSP(二叉空間分割)樹、四叉樹、八叉樹和模糊K-D樹等,在進行空間查找的時候將時間複雜度從O(n)下降到O(logn)。固然,對應的代價是每幀更新的時候,須要更新對應的空間數據結構。本文主要對BVH、BSP和八叉樹進行介紹。算法

一、BVH(bounding volume hierarchies,包圍體層次結構)數據結構

  BV(bounding volume,包圍體)是包含一組物體的空間體,它要比所包含的幾何物體形狀簡單得多,因此在使用包圍體進行碰撞檢測等操做的時候比使用物體自己更快。常見的包圍體有AABB(axis-aligned bounding boxes,軸對齊包圍盒),OBB(oriented bounding boxes,有向包圍盒),以及k-DOP(discrete oriented polytope,離散定向多面體),詳細解釋見維基百科性能

  對於三維場景的實時渲染來講,BVH是最常使用的數據結構,例如,BVH常常用於視椎體裁剪。場景以層次樹形結構進行組織,包含一個根節點、內部節點和葉子節點。最高節點是根,沒有父節點;葉子節點保存着須要繪製的實際幾何體(BVH只能存儲幾何體,實際渲染的物體除了幾何屬性還有其餘屬性,通常使用場景圖表示,參看維基百科)。樹中的每一個節點,包括葉子節點,都有一個包圍體,能夠將其子樹的全部幾何體包圍起來,這就是BVH(包圍體層次結構)名字的來源,圖1爲BVH的示例。大數據

圖1 BVH示例,左圖爲6個物體的簡單場景,右圖爲對應的BVHspa

  在場景中的物體移動的時候,須要對BVH進行更新。若是物體移動之後仍然在原先的包圍體內,則不須要更新;若不在,則刪除這個物體所在節點,並從新計算其父節點的包圍體,而後,從根節點開始,以遞歸形式將這個節點插入這棵樹中。另外一種方法則是以遞歸形式增大父節點的包圍體,直到這個包圍體能夠包含這個子節點爲止。不管使用哪一種方法,隨着編輯操做的增多,這棵樹會變得愈來愈不平衡,效率也會愈來愈低。3d

二、BSP(binary space partitioning,二叉空間分割)樹指針

  BSP樹在1969年由Shumacher首次提出,當時並未想到能成爲開發娛樂產品的算法,但從90年代初BSP樹就已經被用於遊戲行業來改善性能,並使利用地圖中更多細節成爲可能。第一個使用該技術的遊戲是Doom,由遊戲行業中的兩位傳奇人物JohnCarmack和John Romero創立。blog

  在計算機圖形學中,BSP樹有兩種不一樣的形式:分別爲軸對齊(axis-aligned)和多邊形對齊(polygon-aligned)。要建立BSP樹,首先用一個平面將空間一分爲二,而後將幾何體按類別劃分到這兩個空間中,隨後以遞歸形式反覆進行這個過程。這種樹有一個很是有趣的特性,若是按照必定的方式對樹進行遍歷,那麼會從某個視點將這棵樹包含的幾何體進行排序(對於軸對齊的方式來講,它是粗略的排序;對於多邊形對齊方式來講,它的準確的排序)。在Z-Buffer問世以前,基於多邊形對齊的BSP樹成爲3D遊戲進行場景排序的最佳方案。排序

 2.一、軸對齊BSP樹遞歸

  軸對齊BSP樹的建立方式以下:首先,將整個場景包圍在一個AABB中,選取xyz其中一個軸,生成一個與之垂直的平面,將該AABB分爲兩個小AABB,而後以遞歸的方式繼續對生成的AABB進行分割,直到樹達到最大深度或AABB中包含的幾何圖元數量低於用戶定義的某個閾值。軸對齊BSP樹的結構如圖2所示。

圖2 BSP樹結構

  在分割的時候,有些物體會與分割平面相交,對這些物體有如下幾種處理方法:1)存儲在分割平面所在的節點中,如圖2中的三角形也能夠存儲在1b中(圖2採用的是第二種方法);2)存儲在多個葉子節點,如圖2所示;3)將這個物體由這個平面分爲兩個物體。第一種方法效率比較低,好比物體比較小,可是剛好被平面分割,不得不將其存在較高的節點中,因此實際中不多采用這種作法;第二種方法會致使相同的物體被繪製屢次,通常使用timestamping方法對其進行改進,即對繪製過的幾何體作一個標記,繪製前對這個標記進行檢查,若已經繪製過,則再也不繪製,這種方法使用的比較多;第三種方法因爲要對圖元進行分割,因此計算量比較大,並且對於動態物體的渲染不太方便。

  分割平面的選取也有多種方法:1)按照xyz-xyz……的順序進行循環分割,若是每次都選擇中間位置,則結果和八叉樹同樣。固然,也能夠隨意選定位置,BSP樹相對於八叉樹的優點之一就是平面的位置能夠隨意選擇。2)對AABB的最長邊進行分割。3)經過相關算法(geometric probablity theory)計算出近似最優的分割平面,該分割平面將盡量少的與幾何體相交。

  軸對齊BSP樹具備粗略排序的特徵,對遮擋裁剪(occlusion culling)等算法具備較好的加速做用。在遮擋裁剪中,若是可以按照從前日後的順序進行渲染,則能夠減小像素着色器的負擔。使用軸對齊BSP樹,從根節點開始,先遍歷靠近視點一側的全部物體,再遍歷遠離視點的全部物體,對於每一個子節點採用這種方式遞歸,則能夠作到近似的從前日後進行渲染。因爲它沒有對葉子節點內的幾何體進行排序,並且一個物體可能在多個葉子節點中,因此軸對齊BSP樹只是粗略的排序。

 2.二、多邊形對齊BSP樹

  多邊形對齊的BSP樹採用多邊形所在的平面進行空間分割,具體方法以下:在根節點處選取一個多邊形,用這個多邊形所在平面將場景中剩餘的多邊形分爲兩組。對於與分割平面相交的多邊形,沿着相交線將這個多邊形分爲兩個部分。接下來採用一樣的方式對這些多邊形進行遞歸分割,直到全部的多邊形都在這棵BSP樹中,如圖3所示。

圖3 多邊形對齊BSP樹示意圖

  多邊形對齊BSP樹的建立很是耗時,適合靜態場景,它的優勢是對於給定視點,能夠按照嚴格排序的順序進行遍歷,在沒有Z-Buffer的DOS時代,這種方法是3D遊戲製做中一種很好的方法,著名的FPS遊戲Doom和Quake都使用了這種方法。固然,如今已經再也不使用了這種方法(它的好處被Z-Buffer取代,其缺點是隻適用於靜態場景,使用不便)。

三、八叉樹

  八叉樹相似軸對齊BSP樹。沿着軸對齊包圍盒的三條軸對其進行分割,分割點必須位於包圍盒的中心點,以這種方式生成8個新的包圍盒。八叉樹經過將整個場景包含在一個最小的軸對齊包圍盒中進行構造,遞歸分割,直到達到最大遞歸層次或包圍盒中包含的圖元小於某個閾值,其分割過程如圖4所示。八叉樹的使用方式與軸對齊BSP樹同樣,能夠處理同類型的查詢,也能夠用於遮擋裁剪算法中。因爲八叉樹是具備規則的結構,因此有些查詢會比BSP樹高效。

圖4 八叉樹分割過程

  在八叉樹的結構中,一般將物體保存在葉子節點中,其中有些物體必須保存在多個葉子節點中(2.1節第二段的第二種方法)。這種作法的一個最大弊端是增大數據量,而若是使用指針,則會致使八叉樹的編輯變得更加困難。「鬆散的八叉樹」算法對這個問題進行了改進。

四、空間結構的選取

  目前爲止,沒有一種空間結構絕對的最優,根據不一樣場合選擇不一樣的空間結構是一個明智的作法。八叉樹和BSP樹相比,因爲其不須要存儲分割平面的信息(由於每次都是在包圍盒的中心點進行分割),因此要比BSP效率更高。可是這不是絕對的,例如在一個細長的走廊場景中,用BSP明顯更合適,由於對沿着走廊的軸分割次數確定要比另外兩個軸來得多,若是使用八叉樹,要麼浪費另外兩個軸的分割空間,要麼沿着走廊的軸分割不夠細。

  通常來講,對於室內場景使用BSP樹,由於1)室內場景遮擋比較嚴重,使用BSP樹在特定的位置分割有助於提高效率;2)室內極可能朝某個方向延伸比較多,好比一條細長的走廊。對於大規模室外場景,使用八叉樹比較好,由於場景中的物體比較分散,並且不會出現太多的遮擋,因爲不用存儲分割平面位置,使用八叉樹這種規則的空間結構可以提升效率。固然,若是這個大規模室外場景的物體主要集中在地面,使用四叉樹進行空間管理會比較好。

相關文章
相關標籤/搜索