Recast Demo中BVH樹的構建

2021-10-25 10:13:23 字數 4439 閱讀 5374

首先介紹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 到根節點的路徑上經過的所有節點 包括兩端節點 的數量...