import java.util.*; public class RayTracer extends PixApplet { //global variables go here double root[] = {0,0,0,0}; double point[] = {0,0,0}; double point2[] = {0,0,0}; double normal[] = {0,0,0}; double flector[]={0,0,0}; double light[]={1,1,1}; double rgb[] = {0,0,0}; double spheres[][] = { {-1, 1, -20, 1} , { 1, .5, -20.0, 1 } , {-1, -1, -19, 1}, {0,0,-220,200} }; int numspheres=4; public void init() { super.init(); } public void setPix(int frame) { // SET PIXELS FOR THIS ANIMATION FRAME double v[] = {0,0,0}; double w[] = {0,0,0}; v[0] = 0; v[1] = 0; // CAMERA EYEPOINT IS AT THE ORIGIN v[2] = 0; double focalLength=3; int n = 0; for (int j = 0 ; j < H ; j++) { // LOOP OVER IMAGE ROWS for (int i = 0 ; i < W ; i++) { // LOOP OVER IMAGE COLUMNS w[0] = (double)(i - W/2) / W; // COMPUTE RAY DIRECTION AT EACH PIXEL w[1] = (double)(H/2 - j) / W; w[2] = -focalLength; // PLACE IMAGE PLANE AT z = -focalLength rayTrace(v,w,0); // RAY TRACE AT THIS PIXEL shadowTrace(v,w); pix[n++] = pack((int)(255.0 * rgb[0]), (int)(255.0 * rgb[1]), (int)(255.0 * rgb[2])); } } } public void rayTrace(double v[], double w[], int depth) { double t=12345; //set the distance to the nearest sphere to a long way away. We use this distance later. double k[]=minRoot(v,w); //this was an ugly way to get two values out of a recursive subroutine. int i=(int) k[0]; //i is the particular sphere that is closest at this pixel t=k[1]; // t is the distance to that sphere. rgb[0]=rgb[1]=rgb[2] =.1+.8*rgb[0]; //.1 is the ambient light. .8 is the fraction reflected by a reflective surface. if (i<100) { double s[]= {v[0]+(t*w[0]), v[1]+(t*w[1]), v[2]+(t*w[2])}; double n[]= {(s[0]-spheres[i][0])/spheres[i][3], (s[1]-spheres[i][1])/spheres[i][3], (s[2]-spheres[i][2])/spheres[i][3]}; double wn= (w[0]*n[0])+(w[1]*n[1])+(w[2]*n[2]); double flector[]= {(-2*wn*n[0])+w[0], (-2*wn*n[1])+w[1], (-2*wn*n[2])+w[2]}; double point[] = {s[0]+(.00001*flector[0]), s[1]+(.00001 * flector[1]), s[2]+(.00001 * flector[2])}; shadowTrace(point,flector); rayTrace(point, flector, depth + 1); rgb[0] =.8 * rgb[0]; rgb[1] = .8 * rgb[1]; rgb[2] = .8 * rgb[2]; } else if(depth == 0) rgb[0]=rgb[1]=rgb[2] = 0; //0 is the background color. } public void shadowTrace(double v[], double w[]){ double t[]=minRoot(v,w); if (t[1]<12345){ point[0] = v[0] + .999*t[1] * w[0]; point[1] = v[1] + .999*t[1] * w[1]; point[2] = v[2] + .999*t[1] * w[2]; double u[]=minRoot(point,light); if (u[1]<12345){ rgb[2]=rgb[1]=rgb[0]*=.5; //the shadow cuts out half of the light. It looks better that way. } } } public double[] minRoot (double v[], double w[]) { double t=12345; double minr=t; int c=100; for(int i = 0; i < numspheres; i++) { double A = (w[0]*w[0])+(w[1]*w[1])+(w[2]*w[2]); double B = 2*( ((v[0]-spheres[i][0])*w[0])+((v[1]-spheres[i][1])*w[1])+((v[2]-spheres[i][2])*w[2]) ); double C = ((v[0]-spheres[i][0])*(v[0]-spheres[i][0]))+((v[1]-spheres[i][1])*(v[1]-spheres[i][1]))+((v[2]-spheres[i][2])*(v[2]-spheres[i][2]))-(spheres[i][3]*spheres[i][3]); double determinant = B*B - 4*A*C; if(determinant >= 0) { double root1 = ((-B) + Math.sqrt(determinant)) / (2*A); double root2 = ((-B) - Math.sqrt(determinant)) / (2*A); minr= Math.min(root1, root2); } if (minr=0) { t=minr; c=i; } } double k[]={c,t}; return k; } }