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