Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
BoundingIntervalHierarchy.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
7
8#ifdef _MSC_VER
9 #define isnan _isnan
10#else
11 #define isnan std::isnan
12#endif
13
14void BIH::buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats)
15{
16 // create space for the first node
17 tempTree.push_back(int32(3 << 30)); // dummy leaf
18 tempTree.insert(tempTree.end(), 2, 0);
19 //tempTree.add(0);
20
21 // seed bbox
22 AABound gridBox = { bounds.low(), bounds.high() };
23 AABound nodeBox = gridBox;
24 // seed subdivide function
25 subdivide(0, dat.numPrims - 1, tempTree, dat, gridBox, nodeBox, 0, 1, stats);
26}
27
28void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats)
29{
30 if ((right - left + 1) <= dat.maxPrims || depth >= MAX_STACK_SIZE)
31 {
32 // write leaf node
33 stats.updateLeaf(depth, right - left + 1);
34 createNode(tempTree, nodeIndex, left, right);
35 return;
36 }
37 // calculate extents
38 int axis = -1, prevAxis, rightOrig;
39 float clipL = G3D::fnan(), clipR = G3D::fnan(), prevClip = G3D::fnan();
40 float split = G3D::fnan(), prevSplit;
41 bool wasLeft = true;
42 while (true)
43 {
44 prevAxis = axis;
45 prevSplit = split;
46 // perform quick consistency checks
47 G3D::Vector3 d( gridBox.hi - gridBox.lo );
48 if (d.x < 0 || d.y < 0 || d.z < 0)
49 throw std::logic_error("negative node extents");
50 for (int i = 0; i < 3; i++)
51 {
52 if (nodeBox.hi[i] < gridBox.lo[i] || nodeBox.lo[i] > gridBox.hi[i])
53 {
54 //UI.printError(Module.ACCEL, "Reached tree area in error - discarding node with: %d objects", right - left + 1);
55 throw std::logic_error("invalid node overlap");
56 }
57 }
58 // find longest axis
59 axis = d.primaryAxis();
60 split = 0.5f * (gridBox.lo[axis] + gridBox.hi[axis]);
61 // partition L/R subsets
62 clipL = -G3D::inf();
63 clipR = G3D::inf();
64 rightOrig = right; // save this for later
65 float nodeL = G3D::inf();
66 float nodeR = -G3D::inf();
67 for (int i = left; i <= right;)
68 {
69 int obj = dat.indices[i];
70 float minb = dat.primBound[obj].low()[axis];
71 float maxb = dat.primBound[obj].high()[axis];
72 float center = (minb + maxb) * 0.5f;
73 if (center <= split)
74 {
75 // stay left
76 i++;
77 if (clipL < maxb)
78 clipL = maxb;
79 }
80 else
81 {
82 // move to the right most
83 int t = dat.indices[i];
84 dat.indices[i] = dat.indices[right];
85 dat.indices[right] = t;
86 right--;
87 if (clipR > minb)
88 clipR = minb;
89 }
90 nodeL = std::min(nodeL, minb);
91 nodeR = std::max(nodeR, maxb);
92 }
93 // check for empty space
94 if (nodeL > nodeBox.lo[axis] && nodeR < nodeBox.hi[axis])
95 {
96 float nodeBoxW = nodeBox.hi[axis] - nodeBox.lo[axis];
97 float nodeNewW = nodeR - nodeL;
98 // node box is too big compare to space occupied by primitives?
99 if (1.3f * nodeNewW < nodeBoxW)
100 {
101 stats.updateBVH2();
102 int nextIndex = tempTree.size();
103 // allocate child
104 tempTree.push_back(0);
105 tempTree.push_back(0);
106 tempTree.push_back(0);
107 // write bvh2 clip node
108 stats.updateInner();
109 tempTree[nodeIndex + 0] = (axis << 30) | (1 << 29) | nextIndex;
110 tempTree[nodeIndex + 1] = floatToRawIntBits(nodeL);
111 tempTree[nodeIndex + 2] = floatToRawIntBits(nodeR);
112 // update nodebox and recurse
113 nodeBox.lo[axis] = nodeL;
114 nodeBox.hi[axis] = nodeR;
115 subdivide(left, rightOrig, tempTree, dat, gridBox, nodeBox, nextIndex, depth + 1, stats);
116 return;
117 }
118 }
119 // ensure we are making progress in the subdivision
120 if (right == rightOrig)
121 {
122 // all left
123 if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
124 // we are stuck here - create a leaf
125 stats.updateLeaf(depth, right - left + 1);
126 createNode(tempTree, nodeIndex, left, right);
127 return;
128 }
129 if (clipL <= split) {
130 // keep looping on left half
131 gridBox.hi[axis] = split;
132 prevClip = clipL;
133 wasLeft = true;
134 continue;
135 }
136 gridBox.hi[axis] = split;
137 prevClip = G3D::fnan();
138 }
139 else if (left > right)
140 {
141 // all right
142 if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
143 // we are stuck here - create a leaf
144 stats.updateLeaf(depth, right - left + 1);
145 createNode(tempTree, nodeIndex, left, right);
146 return;
147 }
148 right = rightOrig;
149 if (clipR >= split) {
150 // keep looping on right half
151 gridBox.lo[axis] = split;
152 prevClip = clipR;
153 wasLeft = false;
154 continue;
155 }
156 gridBox.lo[axis] = split;
157 prevClip = G3D::fnan();
158 }
159 else
160 {
161 // we are actually splitting stuff
162 if (prevAxis != -1 && !isnan(prevClip))
163 {
164 // second time through - lets create the previous split
165 // since it produced empty space
166 int nextIndex = tempTree.size();
167 // allocate child node
168 tempTree.push_back(0);
169 tempTree.push_back(0);
170 tempTree.push_back(0);
171 if (wasLeft) {
172 // create a node with a left child
173 // write leaf node
174 stats.updateInner();
175 tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex;
176 tempTree[nodeIndex + 1] = floatToRawIntBits(prevClip);
177 tempTree[nodeIndex + 2] = floatToRawIntBits(G3D::inf());
178 } else {
179 // create a node with a right child
180 // write leaf node
181 stats.updateInner();
182 tempTree[nodeIndex + 0] = (prevAxis << 30) | (nextIndex - 3);
183 tempTree[nodeIndex + 1] = floatToRawIntBits(-G3D::inf());
184 tempTree[nodeIndex + 2] = floatToRawIntBits(prevClip);
185 }
186 // count stats for the unused leaf
187 depth++;
188 stats.updateLeaf(depth, 0);
189 // now we keep going as we are, with a new nodeIndex:
190 nodeIndex = nextIndex;
191 }
192 break;
193 }
194 }
195 // compute index of child nodes
196 int nextIndex = tempTree.size();
197 // allocate left node
198 int nl = right - left + 1;
199 int nr = rightOrig - (right + 1) + 1;
200 if (nl > 0) {
201 tempTree.push_back(0);
202 tempTree.push_back(0);
203 tempTree.push_back(0);
204 } else
205 nextIndex -= 3;
206 // allocate right node
207 if (nr > 0) {
208 tempTree.push_back(0);
209 tempTree.push_back(0);
210 tempTree.push_back(0);
211 }
212 // write leaf node
213 stats.updateInner();
214 tempTree[nodeIndex + 0] = (axis << 30) | nextIndex;
215 tempTree[nodeIndex + 1] = floatToRawIntBits(clipL);
216 tempTree[nodeIndex + 2] = floatToRawIntBits(clipR);
217 // prepare L/R child boxes
218 AABound gridBoxL(gridBox), gridBoxR(gridBox);
219 AABound nodeBoxL(nodeBox), nodeBoxR(nodeBox);
220 gridBoxL.hi[axis] = gridBoxR.lo[axis] = split;
221 nodeBoxL.hi[axis] = clipL;
222 nodeBoxR.lo[axis] = clipR;
223 // recurse
224 if (nl > 0)
225 subdivide(left, right, tempTree, dat, gridBoxL, nodeBoxL, nextIndex, depth + 1, stats);
226 else
227 stats.updateLeaf(depth + 1, 0);
228 if (nr > 0)
229 subdivide(right + 1, rightOrig, tempTree, dat, gridBoxR, nodeBoxR, nextIndex + 3, depth + 1, stats);
230 else
231 stats.updateLeaf(depth + 1, 0);
232}
233
234bool BIH::writeToFile(FILE* wf) const
235{
236 uint32 treeSize = tree.size();
237 uint32 check=0, count;
238 check += fwrite(&bounds.low(), sizeof(float), 3, wf);
239 check += fwrite(&bounds.high(), sizeof(float), 3, wf);
240 check += fwrite(&treeSize, sizeof(uint32), 1, wf);
241 check += fwrite(&tree[0], sizeof(uint32), treeSize, wf);
242 count = objects.size();
243 check += fwrite(&count, sizeof(uint32), 1, wf);
244 check += fwrite(&objects[0], sizeof(uint32), count, wf);
245 return check == (3 + 3 + 2 + treeSize + count);
246}
247
248bool BIH::readFromFile(FILE* rf)
249{
250 uint32 treeSize;
251 G3D::Vector3 lo, hi;
252 uint32 check=0, count=0;
253 check += fread(&lo, sizeof(float), 3, rf);
254 check += fread(&hi, sizeof(float), 3, rf);
255 bounds = G3D::AABox(lo, hi);
256 check += fread(&treeSize, sizeof(uint32), 1, rf);
257 tree.resize(treeSize);
258 check += fread(&tree[0], sizeof(uint32), treeSize, rf);
259 check += fread(&count, sizeof(uint32), 1, rf);
260 objects.resize(count); // = new uint32[nObjects];
261 check += fread(&objects[0], sizeof(uint32), count, rf);
262 return uint64(check) == uint64(3 + 3 + 1 + 1 + uint64(treeSize) + uint64(count));
263}
264
265void BIH::BuildStats::updateLeaf(int depth, int n)
266{
267 numLeaves++;
268 minDepth = std::min(depth, minDepth);
269 maxDepth = std::max(depth, maxDepth);
270 sumDepth += depth;
271 minObjects = std::min(n, minObjects);
272 maxObjects = std::max(n, maxObjects);
273 sumObjects += n;
274 int nl = std::min(n, 5);
275 ++numLeavesN[nl];
276}
277
279{
280 printf("Tree stats:\n");
281 printf(" * Nodes: %d\n", numNodes);
282 printf(" * Leaves: %d\n", numLeaves);
283 printf(" * Objects: min %d\n", minObjects);
284 printf(" avg %.2f\n", (float) sumObjects / numLeaves);
285 printf(" avg(n>0) %.2f\n", (float) sumObjects / (numLeaves - numLeavesN[0]));
286 printf(" max %d\n", maxObjects);
287 printf(" * Depth: min %d\n", minDepth);
288 printf(" avg %.2f\n", (float) sumDepth / numLeaves);
289 printf(" max %d\n", maxDepth);
290 printf(" * Leaves w/: N=0 %3d%%\n", 100 * numLeavesN[0] / numLeaves);
291 printf(" N=1 %3d%%\n", 100 * numLeavesN[1] / numLeaves);
292 printf(" N=2 %3d%%\n", 100 * numLeavesN[2] / numLeaves);
293 printf(" N=3 %3d%%\n", 100 * numLeavesN[3] / numLeaves);
294 printf(" N=4 %3d%%\n", 100 * numLeavesN[4] / numLeaves);
295 printf(" N>4 %3d%%\n", 100 * numLeavesN[5] / numLeaves);
296 printf(" * BVH2 nodes: %d (%3d%%)\n", numBVH2, 100 * numBVH2 / (numNodes + numLeaves - 2 * numBVH2));
297}
#define MAX_STACK_SIZE
static uint32 floatToRawIntBits(float f)
std::int32_t int32
Definition Define.h:73
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
void updateLeaf(int depth, int n)
bool writeToFile(FILE *wf) const
void createNode(std::vector< uint32 > &tempTree, int nodeIndex, uint32 left, uint32 right) const
std::vector< uint32 > objects
void buildHierarchy(std::vector< uint32 > &tempTree, buildData &dat, BuildStats &stats)
std::vector< uint32 > tree
bool readFromFile(FILE *rf)
G3D::AABox bounds
void subdivide(int left, int right, std::vector< uint32 > &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats)