首先介紹bvh樹的資料結構:
//bvh(bounding volumn hierachy,chunk means cube)
struct rcchunkytrimesh
;inline
~rcchunkytrimesh()
rcchunkytrimeshnode* nodes;
//這裡用乙個陣列表示樹的節點,nodes代表根節點
int nnodes;
//節點總數
int* tris;
//乙個陣列,記錄了bvh樹里的三角形索引值(具體的頂點資料仍然存放在load模型時儲存的資料中)
int ntris;
//三角形的總數
int maxtrisperchunk;
//乙個葉節點,也就是乙個cube裡面最多儲存的三角形的數量
private
:// explicitly disabled copy constructor and copy assignment operator.
rcchunkytrimesh
(const rcchunkytrimesh&);
rcchunkytrimesh&
operator=(
const rcchunkytrimesh&);
};
這裡的chunk就是cube的意思,代表3d空間的乙個cube,不過這裡的cube是長方體,不是正方體
具體節點node的資料結構如下:
struct rcchunkytrimeshnode
;
在建立bvh樹之前,需要拿到場景的三角形資料float *verts
和三角面資料int* tris
,具體步驟如下:
1. 建立bvh樹
建立bvh,同時分配記憶體,bvh的資料資訊為nodes節點的資訊和儲存的三角形索引陣列資訊,**如下所示:
// 三角形數除以每個chunk的三角形數,得到chunk數
int nchunks =
(ntris + trisperchunk-1)
/ trisperchunk;
// 由於每個節點儲存的三角形數在[trisperchunk/2, trisperchunk]間
// trisperchunk+1個三角形就能占用兩個葉子node和兩個父節點的記憶體
// 所以每個chunk需要分配四個node節點,保證bvh有足夠的記憶體
cm->nodes =
new rcchunkytrimeshnode[nchunks*4]
;if(!cm-
>nodes)
return
false
;// 為vbh樹分配了tris的記憶體
cm->tris =
newint
[ntris*3]
;if(!cm-
>tris)
return
false
;cm-
>ntris = ntris;
2. 獲取所有三角形的aabb包圍盒
new乙個陣列,陣列大小為場景裡三角形的個數,這個陣列用來記錄所有三角形的2d的aabb,**如下所示:
// 代表2d的aabb
struct boundsitem
;// 為每乙個模型裡的三角形,建立乙個2d的aabb
// build tree
boundsitem* items =
new boundsitem[ntris];if
(!items)
return
false
;// 遍歷每乙個三角形,計算其aabb,並記錄三角形在原tris裡的索引
for(
int i =
0; i < ntris; i++
)}
3. 進行樹的劃分
這裡劃分的目標就是三角形,而且這些三角形都在樹的tris陣列裡,具體的劃分方法也很簡單,當前節點從樹的根節點開始:
所以這是乙個深度遞迴的過程,建立bvh樹的**如下:
int curtri =0;
int curnode =0;
// 劃分樹
subdivide
(items, ntris,
0, ntris, trisperchunk, curnode, cm-
>nodes, nchunks*
4, curtri, cm-
>tris, tris)
;
subdivide函式如下:
// 這是乙個遞迴函式,用來建立bvh樹,輸入的items代表三角形對應的bounds陣列
static
void
subdivide
(boundsitem* items,
int nitems,
int imin,
int imax,
int trisperchunk,
int& curnode, rcchunkytrimeshnode* nodes,
const
int maxnodes,
int& curtri,
int* outtris,
const
int* intris)
}else
else
if(axis ==1)
// 取中點,對兩邊各自建立新的樹
int isplit = imin+inum/2;
// left
subdivide
(items, nitems, imin, isplit, trisperchunk, curnode, nodes, maxnodes, curtri, outtris, intris)
;// right
subdivide
(items, nitems, isplit, imax, trisperchunk, curnode, nodes, maxnodes, curtri, outtris, intris)
;// 當走到這裡的時候,劃分子樹,說明此節點不為葉節點,所以其i值是負的
int iescape = curnode - icur;
// negative index means escape.實際上就是該節點下的所有子節點數(包括該節點自身)
node.i =
-iescape;
}}
至此,乙個bvh樹就建立完了,**也不複雜,下面舉乙個具體應用的**,給點乙個2d的長方形,找到與其相交的葉子節點(如果再想找與其相交的三角形,再去遍歷其內部的三角形就可以了)
int
(const rcchunkytrimesh* cm,
float p[2]
,float q[2]
,int
* ids,
const
int maxids)}if
(overlap || isleafnode)
i++;else
}return n;
}
bvh的子樹的aabb是否相交
我認為這裡的aabb應該是有可能相交的,因為排序三角形的時候是按照其aabb的bmin的x或z值排序的,三角形如果很大,可能會導致乙個非葉節點下的倆葉子節點的aabb相交,如下**所示:
static
intcompareitemx
(const
void
* va,
const
void
* vb)
static
intcompareitemy
(const
void
* va,
const
void
* vb)
// 如果不可以放在同乙個cube裡,那麼需要進行切分
// split
calcextends
(items, nitems, imin, imax, node.bmin, node.bmax)
;int axis =
longestaxis
(node.bmax[0]
- node.bmin[0]
, node.bmax[1]
- node.bmin[1]
);// 沿著長邊進行排序
if(axis ==0)
else
if(axis ==1)
維基百科bounding volume hierarchy
再學一周光線追蹤 bvh樹流程
蒙特卡洛光線追蹤技術系列 見 蒙特卡洛光線追蹤技術 這次詳細分析一下 再學一周光線追蹤 裡面bvh樹和包圍盒繫結的流程,為了加入三角麵片來進行優化。在hitable類的派生類sphere中只有乙個返回項bounding box,返回sphere的包圍盒。但是sphere和這個返回的包圍盒並沒有直接聯...
DevExpress中TreeList樹樣式調整
devexpress的treelist預設是沒有樹狀線的,修改treelinestyle屬性無效,這對於tree並不好看。官方解釋說對於devexpress的標準主題是不支援treelist有treeline的 不是技術問題,是設計理念不同 如devexpress style,devexpress ...
樹中節點和
給定一棵 n 個節點組成的樹。樹中節點編號為 1 sim n 1 號節點為樹的根節點。樹中的每個節點 v 都具有乙個非負整數權值 a 我們用 s 來表示從節點 v 到根節點的路徑上經過的所有節點 包括兩端節點 的權值之和 用 h 來表示從節點 v 到根節點的路徑上經過的所有節點 包括兩端節點 的數量...