Fixes for several subtle kd-tree construction issues
- fixed several bugs that occasionally broke double-precision builds - rewrote min/max binning code to make it tolerant to precision issues. Previously, it gave up in such cases, which lead to a slow build with the O(n log n) method.metadata
parent
1f445513dd
commit
b8480a3d60
|
@ -276,15 +276,40 @@ inline size_t roundToPowerOfTwo(size_t value) {
|
||||||
return copysign((double) 1.0, value);
|
return copysign((double) 1.0, value);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cast to single precision and round up if not exactly representable (passthrough)
|
||||||
|
inline float castflt_up(float val) { return val; }
|
||||||
|
|
||||||
|
/// Cast to single precision and round up if not exactly representable
|
||||||
|
inline float castflt_up(double val) {
|
||||||
|
union {
|
||||||
|
float a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
a = (float) val;
|
||||||
|
if ((double) a < val)
|
||||||
|
b += a < 0 ? -1 : 1;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cast to single precision and round down if not exactly representable (passthrough)
|
||||||
|
inline float castflt_down(float val) { return val; }
|
||||||
|
|
||||||
|
/// Cast to single precision and round down if not exactly representable
|
||||||
|
inline float castflt_down(double val) {
|
||||||
|
union {
|
||||||
|
float a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
a = (float) val;
|
||||||
|
if ((double) a > val)
|
||||||
|
b += a > 0 ? -1 : 1;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
}; /* namespace math */
|
}; /* namespace math */
|
||||||
|
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
|
||||||
extern "C" {
|
|
||||||
extern MTS_EXPORT_CORE float nextafterf(float x, float y);
|
|
||||||
extern MTS_EXPORT_CORE double nextafter(double x, double y);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __MITSUBA_CORE_MATH_H_ */
|
#endif /* __MITSUBA_CORE_MATH_H_ */
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Special "ordered" memory allocator
|
* \brief Special "ordered" memory allocator
|
||||||
*
|
*
|
||||||
|
@ -997,10 +998,8 @@ protected:
|
||||||
|
|
||||||
#if defined(DOUBLE_PRECISION)
|
#if defined(DOUBLE_PRECISION)
|
||||||
for (int i=0; i<3; ++i) {
|
for (int i=0; i<3; ++i) {
|
||||||
aabb.min[i] = nextafterf((float) aabb.min[i],
|
aabb.min[i] = math::castflt_down(aabb.min[i]);
|
||||||
-std::numeric_limits<float>::max());
|
aabb.max[i] = math::castflt_up(aabb.max[i]);
|
||||||
aabb.max[i] = nextafterf((float) aabb.max[i],
|
|
||||||
std::numeric_limits<float>::max());
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1346,10 +1345,11 @@ protected:
|
||||||
int axis;
|
int axis;
|
||||||
SizeType numLeft, numRight;
|
SizeType numLeft, numRight;
|
||||||
bool planarLeft;
|
bool planarLeft;
|
||||||
|
int leftBin;
|
||||||
|
|
||||||
inline SplitCandidate() :
|
inline SplitCandidate() :
|
||||||
cost(std::numeric_limits<Float>::infinity()),
|
cost(std::numeric_limits<Float>::infinity()),
|
||||||
pos(0), axis(0), numLeft(0), numRight(0), planarLeft(false) {
|
pos(0), axis(0), numLeft(0), numRight(0), planarLeft(false), leftBin(-1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
|
@ -1360,6 +1360,7 @@ protected:
|
||||||
<< " axis=" << axis << "," << endl
|
<< " axis=" << axis << "," << endl
|
||||||
<< " numLeft=" << numLeft << "," << endl
|
<< " numLeft=" << numLeft << "," << endl
|
||||||
<< " numRight=" << numRight << "," << endl
|
<< " numRight=" << numRight << "," << endl
|
||||||
|
<< " leftBin=" << leftBin << "," << endl
|
||||||
<< " planarLeft=" << (planarLeft ? "yes" : "no") << endl
|
<< " planarLeft=" << (planarLeft ? "yes" : "no") << endl
|
||||||
<< "]";
|
<< "]";
|
||||||
return oss.str();
|
return oss.str();
|
||||||
|
@ -1561,7 +1562,8 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int axis=0; axis<PointType::dim; ++axis) {
|
for (int axis=0; axis<PointType::dim; ++axis) {
|
||||||
float min = (float) aabb.min[axis], max = (float) aabb.max[axis];
|
float min = math::castflt_down(aabb.min[axis]),
|
||||||
|
max = math::castflt_up(aabb.max[axis]);
|
||||||
|
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
*eventEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, axis,
|
*eventEnd++ = EdgeEvent(EdgeEvent::EEdgePlanar, axis,
|
||||||
|
@ -2198,21 +2200,6 @@ protected:
|
||||||
*newEventsLeftEnd = newEventsLeftStart,
|
*newEventsLeftEnd = newEventsLeftStart,
|
||||||
*newEventsRightEnd = newEventsRightStart;
|
*newEventsRightEnd = newEventsRightStart;
|
||||||
|
|
||||||
AABBType leftNodeAABB_enlarged(leftNodeAABB),
|
|
||||||
rightNodeAABB_enlarged(rightNodeAABB);
|
|
||||||
|
|
||||||
#if defined(DOUBLE_PRECISION)
|
|
||||||
int axis0 = (bestSplit.axis + 1)%3, axis1 = (bestSplit.axis + 2)%3;
|
|
||||||
leftNodeAABB_enlarged.min[axis0] = rightNodeAABB_enlarged.min[axis0] =
|
|
||||||
nextafterf((float) nodeAABB.min[axis0], -std::numeric_limits<float>::max());
|
|
||||||
leftNodeAABB_enlarged.max[axis0] = rightNodeAABB_enlarged.max[axis0] =
|
|
||||||
nextafterf((float) nodeAABB.max[axis0], std::numeric_limits<float>::max());
|
|
||||||
leftNodeAABB_enlarged.min[axis1] = rightNodeAABB_enlarged.min[axis1] =
|
|
||||||
nextafterf((float) nodeAABB.min[axis1], -std::numeric_limits<float>::max());
|
|
||||||
leftNodeAABB_enlarged.max[axis1] = rightNodeAABB_enlarged.max[axis1] =
|
|
||||||
nextafterf((float) nodeAABB.max[axis1], std::numeric_limits<float>::max());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (EdgeEvent *event = eventStart; event<eventEnd; ++event) {
|
for (EdgeEvent *event = eventStart; event<eventEnd; ++event) {
|
||||||
int classification = storage.get(event->index);
|
int classification = storage.get(event->index);
|
||||||
|
|
||||||
|
@ -2227,16 +2214,16 @@ protected:
|
||||||
generate new events for each side */
|
generate new events for each side */
|
||||||
const IndexType index = event->index;
|
const IndexType index = event->index;
|
||||||
|
|
||||||
AABBType clippedLeft = cast()->getClippedAABB(index, leftNodeAABB_enlarged);
|
AABBType clippedLeft = cast()->getClippedAABB(index, leftNodeAABB);
|
||||||
AABBType clippedRight = cast()->getClippedAABB(index, rightNodeAABB_enlarged);
|
AABBType clippedRight = cast()->getClippedAABB(index, rightNodeAABB);
|
||||||
|
|
||||||
KDAssert(leftNodeAABB_enlarged.contains(clippedLeft));
|
KDAssert(leftNodeAABB.contains(clippedLeft));
|
||||||
KDAssert(rightNodeAABB_enlarged.contains(clippedRight));
|
KDAssert(rightNodeAABB.contains(clippedRight));
|
||||||
|
|
||||||
if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) {
|
if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) {
|
||||||
for (int axis=0; axis<PointType::dim; ++axis) {
|
for (int axis=0; axis<PointType::dim; ++axis) {
|
||||||
float min = (float) clippedLeft.min[axis],
|
float min = clippedLeft.min[axis],
|
||||||
max = (float) clippedLeft.max[axis];
|
max = clippedLeft.max[axis];
|
||||||
|
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
*newEventsLeftEnd++ = EdgeEvent(
|
*newEventsLeftEnd++ = EdgeEvent(
|
||||||
|
@ -2257,8 +2244,8 @@ protected:
|
||||||
|
|
||||||
if (clippedRight.isValid() && clippedRight.getSurfaceArea() > 0) {
|
if (clippedRight.isValid() && clippedRight.getSurfaceArea() > 0) {
|
||||||
for (int axis=0; axis<PointType::dim; ++axis) {
|
for (int axis=0; axis<PointType::dim; ++axis) {
|
||||||
float min = (float) clippedRight.min[axis],
|
float min = clippedRight.min[axis],
|
||||||
max = (float) clippedRight.max[axis];
|
max = clippedRight.max[axis];
|
||||||
|
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
*newEventsRightEnd++ = EdgeEvent(
|
*newEventsRightEnd++ = EdgeEvent(
|
||||||
|
@ -2425,10 +2412,20 @@ protected:
|
||||||
* \brief Prepare to bin for the specified bounds
|
* \brief Prepare to bin for the specified bounds
|
||||||
*/
|
*/
|
||||||
void setAABB(const AABBType &aabb) {
|
void setAABB(const AABBType &aabb) {
|
||||||
m_aabb = aabb;
|
for (int axis=0; axis<PointType::dim; ++axis) {
|
||||||
m_binSize = m_aabb.getExtents() / (Float) m_binCount;
|
float min = math::castflt_down(aabb.min[axis]);
|
||||||
for (int axis=0; axis<PointType::dim; ++axis)
|
float max = math::castflt_up(aabb.max[axis]);
|
||||||
m_invBinSize[axis] = 1/m_binSize[axis];
|
m_min[axis] = min;
|
||||||
|
m_aabb.min[axis] = min;
|
||||||
|
m_aabb.max[axis] = max;
|
||||||
|
m_binSize[axis] = (max-min) / m_binCount;
|
||||||
|
m_invBinSize[axis] = 1 / m_binSize[axis];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the bin location for a given position and axis
|
||||||
|
inline IndexType computeIndex(float pos, int axis) {
|
||||||
|
return (IndexType) std::min((float) (m_binCount-1), std::max(0.0f, (pos - m_min[axis]) * m_invBinSize[axis]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2444,19 +2441,12 @@ protected:
|
||||||
m_primCount = primCount;
|
m_primCount = primCount;
|
||||||
memset(m_minBins, 0, sizeof(SizeType) * PointType::dim * m_binCount);
|
memset(m_minBins, 0, sizeof(SizeType) * PointType::dim * m_binCount);
|
||||||
memset(m_maxBins, 0, sizeof(SizeType) * PointType::dim * m_binCount);
|
memset(m_maxBins, 0, sizeof(SizeType) * PointType::dim * m_binCount);
|
||||||
const int64_t maxBin = m_binCount-1;
|
|
||||||
|
|
||||||
for (SizeType i=0; i<m_primCount; ++i) {
|
for (SizeType i=0; i<m_primCount; ++i) {
|
||||||
const AABBType aabb = derived->getAABB(indices[i]);
|
const AABBType aabb = derived->getAABB(indices[i]);
|
||||||
for (int axis=0; axis<PointType::dim; ++axis) {
|
for (int axis=0; axis<PointType::dim; ++axis) {
|
||||||
int64_t minIdx = (int64_t) (((float) aabb.min[axis] - (float) m_aabb.min[axis])
|
m_minBins[axis * m_binCount + computeIndex(math::castflt_down(aabb.min[axis]), axis)]++;
|
||||||
* m_invBinSize[axis]);
|
m_maxBins[axis * m_binCount + computeIndex(math::castflt_up (aabb.max[axis]), axis)]++;
|
||||||
int64_t maxIdx = (int64_t) (((float) aabb.max[axis] - (float) m_aabb.min[axis])
|
|
||||||
* m_invBinSize[axis]);
|
|
||||||
m_maxBins[axis * m_binCount
|
|
||||||
+ std::max((int64_t) 0, std::min(maxIdx, maxBin))]++;
|
|
||||||
m_minBins[axis * m_binCount
|
|
||||||
+ std::max((int64_t) 0, std::min(minIdx, maxBin))]++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2468,15 +2458,14 @@ protected:
|
||||||
* splits.
|
* splits.
|
||||||
*/
|
*/
|
||||||
SplitCandidate minimizeCost(Float traversalCost, Float queryCost) {
|
SplitCandidate minimizeCost(Float traversalCost, Float queryCost) {
|
||||||
SplitCandidate candidate;
|
|
||||||
int binIdx = 0, leftBin = 0;
|
|
||||||
TreeConstructionHeuristic tch(m_aabb);
|
TreeConstructionHeuristic tch(m_aabb);
|
||||||
|
SplitCandidate candidate;
|
||||||
|
int binIdx = 0;
|
||||||
|
|
||||||
for (int axis=0; axis<PointType::dim; ++axis) {
|
for (int axis=0; axis<PointType::dim; ++axis) {
|
||||||
VectorType extents = m_aabb.getExtents();
|
|
||||||
SizeType numLeft = 0, numRight = m_primCount;
|
SizeType numLeft = 0, numRight = m_primCount;
|
||||||
Float leftWidth = 0, rightWidth = extents[axis];
|
Float leftWidth = 0, rightWidth = m_aabb.max[axis] - m_aabb.min[axis];
|
||||||
const Float binSize = m_binSize[axis];
|
const float binSize = m_binSize[axis];
|
||||||
|
|
||||||
for (int i=0; i<m_binCount-1; ++i) {
|
for (int i=0; i<m_binCount-1; ++i) {
|
||||||
numLeft += m_minBins[binIdx];
|
numLeft += m_minBins[binIdx];
|
||||||
|
@ -2494,7 +2483,7 @@ protected:
|
||||||
candidate.axis = axis;
|
candidate.axis = axis;
|
||||||
candidate.numLeft = numLeft;
|
candidate.numLeft = numLeft;
|
||||||
candidate.numRight = numRight;
|
candidate.numRight = numRight;
|
||||||
leftBin = i;
|
candidate.leftBin = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
binIdx++;
|
binIdx++;
|
||||||
|
@ -2502,73 +2491,8 @@ protected:
|
||||||
binIdx++;
|
binIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
KDAssert(candidate.cost != std::numeric_limits<Float>::infinity());
|
KDAssert(candidate.cost != std::numeric_limits<Float>::infinity() &&
|
||||||
|
candidate.leftBin >= 0);
|
||||||
const int axis = candidate.axis;
|
|
||||||
const Float min = m_aabb.min[axis];
|
|
||||||
|
|
||||||
/* The following part may seem a bit paranoid. It is ensures that the
|
|
||||||
* returned split plane is consistent with the floating point calculations
|
|
||||||
* done by the binning code in \ref bin(). Since reciprocals and
|
|
||||||
* various floating point roundoff errors are involved, simply setting
|
|
||||||
*
|
|
||||||
* candidate.pos = m_aabb.min[axis] + (leftBin+1) * m_binSize[axis];
|
|
||||||
*
|
|
||||||
* can potentially lead to a slightly different number primitives being
|
|
||||||
* classified to the left and right if we were to do check each
|
|
||||||
* primitive against this split position. We can't have that, however,
|
|
||||||
* since the partitioning code assumes that these numbers are correct.
|
|
||||||
* This lets it avoid doing another costly sweep, hence all the
|
|
||||||
* floating point madness below.
|
|
||||||
*/
|
|
||||||
Float invBinSize = m_invBinSize[axis];
|
|
||||||
float split = (float) (min + (leftBin + 1) * m_binSize[axis]);
|
|
||||||
float splitNext = nextafterf(split,
|
|
||||||
std::numeric_limits<float>::max());
|
|
||||||
int idx = (int) ((split - min) * invBinSize);
|
|
||||||
int idxNext = (int) ((splitNext - min) * invBinSize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The split plane should pass through the last discrete floating
|
|
||||||
* floating value, which would still be classified into
|
|
||||||
* the left bin. If this is not computed correctly, do binary
|
|
||||||
* search.
|
|
||||||
*/
|
|
||||||
if (!(idx == leftBin && idxNext == leftBin+1)) {
|
|
||||||
float left = (float) m_aabb.min[axis];
|
|
||||||
float right = (float) m_aabb.max[axis];
|
|
||||||
int it = 0;
|
|
||||||
while (true) {
|
|
||||||
split = left + (right-left)/2;
|
|
||||||
splitNext = nextafterf(split,
|
|
||||||
std::numeric_limits<float>::max());
|
|
||||||
idx = (int) ((split - min) * invBinSize);
|
|
||||||
idxNext = (int) ((splitNext - min) * invBinSize);
|
|
||||||
|
|
||||||
if (idx == leftBin && idxNext == leftBin+1) {
|
|
||||||
/* Got it! */
|
|
||||||
break;
|
|
||||||
} else if (std::abs(idx-idxNext) > 1 || ++it > 50) {
|
|
||||||
/* Insufficient floating point resolution
|
|
||||||
-> a leaf will be created. */
|
|
||||||
candidate.cost = std::numeric_limits<Float>::infinity();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx <= leftBin)
|
|
||||||
left = split;
|
|
||||||
else
|
|
||||||
right = split;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split <= m_aabb.min[axis] || split >= m_aabb.max[axis]) {
|
|
||||||
/* Insufficient floating point resolution
|
|
||||||
-> a leaf will be created. */
|
|
||||||
candidate.cost = std::numeric_limits<Float>::infinity();
|
|
||||||
}
|
|
||||||
|
|
||||||
candidate.pos = split;
|
|
||||||
|
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
@ -2594,10 +2518,9 @@ protected:
|
||||||
BuildContext &ctx, const Derived *derived, IndexType *primIndices,
|
BuildContext &ctx, const Derived *derived, IndexType *primIndices,
|
||||||
SplitCandidate &split, bool isLeftChild, Float traversalCost,
|
SplitCandidate &split, bool isLeftChild, Float traversalCost,
|
||||||
Float queryCost) {
|
Float queryCost) {
|
||||||
const float splitPos = split.pos;
|
|
||||||
const int axis = split.axis;
|
|
||||||
SizeType numLeft = 0, numRight = 0;
|
SizeType numLeft = 0, numRight = 0;
|
||||||
AABBType leftBounds, rightBounds;
|
AABBType leftBounds, rightBounds;
|
||||||
|
const int axis = split.axis;
|
||||||
|
|
||||||
IndexType *leftIndices, *rightIndices;
|
IndexType *leftIndices, *rightIndices;
|
||||||
if (isLeftChild) {
|
if (isLeftChild) {
|
||||||
|
@ -2613,12 +2536,14 @@ protected:
|
||||||
for (SizeType i=0; i<m_primCount; ++i) {
|
for (SizeType i=0; i<m_primCount; ++i) {
|
||||||
const IndexType primIndex = primIndices[i];
|
const IndexType primIndex = primIndices[i];
|
||||||
const AABBType aabb = derived->getAABB(primIndex);
|
const AABBType aabb = derived->getAABB(primIndex);
|
||||||
|
int startIdx = computeIndex(math::castflt_down(aabb.min[axis]), axis);
|
||||||
|
int endIdx = computeIndex(math::castflt_up (aabb.max[axis]), axis);
|
||||||
|
|
||||||
if (aabb.max[axis] <= splitPos) {
|
if (endIdx <= split.leftBin) {
|
||||||
KDAssert(numLeft < split.numLeft);
|
KDAssert(numLeft < split.numLeft);
|
||||||
leftBounds.expandBy(aabb);
|
leftBounds.expandBy(aabb);
|
||||||
leftIndices[numLeft++] = primIndex;
|
leftIndices[numLeft++] = primIndex;
|
||||||
} else if (aabb.min[axis] > splitPos) {
|
} else if (startIdx > split.leftBin) {
|
||||||
KDAssert(numRight < split.numRight);
|
KDAssert(numRight < split.numRight);
|
||||||
rightBounds.expandBy(aabb);
|
rightBounds.expandBy(aabb);
|
||||||
rightIndices[numRight++] = primIndex;
|
rightIndices[numRight++] = primIndex;
|
||||||
|
@ -2631,9 +2556,11 @@ protected:
|
||||||
rightIndices[numRight++] = primIndex;
|
rightIndices[numRight++] = primIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
leftBounds.clip(m_aabb);
|
leftBounds.clip(m_aabb);
|
||||||
rightBounds.clip(m_aabb);
|
rightBounds.clip(m_aabb);
|
||||||
|
split.pos = m_min[axis] + m_binSize[axis] * (split.leftBin + 1);
|
||||||
|
leftBounds.max[axis] = std::min(leftBounds.max[axis], (Float) split.pos);
|
||||||
|
rightBounds.min[axis] = std::max(rightBounds.min[axis], (Float) split.pos);
|
||||||
|
|
||||||
KDAssert(numLeft == split.numLeft);
|
KDAssert(numLeft == split.numLeft);
|
||||||
KDAssert(numRight == split.numRight);
|
KDAssert(numRight == split.numRight);
|
||||||
|
@ -2644,40 +2571,6 @@ protected:
|
||||||
else
|
else
|
||||||
ctx.rightAlloc.shrinkAllocation(rightIndices, split.numRight);
|
ctx.rightAlloc.shrinkAllocation(rightIndices, split.numRight);
|
||||||
|
|
||||||
leftBounds.max[axis] = std::min(leftBounds.max[axis], (Float) splitPos);
|
|
||||||
rightBounds.min[axis] = std::max(rightBounds.min[axis], (Float) splitPos);
|
|
||||||
|
|
||||||
if (leftBounds.max[axis] != rightBounds.min[axis]) {
|
|
||||||
/* There is some space between the child nodes -- move
|
|
||||||
the split plane onto one of the AABBs so that the
|
|
||||||
heuristic cost is minimized */
|
|
||||||
TreeConstructionHeuristic tch(m_aabb);
|
|
||||||
|
|
||||||
std::pair<Float, Float> prob1 = tch(axis,
|
|
||||||
leftBounds.max[axis] - m_aabb.min[axis],
|
|
||||||
m_aabb.max[axis] - leftBounds.max[axis]);
|
|
||||||
std::pair<Float, Float> prob2 = tch(axis,
|
|
||||||
rightBounds.min[axis] - m_aabb.min[axis],
|
|
||||||
m_aabb.max[axis] - rightBounds.min[axis]);
|
|
||||||
Float cost1 = traversalCost + queryCost
|
|
||||||
* (prob1.first * numLeft + prob1.second * numRight);
|
|
||||||
Float cost2 = traversalCost + queryCost
|
|
||||||
* (prob2.first * numLeft + prob2.second * numRight);
|
|
||||||
|
|
||||||
if (cost1 <= cost2) {
|
|
||||||
split.cost = cost1;
|
|
||||||
split.pos = (float) leftBounds.max[axis];
|
|
||||||
} else {
|
|
||||||
split.cost = cost2;
|
|
||||||
split.pos = (float) rightBounds.min[axis];
|
|
||||||
}
|
|
||||||
|
|
||||||
leftBounds.max[axis] = std::min(leftBounds.max[axis],
|
|
||||||
(Float) split.pos);
|
|
||||||
rightBounds.min[axis] = std::max(rightBounds.min[axis],
|
|
||||||
(Float) split.pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Partition(leftBounds, leftIndices,
|
return Partition(leftBounds, leftIndices,
|
||||||
rightBounds, rightIndices);
|
rightBounds, rightIndices);
|
||||||
}
|
}
|
||||||
|
@ -2686,9 +2579,10 @@ protected:
|
||||||
SizeType *m_maxBins;
|
SizeType *m_maxBins;
|
||||||
SizeType m_primCount;
|
SizeType m_primCount;
|
||||||
int m_binCount;
|
int m_binCount;
|
||||||
|
float m_min[PointType::dim];
|
||||||
|
float m_binSize[PointType::dim];
|
||||||
|
float m_invBinSize[PointType::dim];
|
||||||
AABBType m_aabb;
|
AABBType m_aabb;
|
||||||
VectorType m_binSize;
|
|
||||||
VectorType m_invBinSize;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -135,7 +135,7 @@ if (APPLE)
|
||||||
list(APPEND SRCS platform_darwin.mm)
|
list(APPEND SRCS platform_darwin.mm)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
list(APPEND HDRS ${INCLUDE_DIR}/getopt.h)
|
list(APPEND HDRS ${INCLUDE_DIR}/getopt.h)
|
||||||
list(APPEND SRCS getopt.c platform_win32.cpp)
|
list(APPEND SRCS getopt.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
|
|
@ -55,7 +55,6 @@ if sys.platform == 'darwin':
|
||||||
libcore_objects += coreEnv_osx.SharedObject('platform_darwin.mm')
|
libcore_objects += coreEnv_osx.SharedObject('platform_darwin.mm')
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
libcore_objects += coreEnv.SharedObject('getopt.c')
|
libcore_objects += coreEnv.SharedObject('getopt.c')
|
||||||
libcore_objects += coreEnv.SharedObject('platform_win32.cpp')
|
|
||||||
|
|
||||||
libcore = coreEnv.SharedLibrary('mitsuba-core', libcore_objects)
|
libcore = coreEnv.SharedLibrary('mitsuba-core', libcore_objects)
|
||||||
|
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
/* s_nextafterf.c -- float version of s_nextafter.c.
|
|
||||||
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ====================================================
|
|
||||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
|
||||||
* Permission to use, copy, modify, and distribute this
|
|
||||||
* software is freely granted, provided that this notice
|
|
||||||
* is preserved.
|
|
||||||
* ====================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <mitsuba/mitsuba.h>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
|
||||||
|
|
||||||
/* Use strict IEEE 754 floating point computations
|
|
||||||
for the following code */
|
|
||||||
#pragma float_control(precise, on)
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
float value;
|
|
||||||
uint32_t word;
|
|
||||||
} ieee_float_shape_type;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
double value;
|
|
||||||
struct {
|
|
||||||
uint32_t lsw;
|
|
||||||
uint32_t msw;
|
|
||||||
} parts;
|
|
||||||
} ieee_double_shape_type;
|
|
||||||
|
|
||||||
#define GET_FLOAT_WORD(i,d) \
|
|
||||||
do { \
|
|
||||||
ieee_float_shape_type gf_u; \
|
|
||||||
gf_u.value = (d); \
|
|
||||||
(i) = gf_u.word; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SET_FLOAT_WORD(d,i) \
|
|
||||||
do { \
|
|
||||||
ieee_float_shape_type sf_u; \
|
|
||||||
sf_u.word = (i); \
|
|
||||||
(d) = sf_u.value; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define EXTRACT_WORDS(ix0,ix1,d) \
|
|
||||||
do { \
|
|
||||||
ieee_double_shape_type ew_u; \
|
|
||||||
ew_u.value = (d); \
|
|
||||||
(ix0) = ew_u.parts.msw; \
|
|
||||||
(ix1) = ew_u.parts.lsw; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
#define INSERT_WORDS(d,ix0,ix1) \
|
|
||||||
do { \
|
|
||||||
ieee_double_shape_type iw_u; \
|
|
||||||
iw_u.parts.msw = (ix0); \
|
|
||||||
iw_u.parts.lsw = (ix1); \
|
|
||||||
(d) = iw_u.value; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
float nextafterf(float x, float y) {
|
|
||||||
int32_t hx, hy, ix, iy;
|
|
||||||
|
|
||||||
GET_FLOAT_WORD(hx, x);
|
|
||||||
GET_FLOAT_WORD(hy, y);
|
|
||||||
ix = hx & 0x7fffffff; /* |x| */
|
|
||||||
iy = hy & 0x7fffffff; /* |y| */
|
|
||||||
|
|
||||||
/* x is nan or y is nan? */
|
|
||||||
if ((ix > 0x7f800000) || (iy > 0x7f800000))
|
|
||||||
return x + y;
|
|
||||||
|
|
||||||
if (x == y)
|
|
||||||
return y;
|
|
||||||
|
|
||||||
if (ix == 0) { /* x == 0? */
|
|
||||||
SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hx >= 0) { /* x > 0 */
|
|
||||||
if (hx > hy) { /* x > y: x -= ulp */
|
|
||||||
hx -= 1;
|
|
||||||
} else { /* x < y: x += ulp */
|
|
||||||
hx += 1;
|
|
||||||
}
|
|
||||||
} else { /* x < 0 */
|
|
||||||
if (hy >= 0 || hx > hy) { /* x < y: x -= ulp */
|
|
||||||
hx -= 1;
|
|
||||||
} else { /* x > y: x += ulp */
|
|
||||||
hx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hy = hx & 0x7f800000;
|
|
||||||
if (hy >= 0x7f800000) {
|
|
||||||
x = x + x; /* overflow */
|
|
||||||
return x; /* overflow */
|
|
||||||
}
|
|
||||||
SET_FLOAT_WORD(x, hx);
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
double nextafter(double x, double y) {
|
|
||||||
int32_t hx,hy,ix,iy;
|
|
||||||
uint32_t lx,ly;
|
|
||||||
|
|
||||||
EXTRACT_WORDS(hx,lx,x);
|
|
||||||
EXTRACT_WORDS(hy,ly,y);
|
|
||||||
|
|
||||||
ix = hx & 0x7fffffff; /* |x| */
|
|
||||||
iy = hy & 0x7fffffff; /* |y| */
|
|
||||||
|
|
||||||
if (((ix>=0x7ff00000) && ((ix-0x7ff00000)|lx) != 0) || /* x is nan */
|
|
||||||
((iy>=0x7ff00000) && ((iy-0x7ff00000)|ly) != 0)) /* y is nan */
|
|
||||||
return x+y;
|
|
||||||
|
|
||||||
if (x==y)
|
|
||||||
return x; /* x=y, return x */
|
|
||||||
|
|
||||||
if ((ix|lx) == 0) { /* x == 0 */
|
|
||||||
INSERT_WORDS(x,hy & 0x80000000,1); /* return +-minsubnormal */
|
|
||||||
y = x*x;
|
|
||||||
if (y==x)
|
|
||||||
return y;
|
|
||||||
else
|
|
||||||
return x; /* raise underflow flag */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hx>=0) { /* x > 0 */
|
|
||||||
if (hx>hy || ((hx==hy) && (lx>ly))) { /* x > y, x -= ulp */
|
|
||||||
if (lx==0)
|
|
||||||
hx -= 1;
|
|
||||||
lx -= 1;
|
|
||||||
} else { /* x < y, x += ulp */
|
|
||||||
lx += 1;
|
|
||||||
if (lx==0)
|
|
||||||
hx += 1;
|
|
||||||
}
|
|
||||||
} else { /* x < 0 */
|
|
||||||
if (hy>=0 || hx>hy || ((hx==hy) && (lx>ly))) { /* x < y, x -= ulp */
|
|
||||||
if (lx==0)
|
|
||||||
hx -= 1;
|
|
||||||
lx -= 1;
|
|
||||||
} else { /* x > y, x += ulp */
|
|
||||||
lx += 1;
|
|
||||||
if (lx==0)
|
|
||||||
hx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hy = hx & 0x7ff00000;
|
|
||||||
|
|
||||||
if (hy >= 0x7ff00000)
|
|
||||||
return x+x; /* overflow */
|
|
||||||
|
|
||||||
if (hy < 0x00100000) { /* underflow */
|
|
||||||
y = x*x;
|
|
||||||
if (y!=x) {
|
|
||||||
/* raise underflow flag */
|
|
||||||
INSERT_WORDS(y,hx,lx);
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INSERT_WORDS(x,hx,lx);
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -136,28 +136,9 @@ AABB Triangle::getClippedAABB(const Point *positions, const AABB &aabb) const {
|
||||||
AABB result;
|
AABB result;
|
||||||
for (int i=0; i<nVertices; ++i) {
|
for (int i=0; i<nVertices; ++i) {
|
||||||
for (int j=0; j<3; ++j) {
|
for (int j=0; j<3; ++j) {
|
||||||
/* Now this is really paranoid! */
|
double pos = vertices1[i][j];
|
||||||
double pos_d = vertices1[i][j];
|
result.min[j] = std::min(result.min[j], (Float) math::castflt_down(pos));
|
||||||
float pos_f = (float) pos_d;
|
result.max[j] = std::max(result.max[j], (Float) math::castflt_up(pos));
|
||||||
Float pos_roundedDown, pos_roundedUp;
|
|
||||||
|
|
||||||
if (pos_f < pos_d) {
|
|
||||||
/* Float value is too small */
|
|
||||||
pos_roundedDown = pos_f;
|
|
||||||
pos_roundedUp = nextafterf(pos_f,
|
|
||||||
std::numeric_limits<float>::infinity());
|
|
||||||
} else if (pos_f > pos_d) {
|
|
||||||
/* Float value is too large */
|
|
||||||
pos_roundedUp = pos_f;
|
|
||||||
pos_roundedDown = nextafterf(pos_f,
|
|
||||||
-std::numeric_limits<float>::infinity());
|
|
||||||
} else {
|
|
||||||
/* Double value is exactly representable */
|
|
||||||
pos_roundedDown = pos_roundedUp = pos_f;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.min[j] = std::min(result.min[j], pos_roundedDown);
|
|
||||||
result.max[j] = std::max(result.max[j], pos_roundedUp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.clip(aabb);
|
result.clip(aabb);
|
||||||
|
|
Loading…
Reference in New Issue