TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
BoundingIntervalHierarchy.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
3  * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef _BIH_H
20 #define _BIH_H
21 
22 #include "G3D/Vector3.h"
23 #include "G3D/Ray.h"
24 #include "G3D/AABox.h"
25 
26 #include "Define.h"
27 
28 #include <stdexcept>
29 #include <vector>
30 #include <algorithm>
31 #include <limits>
32 #include <cmath>
33 
34 #define MAX_STACK_SIZE 64
35 
36 static inline uint32 floatToRawIntBits(float f)
37 {
38  union
39  {
40  uint32 ival;
41  float fval;
42  } temp;
43  temp.fval=f;
44  return temp.ival;
45 }
46 
47 static inline float intBitsToFloat(uint32 i)
48 {
49  union
50  {
51  uint32 ival;
52  float fval;
53  } temp;
54  temp.ival=i;
55  return temp.fval;
56 }
57 
58 struct AABound
59 {
61 };
62 
71 {
72  private:
73  void init_empty()
74  {
75  tree.clear();
76  objects.clear();
77  // create space for the first node
78  tree.push_back(3u << 30u); // dummy leaf
79  tree.insert(tree.end(), 2, 0);
80  }
81  public:
82  BIH() { init_empty(); }
83  template< class BoundsFunc, class PrimArray >
84  void build(const PrimArray &primitives, BoundsFunc &getBounds, uint32 leafSize = 3, bool printStats=false)
85  {
86  if (primitives.size() == 0)
87  {
88  init_empty();
89  return;
90  }
91 
92  buildData dat;
93  dat.maxPrims = leafSize;
94  dat.numPrims = uint32(primitives.size());
95  dat.indices = new uint32[dat.numPrims];
96  dat.primBound = new G3D::AABox[dat.numPrims];
97  getBounds(primitives[0], bounds);
98  for (uint32 i=0; i<dat.numPrims; ++i)
99  {
100  dat.indices[i] = i;
101  getBounds(primitives[i], dat.primBound[i]);
102  bounds.merge(dat.primBound[i]);
103  }
104  std::vector<uint32> tempTree;
105  BuildStats stats;
106  buildHierarchy(tempTree, dat, stats);
107  if (printStats)
108  stats.printStats();
109 
110  objects.resize(dat.numPrims);
111  for (uint32 i=0; i<dat.numPrims; ++i)
112  objects[i] = dat.indices[i];
113  //nObjects = dat.numPrims;
114  tree = tempTree;
115  delete[] dat.primBound;
116  delete[] dat.indices;
117  }
118  uint32 primCount() const { return uint32(objects.size()); }
119 
120  template<typename RayCallback>
121  void intersectRay(const G3D::Ray &r, RayCallback& intersectCallback, float &maxDist, bool stopAtFirst=false) const
122  {
123  float intervalMin = -1.f;
124  float intervalMax = -1.f;
125  G3D::Vector3 org = r.origin();
126  G3D::Vector3 dir = r.direction();
127  G3D::Vector3 invDir;
128  for (int i=0; i<3; ++i)
129  {
130  invDir[i] = 1.f / dir[i];
131  if (G3D::fuzzyNe(dir[i], 0.0f))
132  {
133  float t1 = (bounds.low()[i] - org[i]) * invDir[i];
134  float t2 = (bounds.high()[i] - org[i]) * invDir[i];
135  if (t1 > t2)
136  std::swap(t1, t2);
137  if (t1 > intervalMin)
138  intervalMin = t1;
139  if (t2 < intervalMax || intervalMax < 0.f)
140  intervalMax = t2;
141  // intervalMax can only become smaller for other axis,
142  // and intervalMin only larger respectively, so stop early
143  if (intervalMax <= 0 || intervalMin >= maxDist)
144  return;
145  }
146  }
147 
148  if (intervalMin > intervalMax)
149  return;
150  intervalMin = std::max(intervalMin, 0.f);
151  intervalMax = std::min(intervalMax, maxDist);
152 
153  uint32 offsetFront[3];
154  uint32 offsetBack[3];
155  uint32 offsetFront3[3];
156  uint32 offsetBack3[3];
157  // compute custom offsets from direction sign bit
158 
159  for (int i=0; i<3; ++i)
160  {
161  offsetFront[i] = floatToRawIntBits(dir[i]) >> 31;
162  offsetBack[i] = offsetFront[i] ^ 1;
163  offsetFront3[i] = offsetFront[i] * 3;
164  offsetBack3[i] = offsetBack[i] * 3;
165 
166  // avoid always adding 1 during the inner loop
167  ++offsetFront[i];
168  ++offsetBack[i];
169  }
170 
171  StackNode stack[MAX_STACK_SIZE];
172  int stackPos = 0;
173  int node = 0;
174 
175  while (true) {
176  while (true)
177  {
178  uint32 tn = tree[node];
179  uint32 axis = (tn & (3 << 30)) >> 30;
180  bool BVH2 = (tn & (1 << 29)) != 0;
181  int offset = tn & ~(7 << 29);
182  if (!BVH2)
183  {
184  if (axis < 3)
185  {
186  // "normal" interior node
187  float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
188  float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
189  // ray passes between clip zones
190  if (tf < intervalMin && tb > intervalMax)
191  break;
192  int back = offset + offsetBack3[axis];
193  node = back;
194  // ray passes through far node only
195  if (tf < intervalMin) {
196  intervalMin = (tb >= intervalMin) ? tb : intervalMin;
197  continue;
198  }
199  node = offset + offsetFront3[axis]; // front
200  // ray passes through near node only
201  if (tb > intervalMax) {
202  intervalMax = (tf <= intervalMax) ? tf : intervalMax;
203  continue;
204  }
205  // ray passes through both nodes
206  // push back node
207  stack[stackPos].node = back;
208  stack[stackPos].tnear = (tb >= intervalMin) ? tb : intervalMin;
209  stack[stackPos].tfar = intervalMax;
210  stackPos++;
211  // update ray interval for front node
212  intervalMax = (tf <= intervalMax) ? tf : intervalMax;
213  continue;
214  }
215  else
216  {
217  // leaf - test some objects
218  int n = tree[node + 1];
219  while (n > 0) {
220  bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirst);
221  if (stopAtFirst && hit) return;
222  --n;
223  ++offset;
224  }
225  break;
226  }
227  }
228  else
229  {
230  if (axis>2)
231  return; // should not happen
232  float tf = (intBitsToFloat(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
233  float tb = (intBitsToFloat(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
234  node = offset;
235  intervalMin = (tf >= intervalMin) ? tf : intervalMin;
236  intervalMax = (tb <= intervalMax) ? tb : intervalMax;
237  if (intervalMin > intervalMax)
238  break;
239  continue;
240  }
241  } // traversal loop
242  do
243  {
244  // stack is empty?
245  if (stackPos == 0)
246  return;
247  // move back up the stack
248  stackPos--;
249  intervalMin = stack[stackPos].tnear;
250  if (maxDist < intervalMin)
251  continue;
252  node = stack[stackPos].node;
253  intervalMax = stack[stackPos].tfar;
254  break;
255  } while (true);
256  }
257  }
258 
259  template<typename IsectCallback>
260  void intersectPoint(const G3D::Vector3 &p, IsectCallback& intersectCallback) const
261  {
262  if (!bounds.contains(p))
263  return;
264 
265  StackNode stack[MAX_STACK_SIZE];
266  int stackPos = 0;
267  int node = 0;
268 
269  while (true) {
270  while (true)
271  {
272  uint32 tn = tree[node];
273  uint32 axis = (tn & (3 << 30)) >> 30;
274  bool BVH2 = (tn & (1 << 29)) != 0;
275  int offset = tn & ~(7 << 29);
276  if (!BVH2)
277  {
278  if (axis < 3)
279  {
280  // "normal" interior node
281  float tl = intBitsToFloat(tree[node + 1]);
282  float tr = intBitsToFloat(tree[node + 2]);
283  // point is between clip zones
284  if (tl < p[axis] && tr > p[axis])
285  break;
286  int right = offset + 3;
287  node = right;
288  // point is in right node only
289  if (tl < p[axis]) {
290  continue;
291  }
292  node = offset; // left
293  // point is in left node only
294  if (tr > p[axis]) {
295  continue;
296  }
297  // point is in both nodes
298  // push back right node
299  stack[stackPos].node = right;
300  stackPos++;
301  continue;
302  }
303  else
304  {
305  // leaf - test some objects
306  int n = tree[node + 1];
307  while (n > 0) {
308  intersectCallback(p, objects[offset]); // !!!
309  --n;
310  ++offset;
311  }
312  break;
313  }
314  }
315  else // BVH2 node (empty space cut off left and right)
316  {
317  if (axis>2)
318  return; // should not happen
319  float tl = intBitsToFloat(tree[node + 1]);
320  float tr = intBitsToFloat(tree[node + 2]);
321  node = offset;
322  if (tl > p[axis] || tr < p[axis])
323  break;
324  continue;
325  }
326  } // traversal loop
327 
328  // stack is empty?
329  if (stackPos == 0)
330  return;
331  // move back up the stack
332  stackPos--;
333  node = stack[stackPos].node;
334  }
335  }
336 
337  bool writeToFile(FILE* wf) const;
338  bool readFromFile(FILE* rf);
339 
340  protected:
341  std::vector<uint32> tree;
342  std::vector<uint32> objects;
344 
345  struct buildData
346  {
350  int maxPrims;
351  };
352  struct StackNode
353  {
355  float tnear;
356  float tfar;
357  };
358 
360  {
361  private:
362  int numNodes;
367  int sumDepth;
368  int minDepth;
369  int maxDepth;
370  int numLeavesN[6];
371  int numBVH2;
372 
373  public:
375  numNodes(0), numLeaves(0), sumObjects(0), minObjects(0x0FFFFFFF),
376  maxObjects(0xFFFFFFFF), sumDepth(0), minDepth(0x0FFFFFFF),
377  maxDepth(0xFFFFFFFF), numBVH2(0)
378  {
379  for (int i=0; i<6; ++i) numLeavesN[i] = 0;
380  }
381 
382  void updateInner() { numNodes++; }
383  void updateBVH2() { numBVH2++; }
384  void updateLeaf(int depth, int n);
385  void printStats();
386  };
387 
388  void buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats);
389 
390  void createNode(std::vector<uint32> &tempTree, int nodeIndex, uint32 left, uint32 right) const
391  {
392  // write leaf node
393  tempTree[nodeIndex + 0] = (3 << 30) | left;
394  tempTree[nodeIndex + 1] = right - left + 1;
395  }
396 
397  void subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats);
398 };
399 
400 #endif // _BIH_H
G3D::Vector3 lo
Definition: BoundingIntervalHierarchy.h:60
BuildStats()
Definition: BoundingIntervalHierarchy.h:374
int maxObjects
Definition: BoundingIntervalHierarchy.h:366
Definition: BoundingIntervalHierarchy.h:58
uint32 numPrims
Definition: BoundingIntervalHierarchy.h:349
int minObjects
Definition: BoundingIntervalHierarchy.h:365
uint32 node
Definition: BoundingIntervalHierarchy.h:354
void updateBVH2()
Definition: BoundingIntervalHierarchy.h:383
float tfar
Definition: BoundingIntervalHierarchy.h:356
int sumDepth
Definition: BoundingIntervalHierarchy.h:367
int numLeaves
Definition: BoundingIntervalHierarchy.h:363
uint32 primCount() const
Definition: BoundingIntervalHierarchy.h:118
int maxPrims
Definition: BoundingIntervalHierarchy.h:350
static uint32 floatToRawIntBits(float f)
Definition: BoundingIntervalHierarchy.h:36
Definition: BoundingIntervalHierarchy.h:352
bool fuzzyNe(double a, double b)
Definition: g3dmath.h:861
float tnear
Definition: BoundingIntervalHierarchy.h:355
T max(const T &x, const T &y)
Definition: g3dmath.h:320
int numBVH2
Definition: BoundingIntervalHierarchy.h:371
Definition: Vector3.h:58
Definition: BoundingIntervalHierarchy.h:359
void updateInner()
Definition: BoundingIntervalHierarchy.h:382
void init_empty()
Definition: BoundingIntervalHierarchy.h:73
std::vector< uint32 > objects
Definition: BoundingIntervalHierarchy.h:342
static float intBitsToFloat(uint32 i)
Definition: BoundingIntervalHierarchy.h:47
G3D::AABox bounds
Definition: BoundingIntervalHierarchy.h:343
T min(const T &x, const T &y)
Definition: g3dmath.h:305
void printStats()
Definition: BoundingIntervalHierarchy.cpp:291
int minDepth
Definition: BoundingIntervalHierarchy.h:368
int numNodes
Definition: BoundingIntervalHierarchy.h:362
uint32_t uint32
Definition: Define.h:150
G3D::Vector3 hi
Definition: BoundingIntervalHierarchy.h:60
bool left(const int *a, const int *b, const int *c)
Definition: RecastContour.cpp:487
Definition: Ray.h:24
Definition: AABox.h:32
#define TC_COMMON_API
Definition: Define.h:116
Definition: BoundingIntervalHierarchy.h:345
G3D::AABox * primBound
Definition: BoundingIntervalHierarchy.h:348
const Point3 & origin() const
Definition: Ray.h:56
void createNode(std::vector< uint32 > &tempTree, int nodeIndex, uint32 left, uint32 right) const
Definition: BoundingIntervalHierarchy.h:390
static void subdivide(BVItem *items, int nitems, int imin, int imax, int &curNode, dtBVNode *nodes)
Definition: DetourNavMeshBuilder.cpp:114
uint32 * indices
Definition: BoundingIntervalHierarchy.h:347
void intersectPoint(const G3D::Vector3 &p, IsectCallback &intersectCallback) const
Definition: BoundingIntervalHierarchy.h:260
uint32_t uint32
Definition: g3dmath.h:168
void build(const PrimArray &primitives, BoundsFunc &getBounds, uint32 leafSize=3, bool printStats=false)
Definition: BoundingIntervalHierarchy.h:84
#define MAX_STACK_SIZE
Definition: BoundingIntervalHierarchy.h:34
BIH()
Definition: BoundingIntervalHierarchy.h:82
const Vector3 & direction() const
Definition: Ray.h:61
Definition: BoundingIntervalHierarchy.h:70
void intersectRay(const G3D::Ray &r, RayCallback &intersectCallback, float &maxDist, bool stopAtFirst=false) const
Definition: BoundingIntervalHierarchy.h:121
int maxDepth
Definition: BoundingIntervalHierarchy.h:369
std::vector< uint32 > tree
Definition: BoundingIntervalHierarchy.h:341
int sumObjects
Definition: BoundingIntervalHierarchy.h:364