diff -r 4d192e13ee84 -r f4fcabf05785 src/kdtree.cc --- a/src/kdtree.cc Fri Nov 23 16:14:38 2007 +0100 +++ b/src/kdtree.cc Sat Nov 24 21:55:41 2007 +0100 @@ -1,7 +1,63 @@ #include +#include #include "kdtree.h" +class SortableShape +{ +public: + Shape *shape; + BBox bbox; + short axis; + short mark; + + SortableShape(Shape *aShape, short &aAxis): shape(aShape), axis(aAxis), mark(0) + { bbox = shape->get_bbox(); }; + friend bool operator<(const SortableShape& a, const SortableShape& b) + { return a.bbox.L.cell[a.axis] < b.bbox.L.cell[b.axis]; }; + void setAxis(short aAxis) { axis = aAxis; }; + void setMark() { mark = 1; }; + short hasMark() { return mark; }; +}; + +class SortableShapeList: public vector +{ +public: + SortableShapeList(ShapeList &shapes, short axis) + { + ShapeList::iterator shape; + for (shape = shapes.begin(); shape != shapes.end(); shape++) + push_back(SortableShape(*shape, axis)); + }; +}; + +class SplitPos +{ +public: + float pos; + int lnum, rnum; + SplitPos(): pos(0.0), lnum(0), rnum(0) {}; + SplitPos(float &aPos): pos(aPos), lnum(0), rnum(0) {}; + friend bool operator<(const SplitPos& a, const SplitPos& b) + { return a.pos < b.pos; }; + friend bool operator==(const SplitPos& a, const SplitPos& b) + { return a.pos == b.pos; }; +}; + +class SplitList: public vector +{ +}; + +// stack element for kd-tree traversal +struct StackElem +{ + KdNode* node; /* pointer to far child */ + float t; /* the entry/exit signed distance */ + Vector3 pb; /* the coordinates of entry/exit point */ +}; + +// ---------------------------------------- + void Container::addShape(Shape* aShape) { shapes.push_back(aShape); @@ -238,6 +294,132 @@ built = true; } +/* algorithm by Vlastimil Havran, Heuristic Ray Shooting Algorithms, appendix C */ +Shape *KdTree::nearest_intersection(const Shape *origin_shape, const Ray &ray, + float &nearest_distance) +{ + float a, b; /* entry/exit signed distance */ + float t; /* signed distance to the splitting plane */ + + /* if we have no tree, fall back to naive test */ + if (!built) + return Container::nearest_intersection(origin_shape, ray, nearest_distance); + + if (!bbox.intersect(ray, a, b)) + return NULL; + + stack st; + + /* pointers to the far child node and current node */ + KdNode *farchild, *node; + node = root; /* start from the kd-tree root node */ + + StackElem *enPt = new StackElem(); + enPt->t = a; /* set the signed distance */ + enPt->node = NULL; + + /* distinguish between internal and external origin */ + if (a >= 0.0) /* a ray with external origin */ + enPt->pb = ray.a + ray.dir * a; + else /* a ray with internal origin */ + enPt->pb = ray.a; + + /* setup initial exit point in the stack */ + StackElem *exPt = new StackElem(); + exPt->t = b; + exPt->pb = ray.a + ray.dir * b; + exPt->node = NULL; /* set termination flag */ + + st.push(enPt); + + /* loop, traverse through the whole kd-tree, until an object is intersected or ray leaves the scene */ + while (node) + { + /* loop until a leaf is found */ + while (!node->isLeaf()) + { + /* retrieve position of splitting plane */ + float splitVal = node->getSplit(); + short axis = node->getAxis(); + + if (enPt->pb[axis] <= splitVal) + { + if (exPt->pb[axis] <= splitVal) + { /* case N1, N2, N3, P5, Z2, and Z3 */ + node = node->getLeftChild(); + continue; + } + if (exPt->pb[axis] == splitVal) + { /* case Z1 */ + node = node->getRightChild(); + continue; + } + /* case N4 */ + farchild = node->getRightChild(); + node = node->getLeftChild(); + } + else + { /* (enPt->pb[axis] > splitVal) */ + if (splitVal < exPt->pb[axis]) + { + /* case P1, P2, P3, and N5 */ + node = node->getRightChild(); + continue; + } + /* case P4*/ + farchild = node->getLeftChild(); + node = node->getRightChild(); + } + + /* case P4 or N4 . . . traverse both children */ + + /* signed distance to the splitting plane */ + t = (splitVal - ray.a.cell[axis]) / ray.dir.cell[axis]; + + /* setup the new exit point */ + st.push(exPt); + exPt = new StackElem(); + + /* push values onto the stack */ + exPt->t = t; + exPt->node = farchild; + exPt->pb[axis] = splitVal; + exPt->pb[(axis+1)%3] = ray.a.cell[(axis+1)%3] + t * ray.dir.cell[(axis+1)%3]; + exPt->pb[(axis+2)%3] = ray.a.cell[(axis+2)%3] + t * ray.dir.cell[(axis+2)%3]; + } /* while */ + + /* current node is the leaf . . . empty or full */ + /* "intersect ray with each object in the object list, discarding " + "those lying before stack[enPt].t or farther than stack[exPt].t" */ + Shape *nearest_shape = NULL; + float dist = exPt->t; + ShapeList::iterator shape; + for (shape = node->shapes.begin(); shape != node->shapes.end(); shape++) + if (*shape != origin_shape && (*shape)->intersect(ray, dist) + && dist >= enPt->t) + nearest_shape = *shape; + + if (nearest_shape) + { + nearest_distance = dist; + return nearest_shape; + } + + /* pop from the stack */ + enPt = exPt; /* the signed distance intervals are adjacent */ + + /* retrieve the pointer to the next node, it is possible that ray traversal terminates */ + node = enPt->node; + + // pop + exPt = st.top(); + st.pop(); + } /* while */ + + /* ray leaves the scene */ + return NULL; +} + // this should save whole kd-tree with triangles distributed into leaves void KdTree::save(ostream &str, KdNode *node) { @@ -260,5 +442,5 @@ // load kd-tree from file/stream void KdTree::load(istream &str, KdNode *node) { - + }