Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
octree.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_OCTREE_H_)
21 #define __MITSUBA_CORE_OCTREE_H_
22 
23 #include <mitsuba/mitsuba.h>
24 #include <mitsuba/core/atomic.h>
25 #include <mitsuba/core/timer.h>
26 #include <mitsuba/core/aabb.h>
27 
29 
30 /**
31  * \brief Lock-free linked list data structure
32  *
33  * This class provides a very basic linked list data structure whose primary
34  * purpose it is to efficiently service append operations from multiple parallel
35  * threads. These are internally realized via atomic compare and exchange
36  * operations, meaning that no lock must be acquired.
37  *
38  * \ingroup libcore
39  */
40 template <typename T> class LockFreeList {
41 public:
42  struct ListItem {
43  T value;
45 
46  inline ListItem(const T &value) :
47  value(value), next(NULL) { }
48  };
49 
50  inline LockFreeList() : m_head(NULL) {}
51 
53  ListItem *cur = m_head;
54  while (cur) {
55  ListItem *next = cur->next;
56  delete cur;
57  cur = next;
58  }
59  }
60 
61  inline const ListItem *head() const {
62  return m_head;
63  }
64 
65  void append(const T &value) {
66  ListItem *item = new ListItem(value);
67  ListItem **cur = &m_head;
68 
69  while (!atomicCompareAndExchangePtr<ListItem>(cur, item, NULL))
70  cur = &((*cur)->next);
71  }
72 private:
73  ListItem *m_head;
74 };
75 
76 /**
77  * \brief Generic single-reference static octree
78  *
79  * This class is currently used to implement BSSRDF evaluation
80  * with irradiance point clouds.
81  *
82  * The \c Item template parameter must implement a function
83  * named <tt>getPosition()</tt> that returns a \ref Point.
84  *
85  * \ingroup libcore
86  */
87 template <typename Item, typename NodeData> class StaticOctree {
88 public:
89  struct OctreeNode {
90  bool leaf : 1;
91  NodeData data;
92 
93  union {
94  struct {
95  OctreeNode *children[8];
96  };
97 
98  struct {
101  };
102  };
103 
105  if (!leaf) {
106  for (int i=0; i<8; ++i) {
107  if (children[i])
108  delete children[i];
109  }
110  }
111  }
112  };
113 
114  /**
115  * \brief Create a new octree
116  * \param maxDepth
117  * Maximum tree depth (24 by default)
118  * \param maxItems
119  * Maximum items per interior node (8 by default)
120  *
121  * By default, the maximum tree depth is set to 16
122  */
123  inline StaticOctree(const AABB &aabb, uint32_t maxDepth = 24, uint32_t maxItems = 8) :
124  m_aabb(aabb), m_maxDepth(maxDepth), m_maxItems(maxItems), m_root(NULL) { }
125 
126  /// Release all memory
128  if (m_root)
129  delete m_root;
130  }
131 
132  void build() {
133  SLog(EDebug, "Building an octree over " SIZE_T_FMT " data points (%s)..",
134  m_items.size(), memString(m_items.size() * sizeof(Item)).c_str());
135 
136  ref<Timer> timer = new Timer();
137  std::vector<uint32_t> perm(m_items.size()), temp(m_items.size());
138 
139  for (uint32_t i=0; i<m_items.size(); ++i)
140  perm[i] = i;
141 
142  /* Build the kd-tree and compute a suitable permutation of the elements */
143  m_root = build(m_aabb, 0, &perm[0], &temp[0], &perm[0], &perm[0] + m_items.size());
144 
145  /* Apply the permutation */
146  permute_inplace(&m_items[0], perm);
147 
148  SLog(EDebug, "Done (took %i ms)" , timer->getMilliseconds());
149  }
150 
151 protected:
152  struct LabelOrdering : public std::binary_function<uint32_t, uint32_t, bool> {
153  LabelOrdering(const std::vector<Item> &items) : m_items(items) { }
154 
155  inline bool operator()(uint32_t a, uint32_t b) const {
156  return m_items[a].label < m_items[b].label;
157  }
158 
159  const std::vector<Item> &m_items;
160  };
161 
162  /// Return the AABB for a child of the specified index
163  inline AABB childBounds(int child, const AABB &nodeAABB, const Point &center) const {
164  AABB childAABB;
165  childAABB.min.x = (child & 4) ? center.x : nodeAABB.min.x;
166  childAABB.max.x = (child & 4) ? nodeAABB.max.x : center.x;
167  childAABB.min.y = (child & 2) ? center.y : nodeAABB.min.y;
168  childAABB.max.y = (child & 2) ? nodeAABB.max.y : center.y;
169  childAABB.min.z = (child & 1) ? center.z : nodeAABB.min.z;
170  childAABB.max.z = (child & 1) ? nodeAABB.max.z : center.z;
171  return childAABB;
172  }
173 
174  OctreeNode *build(const AABB &aabb, uint32_t depth, uint32_t *base,
175  uint32_t *temp, uint32_t *start, uint32_t *end) {
176  if (start == end) {
177  return NULL;
178  } else if ((uint32_t) (end-start) < m_maxItems || depth > m_maxDepth) {
179  OctreeNode *result = new OctreeNode();
180  result->count = (uint32_t) (end-start);
181  result->offset = (uint32_t) (start-base);
182  result->leaf = true;
183  return result;
184  }
185 
186  Point center = aabb.getCenter();
187  uint32_t nestedCounts[8];
188  memset(nestedCounts, 0, sizeof(uint32_t)*8);
189 
190  /* Label all items */
191  for (uint32_t *it = start; it != end; ++it) {
192  Item &item = m_items[*it];
193  const Point &p = item.getPosition();
194 
195  uint8_t label = 0;
196  if (p.x > center.x) label |= 4;
197  if (p.y > center.y) label |= 2;
198  if (p.z > center.z) label |= 1;
199 
200  AABB bounds = childBounds(label, aabb, center);
201  SAssert(bounds.contains(p));
202 
203  item.label = label;
204  nestedCounts[label]++;
205  }
206 
207  uint32_t nestedOffsets[9];
208  nestedOffsets[0] = 0;
209  for (int i=1; i<=8; ++i)
210  nestedOffsets[i] = nestedOffsets[i-1] + nestedCounts[i-1];
211 
212  /* Sort by label */
213  for (uint32_t *it = start; it != end; ++it) {
214  int offset = nestedOffsets[m_items[*it].label]++;
215  temp[offset] = *it;
216  }
217  memcpy(start, temp, (end-start) * sizeof(uint32_t));
218 
219  /* Recurse */
220  OctreeNode *result = new OctreeNode();
221  for (int i=0; i<8; i++) {
222  AABB bounds = childBounds(i, aabb, center);
223 
224  uint32_t *it = start + nestedCounts[i];
225  result->children[i] = build(bounds, depth+1, base, temp, start, it);
226  start = it;
227  }
228 
229  result->leaf = false;
230 
231  return result;
232  }
233 
234  inline StaticOctree() : m_root(NULL) { }
235 protected:
237  std::vector<Item> m_items;
241 };
242 
243 /**
244  * \brief Generic multiple-reference octree with support for parallel dynamic updates
245  *
246  * Based on the excellent implementation in PBRT. Modifications are
247  * the addition of a bounding sphere query and support for multithreading.
248  *
249  * This class is currently used to implement irradiance caching.
250  *
251  * \ingroup libcore
252  */
253 template <typename Item> class DynamicOctree {
254 public:
255  /**
256  * \brief Create a new octree
257  *
258  * By default, the maximum tree depth is set to 24
259  */
260  inline DynamicOctree(const AABB &aabb, uint32_t maxDepth = 24)
261  : m_aabb(aabb), m_maxDepth(maxDepth) {
262  }
263 
264  /// Insert an item with the specified cell coverage
265  inline void insert(const Item &value, const AABB &coverage) {
266  insert(&m_root, m_aabb, value, coverage,
267  coverage.getExtents().lengthSquared(), 0);
268  }
269 
270  /// Execute <tt>functor.operator()</tt> on all records, which potentially overlap \c p
271  template <typename Functor> inline void lookup(const Point &p, Functor &functor) const {
272  if (!m_aabb.contains(p))
273  return;
274  lookup(&m_root, m_aabb, p, functor);
275  }
276 
277  /// Execute <tt>functor.operator()</tt> on all records, which potentially overlap \c bsphere
278  template <typename Functor> inline void searchSphere(const BSphere &sphere, Functor &functor) {
279  if (!m_aabb.overlaps(sphere))
280  return;
281  searchSphere(&m_root, m_aabb, sphere, functor);
282  }
283 
284  inline const AABB &getAABB() const { return m_aabb; }
285 private:
286  struct OctreeNode {
287  public:
288  OctreeNode() {
289  for (int i=0; i<8; ++i)
290  children[i] = NULL;
291  }
292 
293  ~OctreeNode() {
294  for (int i=0; i<8; ++i) {
295  if (children[i])
296  delete children[i];
297  }
298  }
299 
300  OctreeNode *children[8];
301  LockFreeList<Item> data;
302  };
303 
304  /// Return the AABB for a child of the specified index
305  inline AABB childBounds(int child, const AABB &nodeAABB, const Point &center) const {
306  AABB childAABB;
307  childAABB.min.x = (child & 4) ? center.x : nodeAABB.min.x;
308  childAABB.max.x = (child & 4) ? nodeAABB.max.x : center.x;
309  childAABB.min.y = (child & 2) ? center.y : nodeAABB.min.y;
310  childAABB.max.y = (child & 2) ? nodeAABB.max.y : center.y;
311  childAABB.min.z = (child & 1) ? center.z : nodeAABB.min.z;
312  childAABB.max.z = (child & 1) ? nodeAABB.max.z : center.z;
313  return childAABB;
314  }
315 
316  void insert(OctreeNode *node, const AABB &nodeAABB, const Item &value,
317  const AABB &coverage, Float diag2, uint32_t depth) {
318  /* Add the data item to the current octree node if the max. tree
319  depth is reached or the data item's coverage area is smaller
320  than the current node size */
321  if (depth == m_maxDepth ||
322  (nodeAABB.getExtents().lengthSquared() < diag2)) {
323  node->data.append(value);
324  return;
325  }
326 
327  /* Otherwise: test for overlap */
328  const Point center = nodeAABB.getCenter();
329 
330  /* Otherwise: test for overlap */
331  bool x[2] = { coverage.min.x <= center.x, coverage.max.x > center.x };
332  bool y[2] = { coverage.min.y <= center.y, coverage.max.y > center.y };
333  bool z[2] = { coverage.min.z <= center.z, coverage.max.z > center.z };
334  bool over[8] = { x[0] && y[0] && z[0], x[0] && y[0] && z[1],
335  x[0] && y[1] && z[0], x[0] && y[1] && z[1],
336  x[1] && y[0] && z[0], x[1] && y[0] && z[1],
337  x[1] && y[1] && z[0], x[1] && y[1] && z[1] };
338 
339  /* Recurse */
340  for (int child=0; child<8; ++child) {
341  if (!over[child])
342  continue;
343  if (!node->children[child]) {
344  OctreeNode *newNode = new OctreeNode();
345  if (!atomicCompareAndExchangePtr<OctreeNode>(&node->children[child], newNode, NULL))
346  delete newNode;
347  }
348  const AABB childAABB(childBounds(child, nodeAABB, center));
349  insert(node->children[child], childAABB,
350  value, coverage, diag2, depth+1);
351  }
352  }
353 
354  /// Internal lookup procedure - const version
355  template <typename Functor> inline void lookup(const OctreeNode *node,
356  const AABB &nodeAABB, const Point &p, Functor &functor) const {
357  const Point center = nodeAABB.getCenter();
358 
359  const typename LockFreeList<Item>::ListItem *item = node->data.head();
360  while (item) {
361  functor(item->value);
362  item = item->next;
363  }
364 
365  int child = (p.x > center.x ? 4 : 0)
366  + (p.y > center.y ? 2 : 0)
367  + (p.z > center.z ? 1 : 0);
368 
369  OctreeNode *childNode = node->children[child];
370 
371  if (childNode) {
372  const AABB childAABB(childBounds(child, nodeAABB, center));
373  lookup(node->children[child], childAABB, p, functor);
374  }
375  }
376 
377  template <typename Functor> inline void searchSphere(OctreeNode *node,
378  const AABB &nodeAABB, const BSphere &sphere,
379  Functor &functor) {
380  const Point center = nodeAABB.getCenter();
381 
382  const typename LockFreeList<Item>::ListItem *item = node->data.head();
383  while (item) {
384  functor(item->value);
385  item = item->next;
386  }
387 
388  // Potential for much optimization..
389  for (int child=0; child<8; ++child) {
390  if (node->children[child]) {
391  const AABB childAABB(childBounds(child, nodeAABB, center));
392  if (childAABB.overlaps(sphere))
393  searchSphere(node->children[child], childAABB, sphere, functor);
394  }
395  }
396  }
397 private:
398  OctreeNode m_root;
399  AABB m_aabb;
400  uint32_t m_maxDepth;
401 };
402 
404 
405 #endif /* __MITSUBA_CORE_OCTREE_H_ */
Definition: octree.h:152
Generic multiple-reference octree with support for parallel dynamic updates.
Definition: octree.h:253
bool leaf
Definition: octree.h:90
NodeData data
Definition: octree.h:91
uint32_t count
Definition: octree.h:100
void permute_inplace(DataType *data, std::vector< IndexType > &perm)
Apply an arbitrary permutation to an array in linear time.
Definition: util.h:238
PointType max
Component-wise maximum.
Definition: aabb.h:425
void append(const T &value)
Definition: octree.h:65
const ListItem * head() const
Definition: octree.h:61
OctreeNode * children[8]
Definition: octree.h:95
~OctreeNode()
Definition: octree.h:104
void searchSphere(const BSphere &sphere, Functor &functor)
Execute functor.operator() on all records, which potentially overlap bsphere.
Definition: octree.h:278
Lock-free linked list data structure.
Definition: octree.h:40
Bounding sphere data structure in three dimensions.
Definition: bsphere.h:32
Generic single-reference static octree.
Definition: octree.h:87
const AABB & getAABB() const
Definition: octree.h:284
#define SLog(level, fmt,...)
Write a Log message to the console (static version - to be used outside of classes that derive from O...
Definition: logger.h:49
Debug message, usually turned off.
Definition: formatter.h:30
AABB m_aabb
Definition: octree.h:236
StaticOctree()
Definition: octree.h:234
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
uint32_t m_maxDepth
Definition: octree.h:238
uint32_t m_maxItems
Definition: octree.h:239
Axis-aligned bounding box data structure in three dimensions.
Definition: aabb.h:437
Definition: octree.h:89
Definition: octree.h:42
std::vector< Item > m_items
Definition: octree.h:237
OctreeNode * build(const AABB &aabb, uint32_t depth, uint32_t *base, uint32_t *temp, uint32_t *start, uint32_t *end)
Definition: octree.h:174
#define SAssert(cond)
``Static&#39;&#39; assertion (to be used outside of classes that derive from Object)
Definition: logger.h:79
T value
Definition: octree.h:43
OctreeNode * m_root
Definition: octree.h:240
#define SIZE_T_FMT
Definition: platform.h:92
Reference counting helper.
Definition: ref.h:40
ListItem(const T &value)
Definition: octree.h:46
AABB childBounds(int child, const AABB &nodeAABB, const Point &center) const
Return the AABB for a child of the specified index.
Definition: octree.h:163
~LockFreeList()
Definition: octree.h:52
MTS_EXPORT_CORE std::string memString(size_t size, bool precise=false)
Turn a memory size into a human-readable string.
Platform independent milli/micro/nanosecond timerThis class implements a simple cross-platform timer ...
Definition: timer.h:37
PointType getCenter() const
Return the center point.
Definition: aabb.h:132
VectorType getExtents() const
Calculate the bounding box extents.
Definition: aabb.h:292
uint32_t offset
Definition: octree.h:99
void build()
Definition: octree.h:132
DynamicOctree(const AABB &aabb, uint32_t maxDepth=24)
Create a new octree.
Definition: octree.h:260
PointType min
Component-wise minimum.
Definition: aabb.h:424
void insert(const Item &value, const AABB &coverage)
Insert an item with the specified cell coverage.
Definition: octree.h:265
LabelOrdering(const std::vector< Item > &items)
Definition: octree.h:153
bool contains(const PointType &p) const
Check whether a point lies on or inside the bounding box.
Definition: aabb.h:163
void lookup(const Point &p, Functor &functor) const
Execute functor.operator() on all records, which potentially overlap p.
Definition: octree.h:271
~StaticOctree()
Release all memory.
Definition: octree.h:127
Definition: fwd.h:100
LockFreeList()
Definition: octree.h:50
const std::vector< Item > & m_items
Definition: octree.h:159
bool operator()(uint32_t a, uint32_t b) const
Definition: octree.h:155
StaticOctree(const AABB &aabb, uint32_t maxDepth=24, uint32_t maxItems=8)
Create a new octree.
Definition: octree.h:123
#define MTS_NAMESPACE_END
Definition: platform.h:138
ListItem * next
Definition: octree.h:44