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