metadata
Wenzel Jakob 2010-10-13 03:38:44 +02:00
parent 57c329d646
commit c74924fb7a
3 changed files with 124 additions and 223 deletions

View File

@ -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;

View File

@ -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

View File

@ -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();