views:

448

answers:

2

Hi! 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 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:

alt text

Am I missing a case?

thank you for the help!

A: 

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

dpuzzo
hi! but for example in case C you'd traverse the wrong child, since 'near' would be left child, but you'd be supposed to traverse right child.
Mat
+1  A: 

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

Mat