Thursday, January 8, 2015

Ray Box Intersection and Normal Calculation

In this I am considering that box is axis aligned as shown in figure:
Axis Aligned means all the faces of box (box has 6 faces) lie along or parallel to the x axis or y axis or z axis.

Algorithm:

Set tnear = -INFINITY , tfar = +INFINITY
Get near point and far point from the cube
For the pair of all planes there are 3 planes this algorithm is for x plane
    if rays x Direction (xd)  = 0, the ray is parallel to the planes so:
        if x0 < x near point or x0 > x far point return FALSE  
    else the ray is not parallel to the planes, so calculate intersection
distances of planes
        t1 = (xl - x0) / xd   
        t2 = (xh - x0) / xd   
        if t1 > t2 , swap t1 and t2
        if t1 > tnear , set tnear = t1
        if t2 < tfar , set tfar = t2
        if tnear > tfar , box is missed so return FALSE
        if tfar < 0 , box is behind ray so return FALSE 
    Repeat procedure for y, then z
    All tests were survived, return TRUE or tnear value 
Explanation of algorithm: 
1. Find the near and far points of the box
2. Now perform whether the ray is hitting the box or not. This can be done by checking ray direction x coordinate is less than near points x 
coordinate and grater than x coordinate of far point. If this condition is true means ray is not hitting the planes 
3. Else find where the ray is hitting the surface 
4. Based on intersection return true or false. I used to return tnear when there is intersection otherwise -1
In C++:

float Cube::intersectCube(SbVec3f rayDirection,SbVec3f rayStart){
 float t1,t2,tnear = -1000.0f,tfar = 1000.0f,temp,tCube;
 SbVec3f b1 = getNearPoint();
 SbVec3f b2 = getFarPoint();
 bool intersectFlag = true;
 for(int i =0 ;i < 3; i++){
  if(rayDirection[i] == 0){
   if(rayStart[i] < b1[i] || rayStart[i] > b2[i])
    intersectFlag = false;
  }
  else{
   t1 = (b1[i] - rayStart[i])/rayDirection[i];
   t2 = (b2[i] - rayStart[i])/rayDirection[i];
  if(t1 > t2){
   temp = t1;
   t1 = t2;
   t2 = temp;
  }
  if(t1 > tnear)
   tnear = t1;
  if(t2 < tfar)
   tfar = t2;
  if(tnear > tfar)
   intersectFlag = false;
  if(tfar < 0)
   intersectFlag = false;
  }
 }
 if(intersectFlag == false)
  tCube = -1;
 else
  tCube = tnear;
 
 return tCube;
}
Normal Calculation for Cube: Cocept: We know there are 6 faces for cube. The near point is on three planes and so the far point. Now check the intersection point lies on which face, this can be easily done by calculating distance between intersection point x,y,z coordinates and near point x,y,z coordinates if the distance is less or equivalent to epsilon value then that intersection point lie on -x or -y or -z and if the intersection point is near to far point then intersection point lie on +x or +y or +z.
Note: This planes can be interchanged between far and near point based on the your image setup
Code:
float EPSI = 0.01;

if(abs(point[0] - cubes[locCube].getNearPoint()[0]) < EPS) 
       normal.setValue(-1,0,0);
else if(abs(point[0] - cubes[locCube].getFarPoint()[0]) < EPS) 
      normal.setValue(1,0,0);
else if(abs(point[1] - cubes[locCube].getNearPoint()[1]) < EPS) 
      normal.setValue(0,-1,0);
else if(abs(point[1] - cubes[locCube].getFarPoint()[1]) < EPS) 
      normal.setValue(0,1,0);
else if(abs(point[2] - cubes[locCube].getNearPoint()[2]) < EPS) 
      normal.setValue(0,0,-1);
else if(abs(point[2] - cubes[locCube].getFarPoint()[2]) < EPS) 
      normal.setValue(0,0,1);

where locCube: cube number with which we are caculating normal
EPS: epsilon value

1 comment:

  1. Hello, now I'm do ray tracing engine and your post be very useful for me. thank you. I think you intersection function be more laconic if do small correction
    float Cube::intersectCube(SbVec3f rayDirection,SbVec3f rayStart){
    float t1,t2,tnear = -1000.0f,tfar = 1000.0f,temp,tCube;
    SbVec3f b1 = getNearPoint();
    SbVec3f b2 = getFarPoint();
    for(int i =0 ;i < 3; i++){
    if(rayDirection[i] == 0){
    if(rayStart[i] < b1[i] || rayStart[i] > b2[i])
    return -1;
    }
    else{
    t1 = (b1[i] - rayStart[i])/rayDirection[i];
    t2 = (b2[i] - rayStart[i])/rayDirection[i];
    if(t1 > t2){
    temp = t1;
    t1 = t2;
    t2 = temp;
    }
    if(t1 > tnear)
    tnear = t1;
    if(t2 < tfar)
    tfar = t2;
    if(tnear > tfar || tfar < 0)
    return -1;
    }
    }
    return tnear;
    }

    ReplyDelete