我的kd树遍历代码哪里错了? 我优化了C++的光线跟踪程序。我在树上追踪单一光线。到目前为止,我使用的是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;

我的kd树遍历代码哪里错了? 我优化了C++的光线跟踪程序。我在树上追踪单一光线。到目前为止,我使用的是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;,c++,c++11,raytracing,tree-traversal,kdtree,C++,C++11,Raytracing,Tree Traversal,Kdtree,它没有足够频繁地穿过远处的孩子。我在哪里会错过相关案例?一个问题是小的原始错误代码: //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 交换两行

它没有足够频繁地穿过远处的孩子。我在哪里会错过相关案例?

一个问题是小的原始错误代码:

      //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%的相同像素。这是浮点舍入的问题,但它仍然没有回答这个问题:简化的实现不承认什么情况?或者在这个版本中,什么操作在数值上不够稳定?

首先,不要通过编写您认为更快的代码来试图在速度上击败编译器。由于别名问题,编译器的优化器可能最终无法触及代码。第二,您是否使用了调试器来查看问题所在以及代码在哪里走错了路径?最后,到目前为止,我使用的是Havran的递归算法“B”,对于OOP来说,这似乎是过时的,过于夸张了。那么您是否有一个使用这种递归算法的程序,如果有,它是否有效?如果是,请对新程序并排运行,以查看新程序出错的地方。使用调试器时,是哪部分代码导致了问题?您在发布之前使用过调试器吗?您是否尝试过更改已处理的光栅数以帮助找到出错的地方?另外:使用单个堆栈并推送结构,而不是尝试保持三个堆栈同步。会给你更好的定位。@Anteru:好提示。对于调试:我在发布之前没有尝试过,因为它看起来像是大海捞针。简单的模型没有问题,它需要的不仅仅是少量光线。我的调试技巧不是很好,但我试过了,并花了大约最后一个小时来跟踪它。问题是:我知道存在差异。我没有经常推远节点,所以我肯定太经常错过这个案例了。顺便说一句:图片不正确。我在kd树结构中发现了一个bug,所以它只在一个轴上分裂。这就是为什么它看起来像一片茶壶。它不应该是大海捞针。第一个任务是找到最简单、最小的输入情况,它失败了。然后,在调试器中添加大量调试输出或单步执行,以便将进度与手动计算进行比较。这将很快让您确定行为偏离预期的第一个点,然后您可以从那里向后工作。