cleanups
parent
57c329d646
commit
c74924fb7a
|
@ -830,9 +830,10 @@ protected:
|
|||
const size_type primBucketCount = 16;
|
||||
size_type primBuckets[primBucketCount];
|
||||
memset(primBuckets, 0, sizeof(size_type)*primBucketCount);
|
||||
m_nodeCount = ctx.innerNodeCount + ctx.leafNodeCount;
|
||||
|
||||
m_nodes = static_cast<KDNode *> (allocAligned(
|
||||
sizeof(KDNode) * (ctx.innerNodeCount + ctx.leafNodeCount)));
|
||||
sizeof(KDNode) * m_nodeCount));
|
||||
m_indices = new index_type[ctx.primIndexCount];
|
||||
|
||||
stack.push(boost::make_tuple(prelimRoot, &m_nodes[nodePtr++], &ctx, m_aabb));
|
||||
|
@ -2618,123 +2619,6 @@ protected:
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Internal kd-tree traversal implementation (Havran variant)
|
||||
*
|
||||
* This method is almost identical to \ref rayIntersectHavran, except
|
||||
* that it forwards all ray-leaf intersections to a specified handler.
|
||||
*/
|
||||
template<typename LeafHandler> FINLINE
|
||||
bool rayIntersectHavranCustom(const LeafHandler &leafHandler,
|
||||
const Ray &ray, Float mint, Float maxt,
|
||||
Float &t, void *temp) const {
|
||||
KDStackEntryHavran stack[MTS_KD_MAXDEPTH];
|
||||
#if 0
|
||||
static const int prevAxisTable[] = { 2, 0, 1 };
|
||||
static const int nextAxisTable[] = { 1, 2, 0 };
|
||||
#endif
|
||||
|
||||
/* Set up the entry point */
|
||||
uint32_t enPt = 0;
|
||||
stack[enPt].t = mint;
|
||||
stack[enPt].p = ray(mint);
|
||||
|
||||
/* Set up the exit point */
|
||||
uint32_t exPt = 1;
|
||||
stack[exPt].t = maxt;
|
||||
stack[exPt].p = ray(maxt);
|
||||
stack[exPt].node = NULL;
|
||||
|
||||
const KDNode * __restrict currNode = m_nodes;
|
||||
while (currNode != NULL) {
|
||||
while (EXPECT_TAKEN(!currNode->isLeaf())) {
|
||||
const Float splitVal = (Float) currNode->getSplit();
|
||||
const int axis = currNode->getAxis();
|
||||
const KDNode * __restrict farChild;
|
||||
|
||||
if (stack[enPt].p[axis] <= splitVal) {
|
||||
if (stack[exPt].p[axis] <= splitVal) {
|
||||
/* Cases N1, N2, N3, P5, Z2 and Z3 (see thesis) */
|
||||
currNode = currNode->getLeft();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Typo in Havran's thesis:
|
||||
(it specifies "stack[exPt].p == splitVal", which
|
||||
is clearly incorrect) */
|
||||
if (stack[enPt].p[axis] == splitVal) {
|
||||
/* Case Z1 */
|
||||
currNode = currNode->getRight();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Case N4 */
|
||||
currNode = currNode->getLeft();
|
||||
farChild = currNode + 1; // getRight()
|
||||
} else { /* stack[enPt].p[axis] > splitVal */
|
||||
if (splitVal < stack[exPt].p[axis]) {
|
||||
/* Cases P1, P2, P3 and N5 */
|
||||
currNode = currNode->getRight();
|
||||
continue;
|
||||
}
|
||||
/* Case P4 */
|
||||
farChild = currNode->getLeft();
|
||||
currNode = farChild + 1; // getRight()
|
||||
}
|
||||
|
||||
/* Cases P4 and N4 -- calculate the distance to the split plane */
|
||||
t = (splitVal - ray.o[axis]) * ray.dRcp[axis];
|
||||
|
||||
/* Set up a new exit point */
|
||||
const uint32_t tmp = exPt++;
|
||||
if (exPt == enPt) /* Do not overwrite the entry point */
|
||||
++exPt;
|
||||
|
||||
KDAssert(exPt < MTS_KD_MAX_DEPTH);
|
||||
stack[exPt].prev = tmp;
|
||||
stack[exPt].t = t;
|
||||
stack[exPt].node = farChild;
|
||||
|
||||
#if 1
|
||||
/* Faster than the original code with the
|
||||
prevAxis & nextAxis table */
|
||||
stack[exPt].p = ray(t);
|
||||
#else
|
||||
const int nextAxis = nextAxisTable[axis];
|
||||
const int prevAxis = prevAxisTable[axis];
|
||||
stack[exPt].p[nextAxis] = ray.o[nextAxis] + t*ray.d[nextAxis];
|
||||
stack[exPt].p[prevAxis] = ray.o[prevAxis] + t*ray.d[prevAxis];
|
||||
#endif
|
||||
|
||||
stack[exPt].p[axis] = splitVal;
|
||||
}
|
||||
/* Reached a leaf node */
|
||||
|
||||
/* Floating-point arithmetic.. - use both absolute and relative
|
||||
epsilons when looking for intersections in the subinterval */
|
||||
#if defined(SINGLE_PRECISION)
|
||||
const Float eps = 1e-3;
|
||||
#else
|
||||
const Float eps = 1e-5;
|
||||
#endif
|
||||
const Float m_eps = 1-eps, p_eps = 1+eps;
|
||||
|
||||
const Float searchStart = std::max(mint, stack[enPt].t * m_eps - eps);
|
||||
Float searchEnd = std::min(maxt, stack[exPt].t * p_eps + eps);
|
||||
|
||||
if (leafHandler(currNode, ray, searchStart, searchEnd, t, temp))
|
||||
return true;
|
||||
|
||||
/* Pop from the stack and advance to the next node on the interval */
|
||||
enPt = exPt;
|
||||
currNode = stack[exPt].node;
|
||||
exPt = stack[enPt].prev;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Internal kd-tree traversal implementation (Havran variant)
|
||||
*
|
||||
|
@ -2968,6 +2852,7 @@ protected:
|
|||
size_type m_stopPrims;
|
||||
size_type m_maxBadRefines;
|
||||
size_type m_exactPrimThreshold;
|
||||
size_type m_nodeCount;
|
||||
std::vector<SAHTreeBuilder *> m_builders;
|
||||
std::vector<KDNode *> m_indirections;
|
||||
ref<Mutex> m_indirectionLock;
|
||||
|
|
|
@ -52,7 +52,7 @@ struct TriAccel4 {
|
|||
/// Fast ray-triangle intersection test
|
||||
inline bool rayIntersect(const __m128 o, const __m128 d, float _mint,
|
||||
float _maxt, float *_t, float *_u, float *_v, unsigned int &_shapeIndex,
|
||||
unsigned int &_index);
|
||||
unsigned int &_index) const;
|
||||
};
|
||||
|
||||
FINLINE __m128 TriAccel::rayIntersectPacket(const RayPacket4 &packet,
|
||||
|
@ -188,7 +188,7 @@ inline int TriAccel4::load(const Point *A, const Point *B, const Point *C,
|
|||
|
||||
inline bool TriAccel4::rayIntersect(const __m128 o, const __m128 d, float _mint,
|
||||
float _maxt, float *_t, float *_u, float *_v, unsigned int &_shapeIndex,
|
||||
unsigned int &_index) {
|
||||
unsigned int &_index) const {
|
||||
__m128 o_k, o_u, o_v, d_k, d_u, d_v;
|
||||
/* Arrange the ray according to the projection axes of the
|
||||
four packed triangles. This requires a *good* compiler
|
||||
|
|
|
@ -23,86 +23,84 @@
|
|||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
class TriKDTree : public GenericKDTree<TriKDTree> {
|
||||
friend class GenericKDTree<TriKDTree>;
|
||||
public:
|
||||
TriKDTree(const Triangle *triangles,
|
||||
const Vertex *vertexBuffer,
|
||||
size_type triangleCount)
|
||||
: m_triangles(triangles),
|
||||
m_vertexBuffer(vertexBuffer),
|
||||
m_triangleCount(triangleCount) {
|
||||
TriKDTree() {
|
||||
m_shapeMap.push_back(0);
|
||||
}
|
||||
|
||||
bool rayIntersect(const Ray &ray, Intersection &its) const {
|
||||
uint32_t temp[MTS_KD_INTERSECTION_TEMP];
|
||||
its.t = std::numeric_limits<Float>::infinity();
|
||||
Float mint, maxt;
|
||||
TriAccelHandler handler(m_indices, m_triAccel);
|
||||
|
||||
if (m_aabb.rayIntersect(ray, mint, maxt)) {
|
||||
if (ray.mint > mint) mint = ray.mint;
|
||||
if (ray.maxt < maxt) maxt = ray.maxt;
|
||||
|
||||
if (EXPECT_TAKEN(maxt > mint)) {
|
||||
if (rayIntersectHavranCustom(handler,
|
||||
ray, mint, maxt, its.t, temp)) {
|
||||
fillIntersectionDetails(ray, its.t, temp, its);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
void addShape(const Shape *shape) {
|
||||
Assert(!isBuilt());
|
||||
if (shape->isCompound())
|
||||
Log(EError, "Cannot add compound shapes to a kd-tree - expand them first!");
|
||||
if (shape->getClass()->derivesFrom(TriMesh::m_theClass)) {
|
||||
// Triangle meshes are expanded into individual primitives,
|
||||
// which are visible to the tree construction code. Generic
|
||||
// primitives are only handled by their AABBs
|
||||
m_shapeMap.push_back((size_type)
|
||||
static_cast<const TriMesh *>(shape)->getTriangleCount());
|
||||
m_triangleFlag.push_back(true);
|
||||
} else {
|
||||
m_shapeMap.push_back(1);
|
||||
m_triangleFlag.push_back(false);
|
||||
}
|
||||
return false;
|
||||
m_shapes.push_back(shape);
|
||||
}
|
||||
|
||||
FINLINE AABB getAABB(index_type idx) const {
|
||||
return m_triangles[idx].getAABB(m_vertexBuffer);
|
||||
}
|
||||
|
||||
FINLINE AABB getClippedAABB(index_type idx, const AABB &aabb) const {
|
||||
return m_triangles[idx].getClippedAABB(m_vertexBuffer, aabb);
|
||||
}
|
||||
|
||||
FINLINE size_type getPrimitiveCount() const {
|
||||
return m_triangleCount;
|
||||
}
|
||||
#if 0
|
||||
FINLINE EIntersectionResult intersect(const Ray &ray, index_type idx,
|
||||
Float mint, Float maxt, Float &t, void *tmp) const {
|
||||
Float tempT, tempU, tempV;
|
||||
#if 0
|
||||
if (m_triangles[idx].rayIntersect(m_vertexBuffer, ray, tempU, tempV, tempT)) {
|
||||
if (tempT < mint && tempT > maxt)
|
||||
return ENo;
|
||||
#else
|
||||
if (m_triAccel[idx].rayIntersect(ray, mint, maxt, tempU, tempV, tempT)) {
|
||||
#endif
|
||||
index_type *indexPtr = reinterpret_cast<index_type *>(tmp);
|
||||
Float *floatPtr = reinterpret_cast<Float *>(indexPtr + 1);
|
||||
|
||||
t = tempT;
|
||||
*indexPtr = idx;
|
||||
*floatPtr++ = tempU;
|
||||
*floatPtr++ = tempV;
|
||||
|
||||
return EYes;
|
||||
}
|
||||
return ENo;
|
||||
}
|
||||
#endif
|
||||
|
||||
void build() {
|
||||
buildInternal();
|
||||
Log(EInfo, "Precomputing triangle intersection information (%s)",
|
||||
memString(sizeof(TriAccel)*m_triangleCount).c_str());
|
||||
m_triAccel = static_cast<TriAccel *>(allocAligned(m_triangleCount * sizeof(TriAccel)));
|
||||
for (size_t i=0; i<m_triangleCount; ++i) {
|
||||
const Triangle &tri = m_triangles[i];
|
||||
const Vertex &v0 = m_vertexBuffer[tri.idx[0]];
|
||||
const Vertex &v1 = m_vertexBuffer[tri.idx[1]];
|
||||
const Vertex &v2 = m_vertexBuffer[tri.idx[2]];
|
||||
for (size_t i=1; i<m_shapeMap.size(); ++i)
|
||||
m_shapeMap[i] += m_shapeMap[i-1];
|
||||
|
||||
m_triAccel[i].load(v0.p, v1.p, v2.p);
|
||||
buildInternal();
|
||||
|
||||
ref<Timer> timer = new Timer();
|
||||
size_type primCount = getPrimitiveCount();
|
||||
Log(EDebug, "Precomputing triangle intersection information (%s)",
|
||||
memString(sizeof(TriAccel)*primCount).c_str());
|
||||
m_triAccel = static_cast<TriAccel *>(allocAligned(primCount * sizeof(TriAccel)));
|
||||
|
||||
index_type idx = 0;
|
||||
for (index_type i=0; i<m_shapes.size(); ++i) {
|
||||
const Shape *shape = m_shapes[i];
|
||||
if (m_triangleFlag[i]) {
|
||||
const TriMesh *mesh = static_cast<const TriMesh *>(shape);
|
||||
const Triangle *triangles = mesh->getTriangles();
|
||||
const Vertex *vertexBuffer = mesh->getVertexBuffer();
|
||||
for (index_type j=0; j<mesh->getTriangleCount(); ++j) {
|
||||
const Triangle &tri = triangles[j];
|
||||
const Vertex &v0 = vertexBuffer[tri.idx[0]];
|
||||
const Vertex &v1 = vertexBuffer[tri.idx[1]];
|
||||
const Vertex &v2 = vertexBuffer[tri.idx[2]];
|
||||
m_triAccel[idx].load(v0.p, v1.p, v2.p);
|
||||
m_triAccel[idx].shapeIndex = i;
|
||||
m_triAccel[idx].index = j;
|
||||
++idx;
|
||||
}
|
||||
} else {
|
||||
m_triAccel[idx].shapeIndex = i;
|
||||
m_triAccel[idx].k = KNoTriangleFlag;
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
Log(EDebug, "Done (%i ms)", timer->getMilliseconds());
|
||||
Log(EDebug, "");
|
||||
Assert(idx == primCount);
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Return the shape index corresponding to a primitive index
|
||||
* seen by the generic kd-tree implementation. When this is a triangle
|
||||
* mesh, the \a idx parameter is updated to the triangle index within
|
||||
* the mesh.
|
||||
*/
|
||||
index_type findShape(index_type &idx) const {
|
||||
std::vector<index_type>::const_iterator it = std::lower_bound(
|
||||
m_shapeMap.begin(), m_shapeMap.end(), idx+1) - 1;
|
||||
idx -= *it;
|
||||
return (index_type) (it - m_shapeMap.begin());
|
||||
}
|
||||
|
||||
|
||||
FINLINE void fillIntersectionDetails(const Ray &ray,
|
||||
Float t, const void *tmp, Intersection &its) const {
|
||||
|
@ -133,41 +131,57 @@ public:
|
|||
its.hasUVPartials = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct TriAccelHandler {
|
||||
FINLINE TriAccelHandler(const index_type *indices, const TriAccel *triAccel)
|
||||
: m_indices(indices), m_triAccel(triAccel) { }
|
||||
|
||||
FINLINE bool operator()(const KDNode *node, const Ray &ray, Float searchStart,
|
||||
Float searchEnd, Float &t, void *temp) const {
|
||||
bool foundIntersection = false;
|
||||
for (unsigned int entry=node->getPrimStart(),
|
||||
last = node->getPrimEnd(); entry != last; entry++) {
|
||||
const index_type primIdx = m_indices[entry];
|
||||
Float tempT, tempU, tempV;
|
||||
|
||||
if (m_triAccel[primIdx].rayIntersect(ray, searchStart, searchEnd, tempU, tempV, tempT)) {
|
||||
index_type *indexPtr = reinterpret_cast<index_type *>(temp);
|
||||
Float *floatPtr = reinterpret_cast<Float *>(indexPtr + 1);
|
||||
t = searchEnd = tempT;
|
||||
*indexPtr = primIdx;
|
||||
*floatPtr++ = tempU;
|
||||
*floatPtr++ = tempV;
|
||||
foundIntersection = true;
|
||||
}
|
||||
}
|
||||
return foundIntersection;
|
||||
FINLINE AABB getAABB(index_type idx) const {
|
||||
index_type shapeIdx = findShape(idx);
|
||||
const Shape *shape = m_shapes[shapeIdx];
|
||||
if (m_triangleFlag[shapeIdx]) {
|
||||
const TriMesh *mesh = static_cast<const TriMesh *>(shape);
|
||||
return mesh->getTriangles()[idx].getAABB(mesh->getVertexBuffer());
|
||||
} else {
|
||||
return shape->getAABB();
|
||||
}
|
||||
private:
|
||||
const index_type *m_indices;
|
||||
const TriAccel *m_triAccel;
|
||||
};
|
||||
}
|
||||
|
||||
FINLINE AABB getClippedAABB(index_type idx, const AABB &aabb) const {
|
||||
index_type shapeIdx = findShape(idx);
|
||||
const Shape *shape = m_shapes[shapeIdx];
|
||||
if (m_triangleFlag[shapeIdx]) {
|
||||
const TriMesh *mesh = static_cast<const TriMesh *>(shape);
|
||||
return mesh->getTriangles()[idx].getClippedAABB(mesh->getVertexBuffer(), aabb);
|
||||
} else {
|
||||
return shape->getAABB();
|
||||
}
|
||||
}
|
||||
|
||||
FINLINE size_type getPrimitiveCount() const {
|
||||
return m_shapeMap[m_shapeMap.size()-1];
|
||||
}
|
||||
|
||||
FINLINE EIntersectionResult intersect(const Ray &ray, index_type idx, Float mint,
|
||||
Float maxt, Float &t, void *temp) const {
|
||||
Float tempU, tempV, tempT;
|
||||
if (EXPECT_TAKEN(m_triAccel[idx].k != KNoTriangleFlag)) {
|
||||
const TriAccel &ta = m_triAccel[idx];
|
||||
if (ta.rayIntersect(ray, mint, maxt, tempU, tempV, tempT)) {
|
||||
index_type *indexPtr = reinterpret_cast<index_type *>(temp);
|
||||
Float *floatPtr = reinterpret_cast<Float *>((uint8_t *) indexPtr + 8);
|
||||
t = tempT;
|
||||
*indexPtr++ = ta.shapeIndex;
|
||||
*indexPtr++ = ta.index;
|
||||
*floatPtr++ = tempU;
|
||||
*floatPtr++ = tempV;
|
||||
return EYes;
|
||||
}
|
||||
} else {
|
||||
int shape = m_triAccel[idx].shapeIndex;
|
||||
}
|
||||
return ENo;
|
||||
}
|
||||
private:
|
||||
const Triangle *m_triangles;
|
||||
const Vertex *m_vertexBuffer;
|
||||
std::vector<const Shape *> m_shapes;
|
||||
std::vector<bool> m_triangleFlag;
|
||||
std::vector<index_type> m_shapeMap;
|
||||
TriAccel *m_triAccel;
|
||||
size_type m_triangleCount;
|
||||
};
|
||||
|
||||
|
||||
|
@ -237,8 +251,8 @@ public:
|
|||
ref<TriMesh> mesh = static_cast<TriMesh *> (PluginManager::getInstance()->
|
||||
createObject(TriMesh::m_theClass, bunnyProps));
|
||||
mesh->configure();
|
||||
TriKDTree tree(mesh->getTriangles(),
|
||||
mesh->getVertexBuffer(), mesh->getTriangleCount());
|
||||
TriKDTree tree;
|
||||
tree.addShape(mesh);
|
||||
tree.build();
|
||||
BSphere bsphere(mesh->getBSphere());
|
||||
|
||||
|
@ -249,6 +263,8 @@ public:
|
|||
oldTree->addShape(mesh);
|
||||
oldTree->build();
|
||||
|
||||
bsphere = BSphere(Point(-0.016840, 0.110154, -0.001537), .2f);
|
||||
|
||||
for (int j=0; j<3; ++j) {
|
||||
ref<Random> random = new Random();
|
||||
ref<Timer> timer = new Timer();
|
||||
|
|
Loading…
Reference in New Issue