metadata
Wenzel Jakob 2010-10-11 21:04:05 +02:00
parent 84cff419f8
commit baa41a195a
2 changed files with 226 additions and 42 deletions

View File

@ -174,7 +174,7 @@ public:
} }
} }
#if defined(MTS_KD_DEBUG) #if defined(MTS_KD_DEBUG)
/* Uh oh, allocation could not be found. Check if it has size==0 */ /* Uh oh, allocation could not be found. Check if it has size == 0 */
if (newSize == 0) { if (newSize == 0) {
for (std::vector<Chunk>::iterator it = m_chunks.begin(); for (std::vector<Chunk>::iterator it = m_chunks.begin();
it != m_chunks.end(); ++it) { it != m_chunks.end(); ++it) {
@ -476,9 +476,12 @@ public:
m_exactPrimThreshold = 65536; m_exactPrimThreshold = 65536;
m_maxDepth = 0; m_maxDepth = 0;
m_retract = true; m_retract = true;
m_parallel = true; m_parallelBuild = true;
} }
/**
* \brief Release all memory
*/
virtual ~GenericKDTree() { virtual ~GenericKDTree() {
if (m_indices) if (m_indices)
delete[] m_indices; delete[] m_indices;
@ -486,6 +489,160 @@ public:
delete[] m_nodes; delete[] m_nodes;
} }
/**
* \brief Set the traversal cost used by the surface area heuristic
*/
inline void setTraversalCost(Float traversalCost) {
m_traversalCost = traversalCost;
}
/**
* \brief Return the traversal cost used by the surface area heuristic
*/
inline Float getTraversalCost() const {
return m_traversalCost;
}
/**
* \brief Set the intersection cost used by the surface area heuristic
*/
inline void setIntersectionCost(Float intersectionCost) {
m_intersectionCost = intersectionCost;
}
/**
* \brief Return the intersection cost used by the surface area heuristic
*/
inline Float getIntersectionCost() const {
return m_intersectionCost;
}
/**
* \brief Set the bonus factor for empty space used by the
* surface area heuristic
*/
inline void setEmptySpaceBonus(Float emptySpaceBonus) {
m_emptySpaceBonus = emptySpaceBonus;
}
/**
* \brief Return the bonus factor for empty space used by the
* surface area heuristic
*/
inline Float getEmptySpaceBonus() const {
return m_emptySpaceBonus;
}
/**
* \brief Set the maximum tree depth (0 = use heuristic)
*/
inline void setMaxDepth(size_type maxDepth) {
m_maxDepth = maxDepth;
}
/**
* \brief Return maximum tree depth (0 = use heuristic)
*/
inline size_type getMaxDepth() const {
return m_maxDepth;
}
/**
* \brief Specify whether or not to use primitive clipping will
* be used in the tree construction.
*/
inline void setClip(bool clip) {
m_clip = clip;
}
/**
* \brief Return whether or not to use primitive clipping will
* be used in the tree construction.
*/
inline bool getClip() const {
return m_clip;
}
/**
* \brief Specify whether or not bad splits can be "retracted".
*/
inline void setRetract(bool retract) {
m_retract = retract;
}
/**
* \brief Return whether or not bad splits can be "retracted".
*/
inline bool getRetract() const {
return m_retract;
}
/**
* \brief Set the number of bad refines allowed to happen
* in succession before a leaf node will be created.
*/
inline void setMaxBadRefines(size_type maxBadRefines) {
m_maxBadRefines = maxBadRefines;
}
/**
* \brief Return the number of bad refines allowed to happen
* in succession before a leaf node will be created.
*/
inline size_type getMaxBadRefines() const {
return m_maxBadRefines;
}
/**
* \brief Set the number of primitives, at which recursion will
* stop when building the tree.
*/
inline void setStopPrims(size_type stopPrims) {
m_stopPrims = stopPrims;
}
/**
* \brief Return the number of primitives, at which recursion will
* stop when building the tree.
*/
inline size_type getStopPrims() const {
return m_stopPrims;
}
/**
* \brief Specify whether or not tree construction
* should run in parallel.
*/
inline void setParallelBuild(bool parallel) {
m_parallelBuild = parallel;
}
/**
* \brief Return whether or not tree construction
* will run in parallel.
*/
inline bool getParallelBuild() const {
return m_parallelBuild;
}
/**
* \brief Specify the number of primitives, at which the builder will switch
* from (approximate) Min-Max binning to the accurate O(n log n) SAH-based
* optimization method.
*/
inline void setExactPrimitiveThreshold(bool exactPrimThreshold) {
m_exactPrimThreshold = exactPrimThreshold;
}
/**
* \brief Return the number of primitives, at which the builder will switch
* from (approximate) Min-Max binning to the accurate O(n log n) SAH-based
* optimization method.
*/
inline bool getExactPrimitiveThreshold() const {
return m_exactPrimThreshold;
}
/** /**
* \brief Build a KD-tree over supplied geometry * \brief Build a KD-tree over supplied geometry
*/ */
@ -525,7 +682,8 @@ public:
Log(EDebug, " Scene bounding box (min) : %s", m_aabb.min.toString().c_str()); Log(EDebug, " Scene bounding box (min) : %s", m_aabb.min.toString().c_str());
Log(EDebug, " Scene bounding box (max) : %s", m_aabb.max.toString().c_str()); Log(EDebug, " Scene bounding box (max) : %s", m_aabb.max.toString().c_str());
Log(EDebug, " Min-max bins : %i", MTS_KD_MINMAX_BINS); Log(EDebug, " Min-max bins : %i", MTS_KD_MINMAX_BINS);
Log(EDebug, " Greedy SAH optimization : use for <= %i primitives", m_exactPrimThreshold); Log(EDebug, " Greedy SAH optimization : use for <= %i primitives",
m_exactPrimThreshold);
Log(EDebug, " Perfect splits : %s", m_clip ? "yes" : "no"); Log(EDebug, " Perfect splits : %s", m_clip ? "yes" : "no");
Log(EDebug, " Retract bad splits : %s", m_retract ? "yes" : "no"); Log(EDebug, " Retract bad splits : %s", m_retract ? "yes" : "no");
Log(EDebug, " Stopping primitive count : %i", m_stopPrims); Log(EDebug, " Stopping primitive count : %i", m_stopPrims);
@ -533,9 +691,9 @@ public:
size_type procCount = getProcessorCount(); size_type procCount = getProcessorCount();
if (procCount == 1) if (procCount == 1)
m_parallel = false; m_parallelBuild = false;
if (m_parallel) { if (m_parallelBuild) {
m_builders.resize(procCount); m_builders.resize(procCount);
for (size_type i=0; i<procCount; ++i) { for (size_type i=0; i<procCount; ++i) {
m_builders[i] = new SAHTreeBuilder(i, this); m_builders[i] = new SAHTreeBuilder(i, this);
@ -555,7 +713,7 @@ public:
KDAssert(ctx.leftAlloc.used() == 0); KDAssert(ctx.leftAlloc.used() == 0);
KDAssert(ctx.rightAlloc.used() == 0); KDAssert(ctx.rightAlloc.used() == 0);
if (m_parallel) { if (m_parallelBuild) {
m_interface.done = true; m_interface.done = true;
m_interface.cond->broadcast(); m_interface.cond->broadcast();
for (size_type i=0; i<m_builders.size(); ++i) for (size_type i=0; i<m_builders.size(); ++i)
@ -652,7 +810,8 @@ public:
float split = node->getSplit(); float split = node->getSplit();
bool result = target->initInnerNode(axis, split, children - target); bool result = target->initInnerNode(axis, split, children - target);
if (!result) if (!result)
Log(EError, "Cannot represent relative pointer -- too many primitives?"); Log(EError, "Cannot represent relative pointer -- "
"too many primitives?");
Float tmp = aabb.min[axis]; Float tmp = aabb.min[axis];
aabb.min[axis] = split; aabb.min[axis] = split;
@ -861,10 +1020,12 @@ protected:
leftAlloc.getChunkCount(), memString(leftAlloc.size()).c_str()); leftAlloc.getChunkCount(), memString(leftAlloc.size()).c_str());
Log(EDebug, " Right events : " SIZE_T_FMT " chunks (%s)", Log(EDebug, " Right events : " SIZE_T_FMT " chunks (%s)",
rightAlloc.getChunkCount(), memString(rightAlloc.size()).c_str()); rightAlloc.getChunkCount(), memString(rightAlloc.size()).c_str());
Log(EDebug, " kd-tree nodes : " SIZE_T_FMT " entries, " SIZE_T_FMT " blocks (%s)", Log(EDebug, " kd-tree nodes : " SIZE_T_FMT " entries, " SIZE_T_FMT
nodes.size(), nodes.blockCount(), memString(nodes.capacity() * sizeof(KDNode)).c_str()); " blocks (%s)", nodes.size(), nodes.blockCount(),
Log(EDebug, " Indices : " SIZE_T_FMT " entries, " SIZE_T_FMT " blocks (%s)", memString(nodes.capacity() * sizeof(KDNode)).c_str());
indices.size(), indices.blockCount(), memString(indices.capacity() * sizeof(index_type)).c_str()); Log(EDebug, " Indices : " SIZE_T_FMT " entries, " SIZE_T_FMT
" blocks (%s)", indices.size(), indices.blockCount(),
memString(indices.capacity() * sizeof(index_type)).c_str());
} }
void accumulateStatisticsFrom(const BuildContext &ctx) { void accumulateStatisticsFrom(const BuildContext &ctx) {
@ -915,7 +1076,8 @@ protected:
/* Bit layout: /* Bit layout:
31 : False (inner node) 31 : False (inner node)
30 : Indirection node flag 30 : Indirection node flag
29-3 : Offset to the left child 29-3 : Offset to the left child
or indirection table entry
2-0 : Split axis 2-0 : Split axis
*/ */
uint32_t combined; uint32_t combined;
@ -972,8 +1134,11 @@ protected:
* they lie in different memory chunks. In this case, the node * they lie in different memory chunks. In this case, the node
* stores an index into a globally shared pointer list. * stores an index into a globally shared pointer list.
*/ */
inline void initIndirectionNode(int axis, float split, uint32_t indirectionEntry) { inline void initIndirectionNode(int axis, float split,
inner.combined = EIndirectionMask | axis | ((uint32_t) indirectionEntry << 2); uint32_t indirectionEntry) {
inner.combined = EIndirectionMask
| ((uint32_t) indirectionEntry << 2)
| axis;
inner.split = split; inner.split = split;
} }
@ -1069,7 +1234,8 @@ protected:
int badRefines = m_interface.badRefines; int badRefines = m_interface.badRefines;
EdgeEvent *eventStart = leftAlloc.allocate<EdgeEvent>(eventCount), EdgeEvent *eventStart = leftAlloc.allocate<EdgeEvent>(eventCount),
*eventEnd = eventStart + eventCount; *eventEnd = eventStart + eventCount;
memcpy(eventStart, m_interface.eventStart, eventCount * sizeof(EdgeEvent)); memcpy(eventStart, m_interface.eventStart,
eventCount * sizeof(EdgeEvent));
m_interface.threadMap[node] = m_id; m_interface.threadMap[node] = m_id;
m_interface.node = NULL; m_interface.node = NULL;
m_interface.condJobTaken->signal(); m_interface.condJobTaken->signal();
@ -1110,7 +1276,8 @@ protected:
* accurate SAH-based optimizier. * accurate SAH-based optimizier.
*/ */
boost::tuple<EdgeEvent *, EdgeEvent *, size_type> createEventList( boost::tuple<EdgeEvent *, EdgeEvent *, size_type> createEventList(
OrderedChunkAllocator &alloc, const AABB &nodeAABB, index_type *prims, size_type primCount) { OrderedChunkAllocator &alloc, const AABB &nodeAABB,
index_type *prims, size_type primCount) {
size_type initialSize = primCount * 6, actualPrimCount = 0; size_type initialSize = primCount * 6, actualPrimCount = 0;
EdgeEvent *eventStart = alloc.allocate<EdgeEvent>(initialSize); EdgeEvent *eventStart = alloc.allocate<EdgeEvent>(initialSize);
EdgeEvent *eventEnd = eventStart; EdgeEvent *eventEnd = eventStart;
@ -1296,11 +1463,12 @@ protected:
} }
if (primCount <= m_exactPrimThreshold) { if (primCount <= m_exactPrimThreshold) {
OrderedChunkAllocator &alloc = isLeftChild ? ctx.leftAlloc : ctx.rightAlloc; OrderedChunkAllocator &alloc = isLeftChild
? ctx.leftAlloc : ctx.rightAlloc;
boost::tuple<EdgeEvent *, EdgeEvent *, size_type> events boost::tuple<EdgeEvent *, EdgeEvent *, size_type> events
= createEventList(alloc, nodeAABB, indices, primCount); = createEventList(alloc, nodeAABB, indices, primCount);
Float sahCost; Float sahCost;
if (m_parallel) { if (m_parallelBuild) {
m_interface.mutex->lock(); m_interface.mutex->lock();
m_interface.depth = depth; m_interface.depth = depth;
m_interface.node = node; m_interface.node = node;
@ -1320,10 +1488,11 @@ protected:
// Never tear down this subtree (return a SAH cost of -infinity) // Never tear down this subtree (return a SAH cost of -infinity)
sahCost = -std::numeric_limits<Float>::infinity(); sahCost = -std::numeric_limits<Float>::infinity();
} else { } else {
std::sort(boost::get<0>(events), boost::get<1>(events), EdgeEventOrdering()); std::sort(boost::get<0>(events), boost::get<1>(events),
EdgeEventOrdering());
sahCost = buildTreeSAH(ctx, depth, node, nodeAABB, sahCost = buildTreeSAH(ctx, depth, node, nodeAABB,
boost::get<0>(events), boost::get<1>(events), boost::get<2>(events), boost::get<0>(events), boost::get<1>(events), boost::get<2>(events),
isLeftChild, badRefines); isLeftChild, badRefines);
} }
alloc.release(boost::get<0>(events)); alloc.release(boost::get<0>(events));
@ -1572,7 +1741,8 @@ protected:
sahCostPlanarLeft *= m_emptySpaceBonus; sahCostPlanarLeft *= m_emptySpaceBonus;
if (nL == 0 || nR + numPlanar == 0) if (nL == 0 || nR + numPlanar == 0)
sahCostPlanarRight *= m_emptySpaceBonus; sahCostPlanarRight *= m_emptySpaceBonus;
if (sahCostPlanarLeft < bestSplit.sahCost || sahCostPlanarRight < bestSplit.sahCost) { if (sahCostPlanarLeft < bestSplit.sahCost ||
sahCostPlanarRight < bestSplit.sahCost) {
bestSplit.pos = pos; bestSplit.pos = pos;
bestSplit.axis = axis; bestSplit.axis = axis;
if (sahCostPlanarLeft < sahCostPlanarRight) { if (sahCostPlanarLeft < sahCostPlanarRight) {
@ -1660,8 +1830,8 @@ protected:
storage.set(event->index, ELeftSide); storage.set(event->index, ELeftSide);
primsBoth--; primsBoth--;
primsLeft++; primsLeft++;
} else if (event->pos > bestSplit.pos || (event->pos == bestSplit.pos && } else if (event->pos > bestSplit.pos
!bestSplit.planarLeft)) { || (event->pos == bestSplit.pos && !bestSplit.planarLeft)) {
storage.set(event->index, ERightSide); storage.set(event->index, ERightSide);
primsBoth--; primsBoth--;
primsRight++; primsRight++;
@ -1701,10 +1871,11 @@ protected:
/* ==================================================================== */ /* ==================================================================== */
if (m_clip) { if (m_clip) {
EdgeEvent *leftEventsTempStart = leftAlloc.allocate<EdgeEvent>(primsLeft * 6), EdgeEvent
*rightEventsTempStart = rightAlloc.allocate<EdgeEvent>(primsRight * 6), *leftEventsTempStart = leftAlloc.allocate<EdgeEvent>(primsLeft * 6),
*newEventsLeftStart = leftAlloc.allocate<EdgeEvent>(primsBoth * 6), *rightEventsTempStart = rightAlloc.allocate<EdgeEvent>(primsRight * 6),
*newEventsRightStart = rightAlloc.allocate<EdgeEvent>(primsBoth * 6); *newEventsLeftStart = leftAlloc.allocate<EdgeEvent>(primsBoth * 6),
*newEventsRightStart = rightAlloc.allocate<EdgeEvent>(primsBoth * 6);
EdgeEvent *leftEventsTempEnd = leftEventsTempStart, EdgeEvent *leftEventsTempEnd = leftEventsTempStart,
*rightEventsTempEnd = rightEventsTempStart, *rightEventsTempEnd = rightEventsTempStart,
@ -1732,13 +1903,17 @@ protected:
if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) { if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) {
for (int axis=0; axis<3; ++axis) { for (int axis=0; axis<3; ++axis) {
float min = (float) clippedLeft.min[axis], max = (float) clippedLeft.max[axis]; float min = (float) clippedLeft.min[axis],
max = (float) clippedLeft.max[axis];
if (min == max) { if (min == max) {
*newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, axis, min, index); *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar,
axis, min, index);
} else { } else {
*newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeStart, axis, min, index); *newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeStart,
*newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd, axis, max, index); axis, min, index);
*newEventsLeftEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd,
axis, max, index);
} }
} }
} else { } else {
@ -1747,13 +1922,17 @@ protected:
if (clippedRight.isValid() && clippedRight.getSurfaceArea() > 0) { if (clippedRight.isValid() && clippedRight.getSurfaceArea() > 0) {
for (int axis=0; axis<3; ++axis) { for (int axis=0; axis<3; ++axis) {
float min = (float) clippedRight.min[axis], max = (float) clippedRight.max[axis]; float min = (float) clippedRight.min[axis],
max = (float) clippedRight.max[axis];
if (min == max) { if (min == max) {
*newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, axis, min, index); *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar,
axis, min, index);
} else { } else {
*newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeStart, axis, min, index); *newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeStart,
*newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd, axis, max, index); axis, min, index);
*newEventsRightEnd++ = EdgeEvent(EdgeEvent::EEdgeEnd,
axis, max, index);
} }
} }
} else { } else {
@ -1922,8 +2101,10 @@ protected:
* invBinSize[axis]); * invBinSize[axis]);
int maxIdx = (int) ((aabb.max[axis] - m_aabb.min[axis]) int maxIdx = (int) ((aabb.max[axis] - m_aabb.min[axis])
* invBinSize[axis]); * invBinSize[axis]);
m_maxBins[axis * BinCount + std::max(0, std::min(maxIdx, BinCount-1))]++; m_maxBins[axis * BinCount
m_minBins[axis * BinCount + std::max(0, std::min(minIdx, BinCount-1))]++; + std::max(0, std::min(maxIdx, BinCount-1))]++;
m_minBins[axis * BinCount
+ std::max(0, std::min(minIdx, BinCount-1))]++;
} }
} }
} }
@ -2025,7 +2206,8 @@ protected:
if (idx == leftBin && idxNext > leftBin) if (idx == leftBin && idxNext > leftBin)
break; break;
if (idx < leftBin && idxNext > leftBin) { if (idx < leftBin && idxNext > leftBin) {
/* Insufficient floating point resolution -- a leaf will be created. */ /* Insufficient floating point resolution
-> a leaf will be created. */
candidate.sahCost = std::numeric_limits<Float>::infinity(); candidate.sahCost = std::numeric_limits<Float>::infinity();
break; break;
} }
@ -2035,7 +2217,8 @@ protected:
} }
if (split <= m_aabb.min[axis] || split > m_aabb.max[axis]) { if (split <= m_aabb.min[axis] || split > m_aabb.max[axis]) {
/* Insufficient floating point resolution -- a leaf will be created. */ /* Insufficient floating point resolution
-> a leaf will be created. */
candidate.sahCost = std::numeric_limits<Float>::infinity(); candidate.sahCost = std::numeric_limits<Float>::infinity();
} }
@ -2051,7 +2234,8 @@ protected:
*/ */
boost::tuple<AABB, index_type *, AABB, index_type *> partition( boost::tuple<AABB, index_type *, AABB, index_type *> partition(
BuildContext &ctx, const Derived *derived, index_type *primIndices, BuildContext &ctx, const Derived *derived, index_type *primIndices,
SplitCandidate &split, bool isLeftChild, Float traversalCost, Float intersectionCost) { SplitCandidate &split, bool isLeftChild, Float traversalCost,
Float intersectionCost) {
const float splitPos = split.pos; const float splitPos = split.pos;
const int axis = split.axis; const int axis = split.axis;
size_type numLeft = 0, numRight = 0; size_type numLeft = 0, numRight = 0;
@ -2155,7 +2339,7 @@ private:
Float m_traversalCost; Float m_traversalCost;
Float m_intersectionCost; Float m_intersectionCost;
Float m_emptySpaceBonus; Float m_emptySpaceBonus;
bool m_clip, m_retract, m_parallel; bool m_clip, m_retract, m_parallelBuild;
AABB m_aabb; AABB m_aabb;
size_type m_maxDepth; size_type m_maxDepth;
size_type m_stopPrims; size_type m_stopPrims;

View File

@ -112,7 +112,7 @@ public:
void test02_buildSimple() { void test02_buildSimple() {
Properties bunnyProps("ply"); Properties bunnyProps("ply");
bunnyProps.setString("filename", "tools/tests/lucy.ply"); bunnyProps.setString("filename", "tools/tests/happy.ply");
ref<TriMesh> mesh = static_cast<TriMesh *> (PluginManager::getInstance()-> ref<TriMesh> mesh = static_cast<TriMesh *> (PluginManager::getInstance()->
createObject(TriMesh::m_theClass, bunnyProps)); createObject(TriMesh::m_theClass, bunnyProps));