-
Notifications
You must be signed in to change notification settings - Fork 1
/
BVH.cpp
224 lines (194 loc) · 6.54 KB
/
BVH.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//
// Created by 孙万捷 on 16/4/25.
//
#include "BVH.h"
#define MAX_LEAF_PRIM_NUM 8
static constexpr uint32_t nBuckets = 16;
BVH::BVH(ObjMesh& _mesh)
{
mesh = _mesh;
//build work list
workList.reserve(mesh.faces.size());
for(auto i = 0; i < mesh.faces.size(); ++i)
workList.push_back(BVHPrimitiveInfo(i, BBox(mesh.vertices[mesh.faces[i].x], mesh.vertices[mesh.faces[i].y], mesh.vertices[mesh.faces[i].z])));
//recursive build
std::cout<<"Building BVH..."<<std::endl;
orderedPrims.reserve(mesh.faces.size());
root = RecursiveBuild(0, workList.size());
std::cout<<"Totoal nodes: "<<totalNodes<<std::endl;
std::cout<<"Max depth: "<<maxDepth<<std::endl;
//replace mesh faces order with ordered one
mesh.faces.swap(orderedPrims);
//build linear bvh
lbvh.reserve(totalNodes);
for(auto i = 0; i < totalNodes; ++i)
lbvh.push_back(LBVHNode());
uint32_t offset = 0;
Flatten(root, &offset);
std::cout<<"Root max: ("<<lbvh[0].bMax.x<<", "<<lbvh[0].bMax.y<<", "<<lbvh[0].bMax.z<<")"<<std::endl;
std::cout<<"Root min: ("<<lbvh[0].bMin.x<<", "<<lbvh[0].bMin.y<<", "<<lbvh[0].bMin.z<<")"<<std::endl;
}
BVH::~BVH()
{
Delete(root);
}
void BVH::Delete(BVHNode* node)
{
if(node->left != NULL)
{
Delete(node->left);
}
if(node->right != NULL)
{
Delete(node->right);
}
delete node;
}
uint32_t BVH::Flatten(BVHNode *node, uint32_t* offset)
{
LBVHNode* linearNode = &lbvh[*offset];
linearNode->bMax = node->bounds.bmax;
linearNode->bMin = node->bounds.bmin;
uint32_t myOffset = (*offset)++;
if(node->nPrims > 0)
{
linearNode->primitiveOffset = node->firstPrimOffset;
linearNode->nPrimitives = node->nPrims;
}
else
{
linearNode->nPrimitives = 0;
Flatten(node->left, offset);
linearNode->rightChildOffset = Flatten(node->right, offset);
}
return myOffset;
}
BVHNode* BVH::RecursiveBuild(uint32_t start, uint32_t end, uint32_t depth)
{
maxDepth = fmaxf(depth, maxDepth);
totalNodes++;
BVHNode* node = new BVHNode;
//compute bounds of all primitives in BVH node
BBox bbox;
for(auto i = start; i < end; ++i)
bbox = Union(bbox, workList[i].bounds);
uint32_t nPrims = end - start;
//if number of primitives are less than threshold, create leaf node
if(nPrims <= MAX_LEAF_PRIM_NUM)
{
uint32_t firstPrimOffset = orderedPrims.size();
for(auto i = start; i < end; ++i)
{
auto pIdx = workList[i].pIdx;
orderedPrims.push_back(mesh.faces[pIdx]);
}
node->InitLeaf(firstPrimOffset, nPrims, bbox);
}
else
{
//compute bound of primitive centroids, choose split dimension
BBox centroidBounds;
for(auto i = start; i < end; ++i)
centroidBounds = Union(centroidBounds, workList[i].bounds.bcenter);
// split along max span axis
int dim = centroidBounds.MaxExtent();
//partition primitives into two sets and build children
uint32_t mid = (end + start) / 2;
// if max span axis is too small, create a leaf node
if((centroidBounds.bmax[dim] - centroidBounds.bmin[dim]) < 1e-4)
{
uint32_t firstPrimOffset = orderedPrims.size();
for(auto i = start; i < end; ++i)
{
auto pIdx = workList[i].pIdx;
orderedPrims.push_back(mesh.faces[pIdx]);
}
node->InitLeaf(firstPrimOffset, nPrims, bbox);
return node;
}
//partition primitives based on SAH
std::vector<BucketInfo> buckets(nBuckets);
float extent = centroidBounds.bmax[dim] - centroidBounds.bmin[dim];
for(auto i = start; i < end; ++i)
{
uint32_t b = nBuckets * ((workList[i].bounds.bcenter[dim] - centroidBounds.bmin[dim]) / extent);
if(b == nBuckets) b -= 1;
buckets[b].count++;
buckets[b].bounds = Union(buckets[b].bounds, workList[i].bounds);
}
//compute costs for splitting after each bucket
float cost[nBuckets - 1];
for(auto i = 0; i < nBuckets - 1; ++i)
{
BBox b0, b1;
int count0 = 0, count1 = 0;
for(auto j = 0; j <= i; ++j)
{
b0 = Union(b0, buckets[j].bounds);
count0 += buckets[j].count;
}
for(auto j = i + 1; j < nBuckets; ++j)
{
b1 = Union(b1, buckets[j].bounds);
count1 += buckets[j].count;
}
cost[i] = (count0 * b0.SurfaceArea() + count1 * b1.SurfaceArea()) / bbox.SurfaceArea();
}
//find best split
float minCost = cost[0];
uint32_t bestSplit = 0;
for(auto i = 1; i < nBuckets - 1; ++i)
{
if(cost[i] < minCost)
{
minCost = cost[i];
bestSplit = i;
}
}
//either create leaf or split at selected SAH bucket
if(nPrims > MAX_LEAF_PRIM_NUM || minCost < nPrims)
{
auto compare = [&](BVHPrimitiveInfo& p) {
auto b = nBuckets * ((p.bounds.bcenter[dim] - centroidBounds.bmin[dim]) / extent);
b = (b == nBuckets) ? (b - 1) : b;
return b <= bestSplit;
};
BVHPrimitiveInfo *pmid = std::partition(&workList[start], &workList[end - 1] + 1, compare);
mid = pmid - &workList[0];
}
else
{
uint32_t firstPrimOffset = orderedPrims.size();
for(auto i = start; i < end; ++i)
{
auto pIdx = workList[i].pIdx;
orderedPrims.push_back(mesh.faces[pIdx]);
}
node->InitLeaf(firstPrimOffset, nPrims, bbox);
return node;
}
node->InitInner(RecursiveBuild(start, mid, depth + 1), RecursiveBuild(mid, end, depth + 1));
}
return node;
}
//utility
void export_linear_bvh(const BVH& bvh, std::string filename)
{
std::ofstream out(filename);
if(!out)
{
std::cerr<<"Unable to open file: "<<filename<<std::endl;
exit(-1);
}
for(const auto& item : bvh.lbvh)
{
out<<item.bMin.x<<' '<<item.bMin.y<<' '<<item.bMin.z<<' ';
out<<item.bMax.x<<' '<<item.bMax.y<<' '<<item.bMax.z<<' ';
//if(item.nPrimitives == 0)
// out<<item.rightChildOffset<<' ';
//else
// out<<-1<<' ';
out<<item.nPrimitives<<'\n';
}
std::cout<<"Linear BVH exported"<<std::endl;
}