So I was thinking about writing a little bejeweled style game the other day and thought it’d be good enuff to have some shaded balls for the jewels.
Naturally, I decided to write small raytracer.
In case you missed the excellent “Raytracing Topics & Techniques” by Jacco Bikker, here is a quick break down of how a raytracer works: for each pixel at (x,y) in our image, we cast a ray, eg: from (x,y,0) to (x,y,-1).
Casting a ray involves checking to see which object it would hit / intersect first.
In the case of sphere’s, there is a pretty straight forward bit of black magic we can hijack from povray:
public double rayIntersection( Pt start, Pt stop ) { // start_to_sphere = start - center_of_sphere Pt start_to_sphere = new Pt( start, center_of_sphere ); double radius2 = radius_of_sphere * radius_of_sphere; double dv = stop.dot( start_to_sphere ); double stop_length2 = stop.lengthSquared(); double start_to_sphere_length2 = start_to_sphere.lengthSquared(); double start_to_surface_of_sphere = start_to_sphere_length2 - radius2; double determinant = ( ( dv * dv ) - ( stop_length2 * start_to_surface_of_sphere ) ); double result = -1; if( determinant >= 0 ) { determinant = Math.sqrt( determinant ); double t1 = ( -dv + determinant ) / stop_length2; double t2 = ( -dv - determinant ) / stop_length2; result = ( ( t1 = 0 ) || t2 < 0 ) ? t1 : t2; } return result; }
I know that looks cryptic and nasty, but the bottom line is that this will return a number from 0-1 to indicate how far along the ray the hit occurred or -1 if no hit occured.
Using a single ray per pixel and this using the distance value to weight the red, green and blue values for the sphere produced a result like this:
in about 0.320 of a second.
Looks pretty crappy, huh? Bet you could do better in the gimp in about that amount of time! 😛
Whatever… that was just the primary ray. The primary ray is neat, it tells us where the ray hit on what (player hater?), but why doesn’t it look that neat?
The reason is cuz there is no lighting model…
SPOILER WARNING: RayBall.java
BTW, if someone can give me a more descriptive (and accurate) name for that “dv” variable, I’ll happily change it. The changes from the povray example seem to work, cuz after all pt.dot( pt ) = pt.distanceSquared(), right?
———————
IE must be destroyed.
Leave a Reply