Almost everybody has trouble with getting refraction right in a ray tracer. I have a previous blog post on debugging refraction direction if you support boxes. But usually your first ray tracers just supports spheres and when the picture just looks wrong and/or is black, what do you do?
So if you are more disciplined than I usually am, write a visualization tool that shows you in 3D the rays generated for a given pixel and you will often see what the problem is. Like this super cool program for example.
But if you are a stone age person like me:
Then you have exactly two debugging tools: 1) printf() and 2) output various frame buffers. For debugging refraction, I like #1. First, create some model where you know exactly what the behavior of a ray and its descendants should be. Real glass reflects and refracts. Let's get refraction right. So comment out any possibility of reflection. A ray goes in, and refracts (or if that is impossible, prints that).
Now let's set up the simplest ray and single sphere possible. The one I usually use is this:
The viewing ray A from the camera starts at the eye and goes straight long the minus Z axis. I assume here it is a unit length vector but it may not be depending on how you generate them.
How do you generate that ray? You could hard-code it, or you could instrument your program to take a parameter or command line argument or whatever for which pixel to trace (like -x 250 -y 300 or whatever). If you do that you may need to be careful to get the exact center-- like what are the pixel offsets? That is why I usually just hard code it. Then let the program recurse and make sure that you get:
A hits at Q which is point (0,0,1)
The surface normal vector at Q is (0,0,1)
The ray is refracted to create B with origin Q and direction (0,0,-1)
B hits at R is is point (0,0,-1)
The surface normal at R is (0,0,-1)
The ray is refracted to create C with origin R and direction (0,0,-1)
The ray C goes and computes a color H of the background in that direction.
The recursion returns that color H all the way to the original caller
That will find 99% of bugs in my experience