From c74924fb7a7d814c3e7838d67f31ce2041af59e7 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 13 Oct 2010 03:38:44 +0200 Subject: [PATCH] cleanups --- include/mitsuba/render/gkdtree.h | 121 +------------- include/mitsuba/render/triaccel_sse.h | 4 +- src/tests/test_kd.cpp | 222 ++++++++++++++------------ 3 files changed, 124 insertions(+), 223 deletions(-) diff --git a/include/mitsuba/render/gkdtree.h b/include/mitsuba/render/gkdtree.h index d95ef3e4..c3dcd899 100644 --- a/include/mitsuba/render/gkdtree.h +++ b/include/mitsuba/render/gkdtree.h @@ -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 (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 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 m_builders; std::vector m_indirections; ref m_indirectionLock; diff --git a/include/mitsuba/render/triaccel_sse.h b/include/mitsuba/render/triaccel_sse.h index 5a0638bf..268456a8 100644 --- a/include/mitsuba/render/triaccel_sse.h +++ b/include/mitsuba/render/triaccel_sse.h @@ -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 diff --git a/src/tests/test_kd.cpp b/src/tests/test_kd.cpp index acdbaf9c..6197d799 100644 --- a/src/tests/test_kd.cpp +++ b/src/tests/test_kd.cpp @@ -23,86 +23,84 @@ MTS_NAMESPACE_BEGIN class TriKDTree : public GenericKDTree { + friend class GenericKDTree; 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::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(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(tmp); - Float *floatPtr = reinterpret_cast(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(allocAligned(m_triangleCount * sizeof(TriAccel))); - for (size_t i=0; i timer = new Timer(); + size_type primCount = getPrimitiveCount(); + Log(EDebug, "Precomputing triangle intersection information (%s)", + memString(sizeof(TriAccel)*primCount).c_str()); + m_triAccel = static_cast(allocAligned(primCount * sizeof(TriAccel))); + + index_type idx = 0; + for (index_type i=0; i(shape); + const Triangle *triangles = mesh->getTriangles(); + const Vertex *vertexBuffer = mesh->getVertexBuffer(); + for (index_type j=0; jgetTriangleCount(); ++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::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(temp); - Float *floatPtr = reinterpret_cast(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(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(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(temp); + Float *floatPtr = reinterpret_cast((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 m_shapes; + std::vector m_triangleFlag; + std::vector m_shapeMap; TriAccel *m_triAccel; - size_type m_triangleCount; }; @@ -237,8 +251,8 @@ public: ref mesh = static_cast (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 = new Random(); ref timer = new Timer();