我的kd树遍历代码在哪里错了?

时间:2014-08-18 15:49:35

标签: c++ c++11 raytracing tree-traversal kdtree

我正在优化我的c ++光线跟踪器。我通过kdtrees跟踪单个光线。到目前为止,我使用的是Havran的递归算法' B'这对于OOP来说似乎很古老而且过于夸张。我的新代码尽可能短(希望编译器更容易优化,更容易维护):

    struct StackElement{
        KDTreeNode<PT>* node;
        float tmax;
        array<float, 3> origin;
    };

    //initializing explicit stack
    stack<StackElement> mystack;

    //initialize local variables
    KDTreeNode<PT>* node = tree.root;
    array<float, 3> origin {ray.origin[0], ray.origin[1], ray.origin[2]};
    const array<float, 3> direction {ray.direction[0], ray.direction[1], ray.direction[2]};
    const array<float, 3> invDirection {1.0f / ray.direction[0], 1.0f / ray.direction[1], 1.0f / ray.direction[2]};
    float tmax = numeric_limits<float>::max();
    float tClosestIntersection = numeric_limits<float>::max();
    bool notFullyTraversed = true;

    while(notFullyTraversed) {
        if (node->isLeaf()) {

            //test all primitives inside the leaf
            for (auto p : node->primitives()) {
                p->intersect(ray, tClosestIntersection, intersection, tmax);
            }

            //test if leaf + empty stack => return
            if (nodeStack.empty()) {
                notFullyTraversed = false;
            } else {
                //pop all stack
                origin = mystack.top().origin;
                tmax = mystack.top().tmax;
                node = mystack.top().node;
                mystack.pop();
            }
        } else {
            //get axis of node and its split plane
            const int axis = node->axis();
            const float plane = node->splitposition();

            //test if ray is not parallel to plane
            if ((fabs(direction[axis]) > EPSILON)) {
                const float t = (plane - origin[axis]) * invDirection[axis];

                //case of the ray intersecting the plane, then test both childs
                if (0.0f < t && t < tmax) {
                    //traverse near first, then far. Set tmax = t for near
                    tmax = t;
                    //push only far child onto stack
                    mystack.push({
                                 (origin[axis] > plane )  ? node->leftChild() : node->rightChild() ,
                                 tmax - t,
                                 {origin[0] + direction[0] * t, origin[1] + direction[1] * t, origin[2] + direction[2] * t}
                                 });
                }
            }
            //in every case: traverse near child first
            node = (origin[axis] > plane) ? node->rightChild() : node->leftChild();

        }
    }

    return intersection.found;

它不经常穿越远方的孩子。我在哪里错过相关案例?

1 个答案:

答案 0 :(得分:0)

一个问题很小(原始,错误的代码):

      //traverse near first, then far. Set tmax = t for near
      tmax = t;
      //push only far child onto stack
      mystack.push({ ... , tmax - t,  ...    });

它始终将0.0f作为远节点的退出距离推到堆栈上,这意味着交叉点不接受正t。

交换这两行可以解决这个问题。

我的resurcive堆栈跟踪/决策仍然不同(Havran需要大约25%的迭代次数),输出图片具有99.5%的相同像素。这是浮点内的四舍五入问题,但它仍然没有回答这个问题:这种简化实现无法识别哪种情况?或者在这个版本中哪些操作不够(数值上)足够稳定?