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 :)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With