Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raytracer Refraction Bug

Tags:

c++

raytracing

I'm writing a raytracer in C++, and I've been having some issue with refractions. I'm rendering a sphere and a ground plane, and the sphere should refract. However, it looks more like a sphere within a sphere: the "outer" sphere looks to be shaded properly, but not refracting, while the "inner" sphere looks like it's being self-shadowed. Here's a link to what it looks like: http://imgur.com/QVGkeBT.

Here's the relevant code.

//inside main raytrace function
     if(refraction > 0.0f){ //the surface is refractive
        //calculate refraction vector
        Ray refract(intersection,
          objList[bestObj]->refractedRay(
            ray.dir,intersection,&cos_theta,&R0));
        //recurse
        refrColor = raytrace(refract);
      }
      else{ //no refraction
        refrColor = background;
      }


//refractedRay(vec3,vec3,float*,float*)
  //...initialize variables, do geometric transforms
  //into air out of obj
  if(dot(ray,normal) < 0){
    n1 = ior;
    n2 = 1.0f;
    *cos = dot(ray,-normal);
  }
  //into obj out of air
  else{
    n1 = 1.0f;
    n2 = ior;
    *cos = dot(ray,normal);
    normal = -normal;
  }

  //check value under sqrt
  float n = n1/n2;
  float disc = 1-(pow(n,2)*(1-pow(*cos,2)));
  if(disc < 0){ //total internal reflection
    return ray - 2*-(*cos)*normal; //reflection vector
  }

  return (n*ray)+(((n*(*cos))-sqrt(disc))*normal);

The sphere used to look worse, then I remembered to normalize my vectors and it looks like this. Previously, it looked like only the inner sphere all throughout. Inside the main raytrace function, I do the refraction the same way as reflection, just using the refracted ray instead. I've also tried modifying the incoming point of intersection and ray with epsilon to check for self-refracting as you can get in shadowing.

Any help would be appreciated :)

like image 951
Bhargav B Avatar asked May 09 '13 02:05

Bhargav B


1 Answers

I haven't checked your refraction formulae, but this looks wrong:

//into air out of obj
if(dot(ray,normal) < 0){
  n1 = ior;
  n2 = 1.0f;
  *cos = dot(ray,-normal);
}

If the dot product of the incident ray and the normal is less than zero, and assuming the normal points outwards of the object (which it probably should) then this case corresponds to air -> inside, so your refractive indices should be swapped. As it is now you are rendering a sphere with ior 1 / ior and since that refractive index is less than 1 you are observing total internal reflection on the edges.

Here is one of my implementations which you can take a look at to see if anything is missing (it has more features but you should be able to identify the parts you are interested in and check it your computations match). To me it looks all right so I think fixing the refractive indices should do it.

The nondeterministic pattern in the center of the sphere, though, definitely looks like self-intersection. Make sure that in the case of reflection, you push the reflected ray outside the intersected surface slightly, and in the case of refraction, push the refracted ray inside slightly, to avoid self-intersection.

like image 125
Thomas Avatar answered Nov 29 '22 05:11

Thomas