import java.awt.*; import java.util.LinkedList; public class HW12a extends MISApplet{ // MATERIAL PROPERTIES double ambientColor[] = { 0.2, 0., 0.0 }; double diffuseColor[] = { 0.8, 0.0, 0.0 }; double specularColor[] = {.1,.1,.1}; double specularPower = 20.0; // LIGHTING PROPERTIES /** double lightDirections[][] = { {1,0,0} }; double lightColors[][] = { {1.0,1.0,1.0} }; */ double lightDirections[][] = { {1,1,1}, {0,0,1} ,{-1,0,-1} }; double lightColors[][] = { {0.8,0.9,0.8}, {0.5,0.6,0.5}, {0.5,0.6,0.5} }; boolean useLight[] = new boolean[lightDirections.length]; int res = 10; double foc = 5.0;//focal length of pinhole camera int type; double oldTime; double dt; LinkedList surface_list; final double EPSILON = 0.0001; final double INFINITY = Double.MAX_VALUE; double eye[]; boolean mouseDown = false; boolean texture = false; int pixel_width_max = 10; int pixel_width_min = 1; int pixel_width = pixel_width_max; int pass_pixel_width = pixel_width; double camRotX; double camRotY; double camRotZ; double rotY; double lrotY; double rrotY; double lrotX; double rrotX; double xMAX=2; double yMAX=2; double zMAX=2; int alias = 0; double opacity = 0.0; Cube s; double dx[]; double dy[]; double dz[]; double old_dx[]; double old_dy[]; double old_dz[]; boolean frozen; /** Do this once per run */ public void initialize() { camRotX = 0.16493361431346415; camRotY = -0.38222710618675815; camRotZ = 0.0; surface_list = new LinkedList(); // Hemisphere s = new Hemisphere(1.0); // Sphere s = new Sphere(1.0); s = new Cube(1.0); s.indigo().clear(); surface_list.add(s); surface_list.add(new Sphere(0.5).red().semiclear().metal()); surface_list.add(new Sphere(0.5).yellow().semiclear().metal()); surface_list.add(new Sphere(0.5).darkGray().semiclear().metal()); //surface_list.add(new InfinitePlane(0,0,1,1).blue()); dx = new double[] {0.0, 1.5*Math.cos(0/10), 0.0,0.0}; dy = new double[] {0.0, 0.0, 1.5*Math.cos(2*Math.PI/3+0/10), 0}; dz = new double[] {0.0,0.0,0.0, 1.5*Math.cos(2*2*Math.PI/3+0/10)}; frozen = false; } /** Overriden method that must define frame in doube pix[] array */ public void computeImage(double time){ dt = Math.min(1,time - oldTime); oldTime = time; //FREEZING NEEDS TO REVERT TO "LAST SEEN" NOT "LAST PAINTED" if(!frozen){ old_dx = dx; old_dy = dy; old_dz = dz; dx = new double[] {0.0, 1.5*Math.cos(time/10), 0.0,0.0}; dy = new double[] {0.0, 0.0, 1.5*Math.cos(2*Math.PI/3+time/10), 0}; dz = new double[] {0.0,0.0,0.0, 1.5*Math.cos(2*2*Math.PI/3+time/10)}; }else{ dx = old_dx; dy = old_dy; dz = old_dz; } // MOVE THE WORLD ACCORDING TO "CAMERA" Matrix4x4 m = new Matrix4x4(); m.identity(); m.translate(0,0,-20); m.rotateX(camRotX); m.rotateY(camRotY); m.rotateZ(camRotZ); int in= 0; for(ImplicitSurface s: surface_list){ m.translate(dx[in],dy[in],dz[in]); s.transform(m); m.translate(-dx[in],-dy[in],-dz[in]); if(in==0) s.opacity = opacity; else s.opacity = 1.0 - opacity; in++; } // SLOWLY INCREASE RESOLUTION if(pass_pixel_width > pixel_width_min) pixel_width = pass_pixel_width; pass_pixel_width = -1; if(mouseDown) pixel_width = pixel_width_max; else pixel_width = Math.max(pixel_width_min, pixel_width/2); double rgb[] = new double[3]; double v [] = new double[3]; double w [] = new double[3]; // NON ANTI-ALIASING IS FASTER BECAUSE IT DOESN'T LOOP OVER DOUBLES if(alias==0){ for (int i = 0 ; i < W ; i+=pixel_width) // LOOP OVER IMAGE COLUMNS for (int j = 0 ; j < H ; j+=pixel_width) { // LOOP OVER IMAGE ROWS // CONSTRUCT ORIGINAL RAY FROM EYE v[0] = 0; v[1] = 0; v[2] = 0; w[0] = (double)(i - W/2) / W; // COMPUTE RAY DIRECTION AT EACH PIXEL w[1] = (double)(H/2 - j) / W; // w[2] = -foc; // PLACE IMAGE PLANE AT z=-focalLength //initialize pixel color to black rgb[0]=0; rgb[1]=0; rgb[2]=0; normalize(w); rayTrace(v, w, rgb, 0, null , false); // COMPUTE COLOR AT PIXEL BY RAY TRACING int[] color = new int[] {(int)(255*rgb[0]), (int)(255*rgb[1]), (int)(255*rgb[2]) }; for(int _i = i; _i0&&tn0){ useLight[k] = false; break; } } } } } type = surface.type; ambientColor = surface.ambientColor; diffuseColor = surface.diffuseColor; specularColor = surface.specularColor; specularPower= surface.specularPower; if(!skip && surface.opacity>0) phong(normal, rgb, depth, surface.opacity); // REFLECTION double vp[] = new double[] { point[0] + EPSILON*normal[0], point[1] + EPSILON*normal[1], point[2] + EPSILON*normal[2] }; normalize(normal);//superfluous? double wdn = dot(w,normal);// w dot normal double wp[] = new double[] { w[0] - 2*wdn*normal[0], w[1] - 2*wdn*normal[1], w[2] - 2*wdn*normal[2] }; //recursive call to continue ray rayTrace(vp,wp,rgb, depth+1,within, false); //REFRACTION double c[] = new double[] { wdn*normal[0], wdn*normal[1], wdn*normal[2] }; double s[] = new double[] { w[0]-c[0], w[1]-c[1], w[2]-c[2] }; // air is 1, air is not being in something double n1 = null==within ? 1.0 : within.n; double n2 = (null!=within && surface==within) ? 1.0 : surface.n; double theta1 = Math.acos(norm(c)); double theta2 = Math.asin(Math.sin(theta1)*n1/n2); normalize(c); normalize(s); wp[0] = c[0]*Math.cos(theta2)+s[0]*Math.sin(theta2); wp[1] = c[1]*Math.cos(theta2)+s[1]*Math.sin(theta2); wp[2] = c[2]*Math.cos(theta2)+s[2]*Math.sin(theta2); //normalize(wp); vp[0] = point[0] + EPSILON*wp[0]; vp[1] = point[1] + EPSILON*wp[1]; vp[2] = point[2] + EPSILON*wp[2]; //if(theta1 0) for (int i = 0 ; i < 3 ; i++) diffuse[i] = diffuseColor[i] * n_dot_l; else for (int i = 0 ; i < 3 ; i++) diffuse[i] = 0; // COMPUTE REFLECTION DIRECTION for (int i = 0 ; i < 3 ; i++) reflection[i] = 2 * n_dot_l * normal[i] - lightDirections[l][i]; double r_dot_e = dot(reflection, eyeDirection); // COMPUTE SPECULAR if (r_dot_e > 0) { double specularFactor = Math.pow(r_dot_e, specularPower); for (int i = 0 ; i < 3 ; i++) specular[i] = specularColor[i] * specularFactor; } else for (int i = 0 ; i < 3 ; i++) specular[i] = 0; // ADD DIFFUSE AND SPECULAR for (int i = 0 ; i < 3 ; i++) color[i] += lightColors[l][i] * (diffuse[i] + specular[i]); } } // SEND COLOR TO THE FRAME BUFFER for (int i = 0 ; i < 3 ; i++) { rgb[i] += opacity*Math.pow(0.25,depth)* Math.max(0, Math.min(1.0, color[i])); rgb[i] = Math.min(rgb[i],1.0); } } // MERGE SORT /** Universal Merge sort using dist function and point P */ private double[][] mergeSort(double[][] m){ //sub-problem arrays and result double[][] left, right, result; //base cases if(m.length <= 1) return m; //find middle and create and fille sub-problem arrays int middle = m.length/2; left = new double[middle][6]; right = new double[m.length-middle][6]; for(int j=0;j0.5){ opacity = 0.0; } pass_pixel_width = pixel_width_max; break; case '-': case '_': pixel_width_max= Math.max(1,pixel_width_max/2); pixel_width_min= Math.max(1,pixel_width_min/2); pass_pixel_width = pixel_width_max; break; case '+': case '=': pixel_width_max*=2; pixel_width_min*=2; pass_pixel_width = pixel_width_max; break; case 't': case 'T': texture = !texture; pass_pixel_width = pixel_width_max; break; case 'f': case 'F': frozen = !frozen; pass_pixel_width = pixel_width_max; break; case 'c': case 'C': System.out.println("camRotX: "+camRotX); System.out.println("camRotY: "+camRotY); System.out.println("camRotZ: "+camRotZ); break; } return true; } public boolean mouseDown(Event e, int x, int y){ mouseDown = true; return true; } public boolean mouseUp(Event e, int x, int y){ mouseDown = false; return true; } public boolean mouseDrag(Event e, int x, int y) { int wx = W/2; int wy = H/2; y = H - y - 1; double radius = Math.min( W, H )/2.; double sx = (x-wx)/radius; double sy = (y-wy)/radius; if(sx*sx+sy*sy>1){ double denom = Math.sqrt(sx*sx+sy*sy); sx /= denom; sy /= denom; } double sz= Math.sqrt(Math.max(0,1-sx*sx-sy*sy)); double off[] = {sx,sy,sz}; normalize(off); //camRotX = sign(sy)*Math.acos(dot(off,new double[]{1,0,0})); //camRotY = sign(sx)*Math.acos(dot(off,new double[]{0,0,1})); //camRotZ = Math.acos(dot(off,new double[]{1,0,0})); camRotY = Math.PI*(x-W/2)/W; camRotX = -Math.PI*(y-H/2)/H; //camRotY = sign(x)*Math.PI/2*(x-W/2)/W; //camRotX = -sign(y)*Math.PI/2*(y-H/2)/H; return true; } // USEFUL MATH public static void lerp(double f , double y0[], double y1[], double dst[]){ for(int i=0;i3){ if(equals(p1,p2)){ p1 = triangle[3]; }else if(equals(p1,p3)){ p1 = triangle[3]; }else if(equals(p2,p3)){ p3 = triangle[3]; } } double[] a = new double[] {p2[0]-p1[0],p2[1]-p1[1],p2[2]-p1[2]}; double[] b = new double[] {p3[0]-p1[0],p3[1]-p1[1],p3[2]-p1[2]}; /* Surface normal is (p2-p1)x(p3-p1) * of which we only need the z-coordinate * so if n = axb then the z-coordinate is * a1b2 - a2b1 * which in this case is * (p21 - p11)(p32-p12)-(p32-p12)(p31-p11) */ //let's try that again //(a2b3 - a3b2, a3b1 - a1b3, a1b2 - a2b1) double[] cross = new double[] {a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]}; return cross[2]; } public static boolean equals(double p1[], double p2[]){ for(int i =0; i