KD-Tree traversal (raytracing) - am I missing a case?
I'm trying to traverse a 3D KD-Tree in my raytracer. The Tree is correct, but there seems to be something wrong with my traversal algorithm since I'm getting some errors compared to using a brute-force approach (some small surface areas seem to get ignored).
Note: none of the rays in question is parallel to any axis.
This is my traversal algorithm:
IntersectionData* intersectKDTree(const Ray &ray, KDTreeNode* node, double tMin, double tMax) const{
if (node->GetObjectCount()==0) return 0;
IntersectionData* current = 0;
bool intersected = false;
if (node->m_isLeaf){
...test all primitives in the leaf...
}
else{
int axis = node->m_splitAxis;
double splitPos = node->m_splitPos;
double tSplit = (splitPos-ray.point[axis])/ray.direction[axis];
KDTreeNode* nearNode = ray.point[axis]<splitPos?node->m_leftnode:node->m_rightnode;
KDTreeNode* farNode = ray.point[axis]<splitPos?node->m_rightnode:node->m_leftnode;
if (tSplit > tMax)
return 开发者_StackOverflow社区intersectKDTree(ray, nearNode , tMin, tMax);//case A
else if (tSplit < tMin){
if(tSplit>0)
return intersectKDTree(ray, farNode, tMin, tMax);//case B
else if(tSplit<0)
return intersectKDTree(ray, nearNode, tMin,tMax);//case C
else{//tSplit==0
if(ray.direction[axis]<0)
return intersectKDTree(ray, farNode, tMin, tMax);//case D
else
return intersectKDTree(ray, nearNode, tMin, tMax);//case E
}
}
else{
if(tSplit>0){//case F
current = intersectKDTree(ray, nearNode, tMin, tSplit);
if (current != 0)
return current;
else
return intersectKDTree(ray, farNode, tSplit, tMax);
}
else{
return intersectKDTree(ray,nearNode,tSplit, tMax);//case G
}
}
}
}
I created a graphic with all different cases:
(source: cycovery.com)Am I missing a case?
thank you for the help!
Just in case someone's interested - the mistake i did was to not consider a special case described in this paper
http://www.cs.utexas.edu/ftp/pub/techreports/tr88-07.pdf page 12
It happens if one polygon lies on the splitting plane, such that it's part of both cells and the ray goes through both cells. if the nearcell is tested, but the actual intersection happens in the space of the farcell (this is possible because the polygon that intersects is part of both cells) then there is still the possibility, that in the far cell a intersection could be found which is actually closer than the already found one. Therefore - if the found t for the intersection is larger than tSplit, then already the farCell has to be tested
I've taken a different approach to the problem, here's what I do:
if(ray.direction(current_node.split_axis)>0) {
near=current_node.left_child
far=current_node.right_child
} else {
near=current_node.right_child
far=current_node.left_child
}
tsplit=(current_node.split_value-ray.origin[current_node.split_axis])/ray.direction[current_node.split_axis]
if(tsplit>current_stack.tmax||tsplit<0) {
only near child
} else if(tsplit<tmin) {
only far child
} else {
both childs
}
You see that I don't use the origin of the ray for choosing which of the left/right child is near/far, and I take in account the case you named C by using the tsplit<0 condition
精彩评论