NTrace
GPU ray tracing framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
OcclusionBVHBuilder.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2009-2010 NVIDIA Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 #include "base/Sort.hpp"
19 #include "io/File.hpp"
20 
21 using namespace FW;
22 
23 // Turns on split cost output to file. Testing only.
24 //#define ENABLE_GRAPHS
25 
26 // Selects how spatial splits should be used. Intended for testing only, not as independent build methods.
27 //#define BUILD_NSAH
28 //#define BUILD_SSAH
29 #define BUILD_OSAH
30 //#define BUILD_ASBVH
31 //#define BUILD_VSAH
32 
33 #define BVH_EPSILON 0.01f
34 
35 //------------------------------------------------------------------------
36 
38 : SplitBVHBuilder (bvh, params), m_MaxVisibleDepth(48)
39 {
40  m_cameraPos = cameraPosition;
41 
42  //if(m_params.visibility != NULL)
43  //{
44  // const U8* ptr = m_params.visibility->getPtr();
45  // for(S32 i = 0; i < m_params.visibility->getSize(); i++) // For each byte
46  // {
47  // for(S32 j = 0; j < 8; j++) // For each bit
48  // {
49  // m_visibility.push_back((*ptr) & (1<<j));
50  // }
51  // }
52  //}
53 
54  // Other options
55  // - Extend Array class so that it can operate on not owned arrays
56  // - New Buffer class that will prevent reallocation from dirtying other device memories
57  // - Array or Buffer operating on individual bits
58  // - Use of vector<bool> class with bit-to-bit copy
59 
60  if(m_params.visibility != NULL)
61  {
62  Timer timer(true);
64  F32 transferTime = timer.getElapsed();
65  printf("GPU-CPU visibility transfer time: %.2f (ms)\n", transferTime*1.0e3f);
66  }
67  else
68  {
71  }
72 
73 }
74 
75 //------------------------------------------------------------------------
76 
78 {
79 }
80 
81 //------------------------------------------------------------------------
82 
84 {
85  // Initialize reference stack and determine root bounds.
86 
87  const Vec3i* tris = (Vec3i*)m_bvh.getScene()->getTriVtxIndexBuffer().getPtr();
88  const Vec3f* verts = (Vec3f*)m_bvh.getScene()->getVtxPosBuffer().getPtr();
89 
90  // Find visible triangles
91  NodeSpecOcl rootSpec;
92  rootSpec.numRef = m_bvh.getScene()->getNumTriangles();
93  m_refStack.reset(rootSpec.numRef);
94 
95  F32 log2scene = log((F32)rootSpec.numRef)/log(2.0f);
96  m_MaxVisibleDepth = (S32)(log2scene/2.0f);
97  printf("OSAH max depth: %d\n", m_MaxVisibleDepth);
98 
99  if(!m_params.twoTrees)
100  {
101  // Set the references - optionally only visible or invisible references could be set
102  int last = 0;
103  for (int i = 0; i < rootSpec.numRef; i++)
104  {
105 #ifdef BUILD_VSAH
106  if(m_visibility[i] == 0) // By setting this line, processed triangles are chosen
107  continue;
108 #endif
109 
110  m_refStack[last].triIdx = i;
111  for (int j = 0; j < 3; j++)
112  m_refStack[last].bounds.grow(verts[tris[i][j]]);
113  // Inflate the basic boxes so that box intersections are correct
114  m_refStack[last].bounds.min() -= BVH_EPSILON;
115  m_refStack[last].bounds.max() += BVH_EPSILON;
116  rootSpec.bounds.grow(m_refStack[last].bounds);
117 
118  //if(m_refStack[i].numVisible)
119  // rootSpec.boundsVisible.grow(m_refStack[last].bounds);
120 
121  m_visibility[last] = m_visibility[i];
122  rootSpec.numVisible += m_visibility[i];
123  last++;
124  }
125  rootSpec.numRef = last;
126  printf("Visible triangles: %d tris\n", rootSpec.numVisible);
127 
128  // Inflate the basic boxes so that box intersections are correct
129  /*F32 EPSILON = (rootSpec.bounds.max()-rootSpec.bounds.min()).max() * 2e-5f;
130  rootSpec.bounds.min().set(Vec3f(FW_F32_MAX, FW_F32_MAX, FW_F32_MAX));
131  rootSpec.bounds.max().set(Vec3f(-FW_F32_MAX, -FW_F32_MAX, -FW_F32_MAX));
132  for (int i = 0; i < rootSpec.numRef; i++)
133  {
134  m_refStack[i].bounds.grow(m_refStack[i].bounds.min()-EPSILON);
135  m_refStack[i].bounds.grow(m_refStack[i].bounds.max()+EPSILON);
136  rootSpec.bounds.grow(m_refStack[i].bounds);
137  }*/
138 
139  // Initialize rest of the members.
140 
141  m_minOverlap = rootSpec.bounds.area() * m_params.splitAlpha;
142  m_rightBounds.reset(max(rootSpec.numRef, (int)NumSpatialBins) - 1);
143  //m_rightVisibleBounds.reset(max(rootSpec.numRef, (int)NumSpatialBins) - 1);
144  m_numDuplicates = 0;
146 
147  // Build recursively.
148 
149  BVHNode* root;
150  root = buildNode(rootSpec, 0, rootSpec.numRef-1, 0, 0.0f, 1.0f);
151 
153 
154  // Done.
155 
157  printf("OcclusionBVHBuilder: progress %.0f%%, duplicates %.0f%%\n",
158  100.0f, (F32)m_numDuplicates / (F32)m_bvh.getScene()->getNumTriangles() * 100.0f);
159  return root;
160  }
161  else
162  {
163  NodeSpecOcl visibleSpec, invisibleSpec;
164 
165  // Set the references - separate visible and invisible
166  int lastFound = 0;
167  int lastInvisible = -1;
168  for (int i = 0; i < rootSpec.numRef; i++)
169  {
170  if(m_refStack[i].triIdx == -1)
171  m_refStack[i].triIdx = i;
172 
173  if(lastInvisible == -1 && m_visibility[i]) // Triangle is visible
174  {
175  int j;
176  for(j = max(lastFound+1, i+1); j < rootSpec.numRef; j++) // Find next invisible
177  {
178  if(!m_visibility[j])
179  {
180  m_refStack[j].triIdx = j;
181  sortSwap(this, i, j);
182  lastFound = j;
183  break;
184  }
185  }
186 
187  if(j >= rootSpec.numRef - 1)
188  lastInvisible = m_visibility[i] ? i-1 : i;
189  }
190 
191  for (int j = 0; j < 3; j++)
192  m_refStack[i].bounds.grow(verts[tris[m_refStack[i].triIdx][j]]);
193  // Inflate the basic boxes so that box intersections are correct
194  m_refStack[i].bounds.grow(m_refStack[i].bounds.min()-BVH_EPSILON);
195  m_refStack[i].bounds.grow(m_refStack[i].bounds.max()+BVH_EPSILON);
196 
197  if(m_visibility[i])
198  visibleSpec.bounds.grow(m_refStack[i].bounds);
199  else
200  invisibleSpec.bounds.grow(m_refStack[i].bounds);
201 
202  visibleSpec.numVisible += m_visibility[i];
203  }
204  invisibleSpec.numRef = lastInvisible+1; // We want number of visible, not last index
205  visibleSpec.numRef = rootSpec.numRef - invisibleSpec.numRef;
206 
207  // Build tree for visible nodes
208  // Initialize rest of the members.
209 
210  m_minOverlap = visibleSpec.bounds.area() * m_params.splitAlpha;
211  m_rightBounds.reset(max(visibleSpec.numRef, (int)NumSpatialBins) - 1);
212  //m_rightVisibleBounds.reset(maxvisibleSpec.numRef, (int)NumSpatialBins) - 1);
213  m_numDuplicates = 0;
215 
216  // Build recursively.
217 
218  BVHNode* visible;
219  // TODO: Works the same?!
220  //visible = SplitBVHBuilder::buildNode(visibleSpec, invisibleSpec.numRef, rootSpec.numRef-1, 0, 0.0f, 1.0f);
221  visible = SplitBVHBuilder::buildNode(visibleSpec, rootSpec.numRef - 1, 0.0f, 1.0f);
222 
223  // Done.
224 
226  printf("OcclusionBVHBuilder: progress %.0f%%, duplicates %.0f%%\n",
227  100.0f, (F32)m_numDuplicates / (F32)visibleSpec.numRef * 100.0f);
228 
229 
230  m_refStack.resize(invisibleSpec.numRef); // Forget the visible references, we have already build the tree for them
231 
232 
233  // Build tree for invisible nodes
234  // Initialize rest of the members.
235 
236  m_minOverlap = invisibleSpec.bounds.area() * m_params.splitAlpha;
237  m_rightBounds.reset(max(invisibleSpec.numRef, (int)NumSpatialBins) - 1);
238  //m_rightVisibleBounds.reset(max(invisibleSpec.numRef, (int)NumSpatialBins) - 1);
239  m_numDuplicates = 0;
241 
242  // Build recursively.
243 
244  BVHNode* invisible;
245  // TODO: Works the same?
246  //invisible = SplitBVHBuilder::buildNode(invisibleSpec, 0, invisibleSpec.numRef-1, 0, 0.0f, 1.0f);
247  invisible = SplitBVHBuilder::buildNode(invisibleSpec, invisibleSpec.numRef-1, 0.0f, 1.0f);
248 
249  // Done.
250 
252  printf("OcclusionBVHBuilder: progress %.0f%%, duplicates %.0f%%\n",
253  100.0f, (F32)m_numDuplicates / (F32)invisibleSpec.numRef * 100.0f);
254 
256  return new InnerNode(visibleSpec.bounds + invisibleSpec.bounds, visible, invisible, 0, SplitInfo::SAH, false);
257  }
258 }
259 
260 //------------------------------------------------------------------------
261 
262 void OcclusionBVHBuilder::sortSwap(void* data, int idxA, int idxB)
263 {
265  swap(ptr->m_refStack[idxA], ptr->m_refStack[idxB]);
266  swap(ptr->m_visibility[idxA], ptr->m_visibility[idxB]);
267 }
268 
269 //------------------------------------------------------------------------
270 
271 BVHNode* OcclusionBVHBuilder::buildNode(const NodeSpecOcl& spec, int start, int end, int level, F32 progressStart, F32 progressEnd)
272 {
273  // Display progress.
274 
276  {
277  printf("OcclusionBVHBuilder: progress %.0f%%, duplicates %.0f%%\r",
278  progressStart * 100.0f, (F32)m_numDuplicates / (F32)m_bvh.getScene()->getNumTriangles() * 100.0f);
280  }
281 
282  // Small enough or too deep => create leaf.
283 
284  // TODO: Works the same?
285  /*if (level != 0 && spec.numRef <= m_platform.getMinLeafSize() || level >= MaxDepth) // Make sure we do not make the root a leaf -> GPU traversal will fail
286  return createLeaf(spec, start, end);*/
287  if (level != 0 && spec.numRef <= m_platform.getMinLeafSize() || level >= MaxDepth)
288  return createLeaf(spec);
289 
290  // Find split candidates.
291 
292  F32 area = spec.bounds.area();
293  F32 leafSAH = area * m_platform.getTriangleCost(spec.numRef);
294  F32 nodeSAH = area * m_platform.getNodeCost(2);
295 
296  bool osahChosen = false, osahTested = false;
298  S32 axis = 0;
299 
300  // Occlusion information split
301 
302  ObjectSplitOcl object;
303  SpatialSplitOcl spatial;
304 
305  // Choose which split types should be computed based on the desired construction method
306 
307 #ifndef BUILD_ASBVH
308  if(spec.numVisible != 0 && spec.numVisible != spec.numRef && level < m_MaxVisibleDepth)
309  //if(spec.numVisible != 0 && spec.numVisible != spec.numRef && level < MaxVisibleDepth)
310  {
311  spatial = findSpatialOccludeSplit(spec, start, end, nodeSAH);
312  osahTested = true;
313  osahChosen = spatial.osahChosen;
314  }
315 #endif
316 
317  if(!osahChosen)
318  {
319  object = findObjectSplit(spec, start, end, nodeSAH);
320 
321 #if defined(BUILD_SSAH)
322  if(level < MaxSpatialDepth)
323 #elif defined(BUILD_ASBVH)
324  if(spec.numVisible != 0 && level < MaxSpatialDepth)
325 #elif defined(BUILD_OSAH)
326  if(spec.numVisible != 0 && level < MaxSpatialDepth && level >= m_MaxVisibleDepth)
327 #endif
328 
329 #if defined(BUILD_SSAH) || defined(BUILD_ASBVH) || defined(BUILD_OSAH)
330  {
331  spatial = SpatialSplitOcl();
332 
333  AABB overlap = object.leftBounds;
334  overlap.intersect(object.rightBounds);
335  if (overlap.area() >= m_minOverlap)
336  spatial = findSpatialSplit(spec, start, end, nodeSAH);
337  }
338 #endif
339  }
340 
341  // Leaf SAH is the lowest => create leaf.
342 
343  F32 minSAH = min(leafSAH, object.sah, spatial.sah);
344  // TODO: Works the same?
345  /*if (level != 0 && minSAH == leafSAH && spec.numRef <= m_platform.getMaxLeafSize()) // Make sure we do not make the root a leaf -> GPU traversal will fail
346  return createLeaf(spec, start, end);*/
347  if (level != 0 && minSAH == leafSAH && spec.numRef <= m_platform.getMaxLeafSize()) // Make sure we do not make the root a leaf -> GPU traversal will fail
348  return createLeaf(spec);
349 
350  // Perform split.
351 
352  NodeSpecOcl left, right;
353  if (osahChosen || minSAH == spatial.sah)
354  performSpatialOccludeSplit(left, right, start, end, spatial);
355  if (!left.numRef || !right.numRef)
356  {
357  if(osahChosen)
358  object = findObjectSplit(spec, start, end, nodeSAH); // Fixes a bug when performSpatialOccludeSplit puts all references to one child and execution
359  // falls back to this location but object split was not computed.
360  performObjectSplit(left, right, spec, start, end, object);
361  axis = object.sortDim;
362  }
363  else
364  {
365  splitType = osahChosen ? SplitInfo::OSAH : SplitInfo::SBVH;
366  axis = spatial.dim;
367  }
368 
369  // Create inner node.
370 
371  m_numDuplicates += left.numRef + right.numRef - spec.numRef;
372  F32 progressMid = lerp(progressStart, progressEnd, (F32)right.numRef / (F32)(left.numRef + right.numRef));
373 
374  BVHNode* rightNode = buildNode(right, start+left.numRef, end, level + 1, progressStart, progressMid);
375  BVHNode* leftNode = buildNode(left, start, start+left.numRef-1, level + 1, progressMid, progressEnd);
376 
377  // Swap the boxes so that the left child has more visible triangles
378  if(right.numVisible > left.numVisible) // Will work fine with overlapping visible triangles? If not return to previous approach
379  return new InnerNode(spec.bounds, rightNode, leftNode, axis, splitType, osahTested);
380  else
381  return new InnerNode(spec.bounds, leftNode, rightNode, axis, splitType, osahTested);
382 }
383 
384 //------------------------------------------------------------------------
385 
387 {
388  ObjectSplitOcl split;
389  Reference* refPtr = m_refStack.getPtr(start);
390  S32* visPtr = m_visibility.getPtr(start);
391 
392  S32 visibleLeft, visibleRight;
393 
394 #ifdef ENABLE_GRAPHS
396  File *file = NULL;
397  char dimStr[] = {'x', 'y', 'z'};
398 #endif
399 
400  // Sort along each dimension.
401 
402  for (m_sortDim = 0; m_sortDim < 3; m_sortDim++)
403  {
404  sort(this, start, end+1, sortCompare, sortSwap);
405 
406 #ifdef ENABLE_GRAPHS
407  if(level == 0)
408  {
409  // Open file buffer
410  CreateDirectory(m_params.logDirectory.getPtr(), NULL);
411  String name = sprintf("%s\\cost_sah_%s%d_%c.log", m_params.logDirectory.getPtr(), m_params.buildName.getPtr(), m_params.cameraIdx, dimStr[m_sortDim]);
412  file = new File(name, File::Create);
413  buffer = new BufferedOutputStream(*file, 1024, true, true);
414  }
415 #endif
416 
417  // Starting visibilities
418  visibleLeft = 0;
419  visibleRight = spec.numVisible;
420 
421  // Sweep right to left and determine bounds.
422 
423  AABB rightBounds;
424  //AABB rightVisibleBounds;
425  for (int i = end-start; i > 0; i--)
426  {
427  //if(refPtr[i].numVisible)
428  // rightVisibleBounds.grow(refPtr[i].bounds);
429  //m_rightVisibleBounds[i - 1] = rightVisibleBounds;
430 
431  rightBounds.grow(refPtr[i].bounds);
432  m_rightBounds[i - 1] = rightBounds;
433  }
434 
435  // Sweep left to right and select lowest SAH.
436 
437  AABB leftBounds;
438  //AABB leftVisibleBounds;
439  for (int i = 1; i < end-start+1; i++) // All own triangles have been tested
440  {
441  //if(refPtr[i-1].numVisible)
442  // leftVisibleBounds.grow(refPtr[i-1].bounds);
443 
444  visibleLeft += visPtr[i - 1];
445  visibleRight -= visPtr[i - 1];
446 
447  leftBounds.grow(refPtr[i - 1].bounds);
448 
449  // Calculate SAH
450 
451  F32 sah = nodeSAH + leftBounds.area() * m_platform.getTriangleCost(i) + m_rightBounds[i - 1].area() * m_platform.getTriangleCost((end-start+1) - i);
452 
453  if(sah < split.sah)
454  {
455  split.sah = sah;
456  split.sortDim = m_sortDim;
457  split.numLeft = i;
458  split.leftBounds = leftBounds;
459  split.leftVisible = visibleLeft;
460  //split.leftVisibleBounds = leftVisibleBounds;
461  split.rightBounds = m_rightBounds[i - 1];
462  split.rightVisible = visibleRight;
463  //split.rightVisibleBounds = m_rightVisibleBounds[j - 1];
464  }
465 
466 #ifdef ENABLE_GRAPHS
467  // Print split data
468  if(level == 0)
469  {
470  buffer->writef("%d\t%f\n", i, sah);
471  }
472 #endif
473  }
474 
475 #ifdef ENABLE_GRAPHS
476  // Free file buffer
477  if(level == 0)
478  {
479  buffer->flush();
480  delete file;
481  delete buffer;
482  }
483 #endif
484  }
485 
486  return split;
487 }
488 
489 //------------------------------------------------------------------------
490 
492 {
493  ObjectSplitOcl split, osplit;
494  Reference* refPtr = m_refStack.getPtr(start);
495  S32* visPtr = m_visibility.getPtr(start);
496 
497  S32 visibleLeft, visibleRight;
498 
499 #ifdef ENABLE_GRAPHS
501  File *file = NULL;
502  char dimStr[] = {'x', 'y', 'z'};
503 #endif
504 
505  // Sort along each dimension.
506 
507  for (m_sortDim = 0; m_sortDim < 3; m_sortDim++)
508  {
509  sort(this, start, end+1, sortCompare, sortSwap);
510 
511 #ifdef ENABLE_GRAPHS
512  if(level == 0)
513  {
514  // Open file buffer
515  CreateDirectory(m_params.logDirectory.getPtr(), NULL);
517  file = new File(name, File::Create);
518  buffer = new BufferedOutputStream(*file, 1024, true, true);
519  }
520 #endif
521 
522  // Starting visibilities
523  visibleLeft = 0;
524  visibleRight = spec.numVisible;
525 
526  // Sweep right to left and determine bounds.
527 
528  AABB rightBounds;
529  //AABB rightVisibleBounds;
530  for (int i = end-start; i > 0; i--)
531  {
532  //if(refPtr[i].numVisible)
533  // rightVisibleBounds.grow(refPtr[i].bounds);
534  //m_rightVisibleBounds[i - 1] = rightVisibleBounds;
535 
536  rightBounds.grow(refPtr[i].bounds);
537  m_rightBounds[i - 1] = rightBounds;
538  }
539 
540  // Sweep left to right and select lowest SAH.
541 
542  AABB leftBounds;
543  //AABB leftVisibleBounds;
544  for (int i = 1; i < end-start+1; i++) // All own triangles have been tested
545  {
546  //if(refPtr[i-1].numVisible)
547  // leftVisibleBounds.grow(refPtr[i-1].bounds);
548 
549  // Calculate occlusion
550  visibleLeft += visPtr[i - 1];
551  visibleRight -= visPtr[i - 1];
552 
553  leftBounds.grow(refPtr[i - 1].bounds);
554 
555  // Calculate SAH
556 
557  F32 sah = nodeSAH + leftBounds.area() * m_platform.getTriangleCost(i) + m_rightBounds[i - 1].area() * m_platform.getTriangleCost((end-start+1) - i);
558 
559  // Calculate OSAH
560  F32 osah = FW_F32_MAX;
561 
562  if(spec.numVisible != 0 && spec.numVisible != spec.numRef)
563  {
564  F32 weight = m_params.osahWeight * (1.0f - (float)spec.numVisible/(float)(end-start+1));
565  F32 probL = weight * (float)visibleLeft/(float)spec.numVisible + (1.0f - weight) * leftBounds.area()/spec.bounds.area();
566  F32 probR = weight * (float)visibleRight/(float)spec.numVisible + (1.0f - weight) * m_rightBounds[i - 1].area()/spec.bounds.area();
567  osah = nodeSAH + probL * m_platform.getTriangleCost(i) + probR * m_platform.getTriangleCost((end-start+1) - i);
568  }
569 
570  // Update best splits
571  if(osah < osplit.sah)
572  {
573  osplit.sah = osah;
574  osplit.sortDim = m_sortDim;
575  osplit.numLeft = i;
576  osplit.leftBounds = leftBounds;
577  osplit.leftVisible = visibleLeft;
578  //osplit.leftVisibleBounds = leftVisibleBounds;
579  osplit.rightBounds = m_rightBounds[i - 1];
580  osplit.rightVisible = visibleRight;
581  //osplit.rightVisibleBounds = m_rightVisibleBounds[i - 1];
582  osplit.osahTested = true;
583  }
584 
585  if(sah < split.sah)
586  {
587  split.sah = sah;
588  split.sortDim = m_sortDim;
589  split.numLeft = i;
590  split.leftBounds = leftBounds;
591  split.leftVisible = visibleLeft;
592  //split.leftVisibleBounds = leftVisibleBounds;
593  split.rightBounds = m_rightBounds[i - 1];
594  split.rightVisible = visibleRight;
595  //split.rightVisibleBounds = m_rightVisibleBounds[i - 1];
596  }
597 
598 #ifdef ENABLE_GRAPHS
599  // Print split data
600  if(level == 0)
601  {
602  if(osah < FW_F32_MAX)
603  buffer->writef("%d\t%f\t%f\n", i, sah, osah);
604  else
605  buffer->writef("%d\t%f\t%f\n", i, sah, (float)2.0f*spec.numRef); // Should be always larger than any computed cost but small enough not to distort the graph
606  //buffer->writef("%d\t%f\t?\n", i, sah);
607  }
608 #endif
609  }
610 
611 #ifdef ENABLE_GRAPHS
612  // Free file buffer
613  if(level == 0)
614  {
615  buffer->flush();
616  delete file;
617  delete buffer;
618  }
619 #endif
620  }
621 
622  // Chose better of the two heuristics
623  S32 hidTris = osplit.leftVisible < osplit.rightVisible ? osplit.numLeft : spec.numRef - osplit.numLeft;
624  S32 largerChild = FW::max(split.numLeft, spec.numRef - split.numLeft);
625 
626  if(osplit.sah < FW_F32_MAX && hidTris > largerChild)
627  {
628  osplit.osahChosen = true;
629  return osplit;
630  }
631  else
632  {
633  split.osahTested = osplit.osahTested;
634  return split;
635  }
636 }
637 //------------------------------------------------------------------------
638 
639 void OcclusionBVHBuilder::performObjectSplit(NodeSpecOcl& left, NodeSpecOcl& right, const NodeSpecOcl& spec, int start, int end, const ObjectSplitOcl& split)
640 {
641  m_sortDim = split.sortDim;
642  sort(this, start, end+1, sortCompare, sortSwap);
643 
644  left.numRef = split.numLeft;
645  left.bounds = split.leftBounds;
646  left.numVisible = split.leftVisible;
647  //left.boundsVisible = split.leftVisibleBounds;
648  right.numRef = spec.numRef - split.numLeft;
649  right.bounds = split.rightBounds;
650  right.numVisible = split.rightVisible;
651  //right.boundsVisible = split.rightVisibleBounds;
652 }
653 
654 //------------------------------------------------------------------------
655 
657 {
658  // Initialize bins.
659 
660  Vec3f origin = spec.bounds.min();
661  Vec3f binSize = (spec.bounds.max() - origin) * (1.0f / (F32)NumSpatialBins);
662  Vec3f invBinSize = 1.0f / binSize;
663 
664  //size_t visibleLeft, visibleRight;
665 
666  for (int dim = 0; dim < 3; dim++)
667  {
668  for (int i = 0; i < NumSpatialBins; i++)
669  {
670  SpatialBinOcl& bin = m_bins[dim][i];
671  bin.bounds = AABB();
672  bin.enter = 0;
673  bin.exit = 0;
674  //bin.enterVisible = 0;
675  //bin.exitVisible = 0;
676  }
677  }
678 
679  // Chop references into bins.
680 
681  for (int refIdx = start; refIdx < end+1; refIdx++)
682  {
683  const Reference& ref = m_refStack[refIdx];
684  Vec3i firstBin = clamp(Vec3i((ref.bounds.min() - origin) * invBinSize), 0, NumSpatialBins - 1);
685  Vec3i lastBin = clamp(Vec3i((ref.bounds.max() - origin) * invBinSize), firstBin, NumSpatialBins - 1);
686 
687  for (int dim = 0; dim < 3; dim++)
688  {
689  Reference currRef = ref;
690  for (int i = firstBin[dim]; i < lastBin[dim]; i++)
691  {
692  Reference leftRef, rightRef;
693  splitReference(leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (F32)(i + 1));
694  if(leftRef.bounds.valid()) // May be invalid because the boxes are inflated by BVH_EPSILON
695  m_bins[dim][i].bounds.grow(leftRef.bounds);
696  currRef = rightRef;
697  }
698  if(currRef.bounds.valid()) // May be invalid because the boxes are inflated by BVH_EPSILON
699  m_bins[dim][lastBin[dim]].bounds.grow(currRef.bounds);
700  m_bins[dim][firstBin[dim]].enter++;
701  m_bins[dim][lastBin[dim]].exit++;
702  //if(ref.numVisible)
703  //{
704  // m_bins[dim][firstBin[dim]].enterVisible++;
705  // m_bins[dim][lastBin[dim]].exitVisible++;
706  //}
707  }
708  }
709 
710  // Select best split plane.
711 
712  SpatialSplitOcl split, osplit;
713  for (int dim = 0; dim < 3; dim++)
714  {
715  // Sweep right to left and determine bounds.
716 
717  AABB rightBounds;
718  for (int i = NumSpatialBins - 1; i > 0; i--)
719  {
720  if(m_bins[dim][i].bounds.valid())
721  rightBounds.grow(m_bins[dim][i].bounds);
722  m_rightBounds[i - 1] = rightBounds;
723  }
724 
725  // Sweep left to right and select lowest SAH.
726 
727  AABB leftBounds;
728  int leftNum = 0;
729  int rightNum = spec.numRef;
730 
731  // Starting visibilities
732  //visibleLeft = 0;
733  //visibleRight = spec.numVisible;
734 
735  for (int i = 1; i < NumSpatialBins; i++)
736  {
737  if(!m_bins[dim][i-1].bounds.valid())
738  continue;
739 
740  leftBounds.grow(m_bins[dim][i - 1].bounds);
741  leftNum += m_bins[dim][i - 1].enter;
742  rightNum -= m_bins[dim][i - 1].exit;
743  //visibleLeft += m_bins[dim][i - 1].enterVisible;
744  //visibleRight -= m_bins[dim][i - 1].exitVisible;
745 
746  F32 sah = nodeSAH + leftBounds.area() * m_platform.getTriangleCost(leftNum) + m_rightBounds[i - 1].area() * m_platform.getTriangleCost(rightNum);
747  if (sah < split.sah)
748  {
749  split.sah = sah;
750  split.dim = dim;
751  split.pos = origin[dim] + binSize[dim] * (F32)i;
752  split.leftNum = leftNum;
753  split.rightNum = rightNum;
754  //split.leftVisible = visibleLeft;
755  //split.rightVisible = visibleRight;
756  }
757  }
758  }
759 
760  return split;
761 }
762 
763 //------------------------------------------------------------------------
764 
766 {
767  // Initialize bins.
768 
769  Vec3f origin = spec.bounds.min();
770  Vec3f binSize = (spec.bounds.max() - origin) * (1.0f / (F32)NumSpatialBins);
771  Vec3f invBinSize = 1.0f / binSize;
772 
773  S32 visibleLeft, visibleRight;
774 
775 #ifdef ENABLE_GRAPHS
777  File *file = NULL;
778  char dimStr[] = {'x', 'y', 'z'};
779 #endif
780 
781  for (int dim = 0; dim < 3; dim++)
782  {
783  for (int i = 0; i < NumSpatialBins; i++)
784  {
785  SpatialBinOcl& bin = m_bins[dim][i];
786  bin.bounds = AABB();
787  bin.enter = 0;
788  bin.exit = 0;
789  bin.enterVisible = 0;
790  bin.exitVisible = 0;
791  }
792  }
793 
794  // Chop references into bins.
795 
796  for (int refIdx = start; refIdx < end+1; refIdx++)
797  {
798  const Reference& ref = m_refStack[refIdx];
799  Vec3i firstBin = clamp(Vec3i((ref.bounds.min() - origin) * invBinSize), 0, NumSpatialBins - 1);
800  Vec3i lastBin = clamp(Vec3i((ref.bounds.max() - origin) * invBinSize), firstBin, NumSpatialBins - 1);
801 
802  for (int dim = 0; dim < 3; dim++)
803  {
804  Reference currRef = ref;
805  for (int i = firstBin[dim]; i < lastBin[dim]; i++)
806  {
807  Reference leftRef, rightRef;
808  splitReference(leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (F32)(i + 1));
809  if(leftRef.bounds.valid()) // May be invalid because the boxes are inflated by BVH_EPSILON
810  m_bins[dim][i].bounds.grow(leftRef.bounds);
811  currRef = rightRef;
812  }
813  if(currRef.bounds.valid()) // May be invalid because the boxes are inflated by BVH_EPSILON
814  m_bins[dim][lastBin[dim]].bounds.grow(currRef.bounds);
815  m_bins[dim][firstBin[dim]].enter++;
816  m_bins[dim][lastBin[dim]].exit++;
817  if(m_visibility[refIdx])
818  {
819  m_bins[dim][firstBin[dim]].enterVisible++;
820  m_bins[dim][lastBin[dim]].exitVisible++;
821  }
822  }
823  }
824 
825  // Select best split plane.
826 
827  SpatialSplitOcl split, osplit;
828  for (int dim = 0; dim < 3; dim++)
829  {
830  // Sweep right to left and determine bounds.
831 
832  AABB rightBounds;
833  for (int i = NumSpatialBins - 1; i > 0; i--)
834  {
835  if(m_bins[dim][i].bounds.valid())
836  rightBounds.grow(m_bins[dim][i].bounds);
837  m_rightBounds[i - 1] = rightBounds;
838  }
839 
840  // Sweep left to right and select lowest SAH.
841 
842  AABB leftBounds;
843  int leftNum = 0;
844  int rightNum = spec.numRef;
845 
846  // Starting visibilities
847  visibleLeft = 0;
848  visibleRight = spec.numVisible;
849 
850 #ifdef ENABLE_GRAPHS
851  if(level == 0)
852  {
853  // Open file buffer
854  CreateDirectory(m_params.logDirectory.getPtr(), NULL);
855  String name = sprintf("%s\\cost_osah,ssah_%s%d_%c.log", m_params.logDirectory.getPtr(), m_params.buildName.getPtr(), m_params.cameraIdx, dimStr[dim]);
856  file = new File(name, File::Create);
857  buffer = new BufferedOutputStream(*file, 1024, true, true);
858  }
859 #endif
860 
861  for (int i = 1; i < NumSpatialBins; i++)
862  {
863  if(!m_bins[dim][i-1].bounds.valid())
864  continue;
865 
866  leftBounds.grow(m_bins[dim][i - 1].bounds);
867  leftNum += m_bins[dim][i - 1].enter;
868  rightNum -= m_bins[dim][i - 1].exit;
869  visibleLeft += m_bins[dim][i - 1].enterVisible;
870  visibleRight -= m_bins[dim][i - 1].exitVisible;
871 
872  F32 osah = FW_F32_MAX;
873  //if(visibleLeft == 0 || visibleRight == 0)
874  {
875  //F32 weight = 0.9f * (1.0f - (float)spec.numVisible/(float)(end-start+1));
876  F32 weight = m_params.osahWeight;
877  F32 probL = weight * ((float)(visibleLeft)/(float)spec.numVisible) + (1.0f - weight) * leftBounds.area()/spec.bounds.area();
878  F32 probR = weight * ((float)(visibleRight)/(float)spec.numVisible) + (1.0f - weight) * m_rightBounds[i - 1].area()/spec.bounds.area();
879  osah = nodeSAH + probL * m_platform.getTriangleCost(leftNum) + probR * m_platform.getTriangleCost(rightNum);
880  }
881  if (osah < osplit.sah)
882  {
883  osplit.sah = osah;
884  osplit.dim = dim;
885  osplit.pos = origin[dim] + binSize[dim] * (F32)i;
886  osplit.leftNum = leftNum;
887  osplit.rightNum = rightNum;
888  osplit.leftVisible = visibleLeft;
889  osplit.rightVisible = visibleRight;
890  }
891 
892  F32 sah = nodeSAH + leftBounds.area() * m_platform.getTriangleCost(leftNum) + m_rightBounds[i - 1].area() * m_platform.getTriangleCost(rightNum);
893  if (sah < split.sah)
894  {
895  split.sah = sah;
896  split.dim = dim;
897  split.pos = origin[dim] + binSize[dim] * (F32)i;
898  split.leftNum = leftNum;
899  split.rightNum = rightNum;
900  split.leftVisible = visibleLeft;
901  split.rightVisible = visibleRight;
902  }
903 
904 #ifdef ENABLE_GRAPHS
905  // Print split data
906  if(level == 0)
907  {
908  if(osah < FW_F32_MAX)
909  buffer->writef("%d\t%f\t%f\n", i, sah, osah);
910  else
911  buffer->writef("%d\t%f\t%f\n", i, sah, (float)2.0f*spec.numRef); // Should be always larger than any computed cost but small enough not to distort the graph
912  //buffer->writef("%d\t%f\t?\n", i, sah);
913  }
914 #endif
915  }
916 
917 #ifdef ENABLE_GRAPHS
918  // Free file buffer
919  if(level == 0)
920  {
921  buffer->flush();
922  delete file;
923  delete buffer;
924  }
925 #endif
926  }
927 
928  S32 hidTris = osplit.leftVisible < osplit.rightVisible ? osplit.leftNum : osplit.rightNum;
929  S32 smallerChild = FW::max(split.leftNum, split.rightNum);
930 
931  if(osplit.sah < FW_F32_MAX && hidTris > smallerChild)
932  {
933  osplit.osahChosen = true;
934  return osplit;
935  }
936  else
937  {
938  split.osahChosen = false;
939 #ifndef BUILD_OSAH
940  split.sah = FW_F32_MAX;
941 #endif
942  return split;
943  }
944 }
945 
946 //------------------------------------------------------------------------
947 
948 /*OcclusionBVHBuilder::SpatialSplitOcl OcclusionBVHBuilder::findVisibleSplit(const NodeSpecOcl& spec, int start, int end, F32 nodeSAH, int level)
949 {
950  // Initialize bins.
951 
952  const int numBins = 3;
953  F32 splitPos[3][numBins];
954 
955  size_t visibleLeft, visibleRight;
956 
957 #ifdef ENABLE_GRAPHS
958  BufferedOutputStream *buffer = NULL;
959  File *file = NULL;
960  char dimStr[] = {'x', 'y', 'z'};
961 #endif
962 
963  for (int dim = 0; dim < 3; dim++)
964  {
965  for (int i = 0; i < numBins; i++)
966  {
967  SpatialBinOcl& bin = m_bins[dim][i];
968  bin.bounds = AABB();
969  bin.enter = 0;
970  bin.exit = 0;
971  bin.enterVisible = 0;
972  bin.exitVisible = 0;
973  }
974 
975  splitPos[dim][1] = spec.boundsVisible.min()[dim];
976  splitPos[dim][2] = spec.boundsVisible.max()[dim];
977  }
978 
979  // Chop references into bins.
980 
981  for (int refIdx = start; refIdx < end+1; refIdx++)
982  {
983  const Reference& ref = m_refStack[refIdx];
984  Vec3i firstBin, lastBin;
985  for (int dim = 0; dim < 3; dim++)
986  {
987  firstBin[dim] = ref.bounds.min()[dim] < splitPos[dim][1] ? 0 : ref.bounds.min()[dim] <= splitPos[dim][2] ? 1 : 2;
988  lastBin[dim] = ref.bounds.max()[dim] < splitPos[dim][1] ? 0 : ref.bounds.max()[dim] <= splitPos[dim][2] ? 1 : 2;
989  }
990 
991  for (int dim = 0; dim < 3; dim++)
992  {
993  Reference currRef = ref;
994  for (int i = firstBin[dim]; i < lastBin[dim]; i++)
995  {
996  Reference leftRef, rightRef;
997  splitReference(leftRef, rightRef, currRef, dim, splitPos[dim][i + 1]);
998  if(leftRef.bounds.valid()) // May be invalid because the boxes are inflated by BVH_EPSILON
999  m_bins[dim][i].bounds.grow(leftRef.bounds);
1000  currRef = rightRef;
1001  }
1002  if(currRef.bounds.valid()) // May be invalid because the boxes are inflated by BVH_EPSILON
1003  m_bins[dim][lastBin[dim]].bounds.grow(currRef.bounds);
1004  m_bins[dim][firstBin[dim]].enter++;
1005  m_bins[dim][lastBin[dim]].exit++;
1006  if(ref.numVisible)
1007  {
1008  m_bins[dim][firstBin[dim]].enterVisible++;
1009  m_bins[dim][lastBin[dim]].exitVisible++;
1010  }
1011  }
1012  }
1013 
1014  // Select best split plane.
1015 
1016  SpatialSplitOcl split;
1017  for (int dim = 0; dim < 3; dim++)
1018  {
1019  // Sweep right to left and determine bounds.
1020 
1021  AABB rightBounds;
1022  for (int i = numBins - 1; i > 0; i--)
1023  {
1024  if(m_bins[dim][i].bounds.valid())
1025  rightBounds.grow(m_bins[dim][i].bounds);
1026  m_rightBounds[i - 1] = rightBounds;
1027  }
1028 
1029  // Sweep left to right and select lowest SAH.
1030 
1031  AABB leftBounds;
1032  int leftNum = 0;
1033  int rightNum = spec.numRef;
1034 
1035  // Starting visibilities
1036  visibleLeft = 0;
1037  visibleRight = spec.numVisible;
1038 
1039 #ifdef ENABLE_GRAPHS
1040  if(level == 0)
1041  {
1042  // Open file buffer
1043  CreateDirectory(m_params.logDirectory.getPtr(), NULL);
1044  String name = sprintf("%s\\cost_%s%d_%c.log", m_params.logDirectory.getPtr(), m_params.buildName.getPtr(), m_params.cameraIdx, dimStr[dim]);
1045  file = new File(name, File::Create);
1046  buffer = new BufferedOutputStream(*file, 1024, true, true);
1047  }
1048 #endif
1049 
1050  for (int i = 1; i < numBins; i++)
1051  {
1052  if(!m_bins[dim][i-1].bounds.valid())
1053  continue;
1054 
1055  leftBounds.grow(m_bins[dim][i - 1].bounds);
1056  leftNum += m_bins[dim][i - 1].enter;
1057  rightNum -= m_bins[dim][i - 1].exit;
1058  visibleLeft += m_bins[dim][i - 1].enterVisible;
1059  visibleRight -= m_bins[dim][i - 1].exitVisible;
1060 
1061  F32 osah = FW_F32_MAX;
1062  if(visibleLeft == 0 || visibleRight == 0)
1063  {
1064  F32 weight = m_params.osahWeight * (1.0f - (float)spec.numVisible/(float)(end-start+1));
1065  F32 probL = weight * ((float)(visibleLeft)/(float)spec.numVisible) + (1.0f - weight) * leftBounds.area()/spec.bounds.area();
1066  F32 probR = weight * ((float)(visibleRight)/(float)spec.numVisible) + (1.0f - weight) * m_rightBounds[i - 1].area()/spec.bounds.area();
1067  osah = nodeSAH + probL * m_platform.getTriangleCost(leftNum) + probR * m_platform.getTriangleCost(rightNum);
1068  }
1069 
1070  if (osah < split.sah)
1071  {
1072  split.sah = osah;
1073  split.dim = dim;
1074  split.pos = splitPos[dim][i];
1075  split.leftArea = leftBounds.area();
1076  split.rightArea = m_rightBounds[i - 1].area();
1077  split.leftNum = leftNum;
1078  split.rightNum = rightNum;
1079  split.leftVisible = visibleLeft;
1080  split.rightVisible = visibleRight;
1081  }
1082 
1083 #ifdef ENABLE_GRAPHS
1084  // Print split data
1085  if(level == 0)
1086  {
1087  if(osah < FW_F32_MAX)
1088  buffer->writef("%d\t?\t%f\n", i, osah);
1089  else
1090  buffer->writef("%d\t?\t%f\n", i, (float)2.0f*spec.numRef); // Should be always larger than any computed cost but small enough not to distort the graph
1091  //buffer->writef("%d\t%f\t?\n", i, sah);
1092  }
1093 #endif
1094  }
1095 
1096 #ifdef ENABLE_GRAPHS
1097  // Free file buffer
1098  if(level == 0)
1099  {
1100  buffer->flush();
1101  delete file;
1102  delete buffer;
1103  }
1104 endif
1105  }
1106 
1107  //S32 invisChild = split.leftVisible < split.rightVisible ? split.leftNum : split.rightNum;
1108  //S32 visChild = split.leftVisible < split.rightVisible ? split.rightNum : split.leftNum;
1109 
1110  F32 visibleSAH, invisibleSAH;
1111  if(split.leftVisible < split.rightVisible)
1112  {
1113  visibleSAH = split.rightArea * m_platform.getTriangleCost(split.rightNum);
1114  invisibleSAH = nodeSAH + split.leftArea * m_platform.getTriangleCost(split.leftNum);
1115  }
1116  else
1117  {
1118  visibleSAH = nodeSAH + split.leftArea * m_platform.getTriangleCost(split.leftNum);
1119  invisibleSAH = split.rightArea * m_platform.getTriangleCost(split.rightNum);
1120  }
1121 
1122  //if(split.sah < FW_F32_MAX && invisChild > visChild)
1123  if(visibleSAH*2.0f < invisibleSAH)
1124  {
1125  return split;
1126  }
1127  else
1128  {
1129  split.dim = -1;
1130  return split;
1131  }
1132 }*/
1133 
1134 //------------------------------------------------------------------------
1135 
1136 void OcclusionBVHBuilder::performSpatialOccludeSplit(NodeSpecOcl& left, NodeSpecOcl& right, int& start, int& end, const SpatialSplitOcl& split)
1137 {
1138  // Categorize references and compute bounds.
1139  //
1140  // Left-hand side: [leftStart, leftEnd[
1141  // Uncategorized/split: [leftEnd, rightStart[
1142  // Right-hand side: [rightStart, refs.getSize()[
1143 
1144  Array<Reference>& refs = m_refStack;
1145  int leftStart = start;
1146  int leftEnd = leftStart;
1147  int rightStart = end+1;
1148  left.bounds = right.bounds = AABB();
1149  //left.boundsVisible = right.boundsVisible = AABB();
1150 
1151  for (int i = leftEnd; i < rightStart; i++)
1152  {
1153  // Entirely on the left-hand side?
1154 
1155  if (refs[i].bounds.max()[split.dim] <= split.pos)
1156  {
1157  left.bounds.grow(refs[i].bounds);
1158  //if(refs[i].numVisible)
1159  // left.boundsVisible.grow(refs[i].bounds);
1160  left.numVisible += m_visibility[i];
1161  swap(refs[i], refs[leftEnd]);
1162  swap(m_visibility[i], m_visibility[leftEnd]);
1163  leftEnd++;
1164  }
1165 
1166  // Entirely on the right-hand side?
1167 
1168  else if (refs[i].bounds.min()[split.dim] >= split.pos)
1169  {
1170  right.bounds.grow(refs[i].bounds);
1171  //if(refs[i].numVisible)
1172  // right.boundsVisible.grow(refs[i].bounds);
1173  right.numVisible += m_visibility[i];
1174  rightStart--;
1175  swap(refs[i], refs[rightStart]);
1176  swap(m_visibility[i], m_visibility[rightStart]);
1177  i--;
1178  }
1179  }
1180 
1181  // Duplicate or unsplit references intersecting both sides.
1182 
1183  while (leftEnd < rightStart)
1184  {
1185  // Split reference.
1186 
1187  Reference lref, rref;
1188  splitReference(lref, rref, refs[leftEnd], split.dim, split.pos);
1189 
1190  // Compute SAH for duplicate/unsplit candidates.
1191 
1192  AABB lub = left.bounds; // Unsplit to left: new left-hand bounds.
1193  AABB rub = right.bounds; // Unsplit to right: new right-hand bounds.
1194  AABB ldb = left.bounds; // Duplicate: new left-hand bounds.
1195  AABB rdb = right.bounds; // Duplicate: new right-hand bounds.
1196  lub.grow(refs[leftEnd].bounds);
1197  rub.grow(refs[leftEnd].bounds);
1198  ldb.grow(lref.bounds);
1199  rdb.grow(rref.bounds);
1200 
1201  if(!lref.bounds.valid()) // Unsplit to right
1202  {
1203  right.bounds = rub;
1204  //if(refs[leftEnd].numVisible)
1205  // right.boundsVisible.grow(refs[leftEnd].bounds);
1206  right.numVisible += m_visibility[leftEnd];
1207  rightStart--;
1208  swap(refs[leftEnd], refs[rightStart]);
1209  swap(m_visibility[leftEnd], m_visibility[rightStart]);
1210  continue;
1211  }
1212  if(!rref.bounds.valid()) // Unsplit to left
1213  {
1214  left.bounds = lub;
1215  //if(refs[leftEnd].numVisible)
1216  // left.boundsVisible.grow(refs[leftEnd].bounds);
1217  left.numVisible += m_visibility[leftEnd];
1218  leftEnd++;
1219  continue;
1220  }
1221 
1222  F32 lac = m_platform.getTriangleCost(leftEnd - leftStart);
1223  F32 rac = m_platform.getTriangleCost(end+1 - rightStart);
1224  F32 lbc = m_platform.getTriangleCost(leftEnd - leftStart + 1);
1225  F32 rbc = m_platform.getTriangleCost(end+1 - rightStart + 1);
1226 
1227  F32 unsplitLeftSAH = lub.area() * lbc + right.bounds.area() * rac;
1228  F32 unsplitRightSAH = left.bounds.area() * lac + rub.area() * rbc;
1229  F32 duplicateSAH = ldb.area() * lbc + rdb.area() * rbc;
1230  F32 minSAH = min(unsplitLeftSAH, unsplitRightSAH, duplicateSAH);
1231 
1232  // Unsplit to left?
1233 
1234  if (minSAH == unsplitLeftSAH && (!split.osahChosen || split.leftVisible))
1235  {
1236  left.bounds = lub;
1237  //if(refs[leftEnd].numVisible)
1238  // left.boundsVisible.grow(refs[leftEnd].bounds);
1239  left.numVisible += m_visibility[leftEnd];
1240  leftEnd++;
1241  }
1242 
1243  // Unsplit to right?
1244 
1245  else if (minSAH == unsplitRightSAH && (!split.osahChosen || split.rightVisible))
1246  {
1247  right.bounds = rub;
1248  //if(refs[leftEnd].numVisible)
1249  // right.boundsVisible.grow(refs[leftEnd].bounds);
1250  right.numVisible += m_visibility[leftEnd];
1251  rightStart--;
1252  swap(refs[leftEnd], refs[rightStart]);
1253  swap(m_visibility[leftEnd], m_visibility[rightStart]);
1254  }
1255 
1256  // Duplicate?
1257 
1258  else
1259  {
1260  left.bounds = ldb;
1261  right.bounds = rdb;
1262  left.numVisible += m_visibility[leftEnd];
1263  right.numVisible += m_visibility[leftEnd];
1264  S32 refVis = m_visibility[leftEnd]; // Must be saved because allocation in 'add' might change memory location of the reference
1265  //if(refs[leftEnd].numVisible)
1266  //{
1267  // left.boundsVisible.grow(lref.bounds);
1268  // right.boundsVisible.grow(rref.bounds);
1269  //}
1270  refs[leftEnd] = lref;
1271  refs.add(rref);
1272  m_visibility.add(refVis); // Add visibility for the new reference
1273  leftEnd++;
1274  end++;
1275  swap(refs[end], refs.getLast()); // If we weren't building from right to left this would cause a bug
1277  }
1278 
1279  //if(left.numVisible && right.numVisible)
1280  // fail("Visible triangles division!");
1281  }
1282 
1283  left.numRef = leftEnd - leftStart;
1284  right.numRef = end+1 - rightStart;
1285 }
1286 
1287 //------------------------------------------------------------------------
1288 
1289 bool OcclusionBVHBuilder::sortCompare(void* data, int idxA, int idxB)
1290 {
1291  const OcclusionBVHBuilder* ptr = (const OcclusionBVHBuilder*)data;
1292  int dim = ptr->m_sortDim;
1293  const Reference& ra = ptr->m_refStack[idxA];
1294  const Reference& rb = ptr->m_refStack[idxB];
1295  F32 ca = ra.bounds.min()[dim] + ra.bounds.max()[dim];
1296  F32 cb = rb.bounds.min()[dim] + rb.bounds.max()[dim];
1297  return (ca < cb || (ca == cb && ra.triIdx < rb.triIdx));
1298 }
1299 
bool enablePrints
Flag whether to enable prints about build progress.
Definition: BVH.hpp:112
Stucture holding the BVH build parameters.
Definition: BVH.hpp:109
virtual void flush(void)
Definition: Stream.cpp:275
#define NULL
Definition: Defs.hpp:39
#define FW_F32_MAX
Definition: Defs.hpp:118
Maximum depth of the BVH tree.
const char * getPtr(void) const
Definition: String.hpp:51
Buffer & getTriVtxIndexBuffer(void)
Returns buffer of triangle's vertex indieces.
Definition: Scene.hpp:75
void sort(void *data, int start, int end, SortCompareFunc compareFunc, SortSwapFunc swapFunc, bool multicore=false)
Definition: Sort.cpp:203
SpatialSplitOcl findSpatialOccludeSplit(const NodeSpecOcl &spec, int start, int end, F32 nodeSAH)
FW_CUDA_FUNC const Vec3f & max(void) const
Definition: Util.hpp:49
Array< Reference > m_refStack
Reference stack.
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer
Definition: DLLImports.inl:315
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid * data
Definition: DLLImports.inl:319
BVHNode * buildNode(NodeSpec spec, int level, F32 progressStart, F32 progressEnd)
Builds a BVH node. The built node may be an inner node as well as a leaf node.
const char * name
Definition: DLLImports.cpp:42
void ** ptr
Definition: DLLImports.cpp:74
Buffer & getVtxPosBuffer(void)
Returns vertex position buffer.
Definition: Scene.hpp:103
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v GLuint v GLenum GLenum GLenum GLuint GLint level GLsizei GLuint framebuffers GLuint const GLchar name GLenum GLintptr GLsizeiptr GLvoid data GLuint GLenum GLint param GLuint GLenum GLint param GLhandleARB programObj GLenum GLenum GLsizei GLsizei height GLenum GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid pixels GLint GLsizei const GLfloat value GLint GLfloat GLfloat v1 GLint GLfloat GLfloat GLfloat v2 GLint GLsizei const GLfloat value GLint GLsizei GLboolean const GLfloat value GLuint program GLuint GLfloat GLfloat GLfloat z GLuint GLint GLenum GLboolean GLsizei const GLvoid pointer GLuint GLuint const GLchar name GLenum GLsizei GLenum GLsizei GLsizei height GLenum GLuint renderbuffer GLenum GLenum GLint * params
Definition: DLLImports.inl:373
Array< AABB > m_rightBounds
Bounding boxes of all the possible right children.
BVHNode * createLeaf(const NodeSpec &spec)
Builds a leaf node.
BVH inner node.
Definition: BVHNode.hpp:228
OcclusionBVHBuilder(BVH &bvh, const BVH::BuildParams &params, const Vec3f &cameraPosition)
void start(void)
Definition: Timer.hpp:42
BVH & m_bvh
BVH being built.
float getTriangleCost(S32 n) const
Calcuates cost of a given number of triangles rounded to the batch size.
Definition: Platform.hpp:95
const U8 * getPtr(S64 ofs=0)
Definition: Buffer.hpp:106
F32 splitAlpha
Spatial split area threshold.
Definition: BVH.hpp:113
SpatialBinOcl m_bins[3][NumSpatialBins]
const BVH::BuildParams & m_params
Build parameters.
S getNumBytes(void) const
Definition: Array.hpp:225
S32 m_numDuplicates
Number of duplicated references.
ObjectSplitOcl findObjectSplit(const NodeSpecOcl &spec, int start, int end, F32 nodeSAH)
SpatialSplitOcl findSpatialSplit(const NodeSpecOcl &spec, int start, int end, F32 nodeSAH)
BVHNode * buildNode(const NodeSpecOcl &spec, int start, int end, int level, F32 progressStart, F32 progressEnd)
void reset(S size=0)
Definition: Array.hpp:317
const Platform & m_platform
Platform settings.
Array< S32 > & getTriIndices(void)
Returns an array of triangle indices to which leaf nodes are pointig. These indices point to scene's ...
Definition: BVH.hpp:180
F32 osahWeight
Weighting factor for OSAH construction.
Definition: BVH.hpp:114
float F32
Definition: Defs.hpp:89
const T & getLast(void) const
Definition: Array.hpp:272
Scene * getScene(void) const
FW_CUDA_FUNC float area(void) const
Definition: Util.hpp:45
float getNodeCost(S32 n) const
Calculates cost of a given number of nodes rounded to the batch size.
Definition: Platform.hpp:102
FW_CUDA_FUNC bool valid(void) const
Definition: Util.hpp:46
FW_CUDA_FUNC T min(const VectorBase< T, L, S > &v)
Definition: Math.hpp:461
FW_CUDA_FUNC T max(const VectorBase< T, L, S > &v)
Definition: Math.hpp:462
S32 m_sortDim
Sort dimension. Used by sort method.
int getNumTriangles(void) const
Definition: Scene.hpp:61
BVH acceleration structure class.
Definition: BVH.hpp:74
ObjectSplitOcl findObjectOccludeSplit(const NodeSpecOcl &spec, int start, int end, F32 nodeSAH)
static void sortSwap(void *data, int idxA, int idxB)
F32 m_minOverlap
Minimum overlap of the left and right AABB of the object split needed to make spatial split worth fin...
Maximum depth of the BVH where spatial split will still be used.
signed int S32
Definition: Defs.hpp:88
void splitReference(Reference &left, Reference &right, const Reference &ref, int dim, F32 pos)
Splits the triangle's bounding box.
String logDirectory
Directory where the log file will be saved.
Definition: BVH.hpp:118
void performObjectSplit(NodeSpecOcl &left, NodeSpecOcl &right, const NodeSpecOcl &spec, int start, int end, const ObjectSplitOcl &split)
SplitType
Available split types.
Definition: BVHNode.hpp:65
static bool sortCompare(void *data, int idxA, int idxB)
T & add(void)
Definition: Array.hpp:384
FW_CUDA_FUNC const Vec3f & min(void) const
Definition: Util.hpp:48
String sprintf(const char *fmt,...)
Definition: Defs.cpp:241
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int dim
Definition: DLLImports.inl:74
virtual BVHNode * run(void)
Buffer * visibility
Visibility buffer for the CPU renderer.
Definition: BVH.hpp:117
int cameraIdx
Camera index.
Definition: BVH.hpp:120
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction f
Definition: DLLImports.inl:88
Number of spatial bins per node in each axis.
FW_CUDA_FUNC void grow(const Vec3f &pt)
Definition: Util.hpp:41
Class performing SBVH build.
void printf(const char *fmt,...)
Definition: Defs.cpp:225
S32 triIdx
Index of the triangle.
S32 getMaxLeafSize() const
Definition: Platform.hpp:157
FW_CUDA_FUNC F64 log(F64 a)
Definition: Math.hpp:47
void compact(void)
Definition: Array.hpp:335
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v GLuint v GLenum GLenum GLenum GLuint GLint level
Definition: DLLImports.inl:333
FW_CUDA_FUNC void swap(T &a, T &b)
Definition: Defs.hpp:183
String buildName
Build name.
Definition: BVH.hpp:119
T set(S idx, const T &item)
Definition: Array.hpp:248
void performSpatialOccludeSplit(NodeSpecOcl &left, NodeSpecOcl &right, int &start, int &end, const SpatialSplitOcl &split)
BVH virtual node. Parent class of both a leaf node and an inner node.
Definition: BVHNode.hpp:136
#define BVH_EPSILON
AABB bounds
Bounding box of the triangle.
void writef(const char *fmt,...)
Definition: Stream.cpp:239
const T * getPtr(S idx=0) const
Definition: Array.hpp:202
S32 getMinLeafSize() const
Definition: Platform.hpp:152
F32 getElapsed(void)
Definition: Timer.hpp:44
Structure holding triangle's index together with its bounding box.
FW_CUDA_FUNC void intersect(const AABB &aabb)
Definition: Util.hpp:43
void resize(S size)
Definition: Array.hpp:366
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v GLuint v GLenum GLenum GLenum GLuint GLint level GLsizei GLuint framebuffers GLuint const GLchar name GLenum GLintptr GLsizeiptr GLvoid data GLuint GLenum GLint param GLuint GLenum GLint param GLhandleARB programObj GLenum GLenum GLsizei GLsizei height GLenum GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid pixels GLint GLsizei const GLfloat value GLint GLfloat GLfloat v1 GLint GLfloat GLfloat GLfloat v2 GLint GLsizei const GLfloat value GLint GLsizei GLboolean const GLfloat value GLuint program GLuint GLfloat GLfloat GLfloat z GLuint GLint GLenum GLboolean GLsizei const GLvoid pointer GLuint GLuint const GLchar name GLenum GLsizei GLenum GLsizei GLsizei height GLenum GLuint renderbuffer GLenum GLenum GLint params GLuint GLsizei range GLuint GLsizei const GLubyte GLsizei GLenum const GLvoid coords GLuint GLsizei GLsizei GLsizei const GLubyte GLsizei GLenum const GLvoid coords GLuint GLenum GLsizei const GLvoid pathString GLuint GLenum const GLvoid GLbitfield GLuint GLsizei GLenum GLuint GLfloat emScale GLuint GLuint srcPath GLuint GLuint GLenum const GLfloat transformValues GLuint GLenum GLint value GLuint GLenum GLfloat value GLenum GLint ref
Definition: DLLImports.inl:400
FW_CUDA_FUNC A lerp(const A &a, const A &b, const B &t)
Definition: Math.hpp:115
Timer m_progressTimer
Progress timer.
bool twoTrees
Flag whether to build BVH from two separate trees.
Definition: BVH.hpp:121