我正在优化我的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;
它不经常穿越远方的孩子。我在哪里错过相关案例?
答案 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%的相同像素。这是浮点内的四舍五入问题,但它仍然没有回答这个问题:这种简化实现无法识别哪种情况?或者在这个版本中哪些操作不够(数值上)足够稳定?