package graphics; public abstract class Shape { //shape's colors protected double shininess; //specular component protected int[] diffuseColor = {0,0,0}; protected int[] specularColor = {0,0,0}; //what fraction of colors are coming from other objects //reflected in object vs. color of actual object public double reflectiveness = 0; public double refIndex = 1.0; //index of refraction public double transparency = 0; //how transparent the object is (0 is opaque) //public int[] color = {0, 0, 0}; //transformation matrix public Matrix3D matrix; public abstract void transform(); public void setDiffuse(int r, int g, int b) { diffuseColor[0] = r; diffuseColor[1] = g; diffuseColor[2] = b; } public void setSpecular(double s, int r, int g, int b) { shininess = s; specularColor[0] = r; specularColor[1] = g; specularColor[2] = b; } //to be overridden by child shapes //returns array of t values (roots) or void if no intersection //sets point of intersection and normal there public double[] testRay(Vector3 v, Vector3 w, Vector3 pos, Vector3 normal) { return null; } //calculates intersection point given v, w, and t protected void setIntersectionPoint(Vector3 v, Vector3 w, double t, Vector3 pos) { pos.set(0, v.get(0) + t * w.get(0)); pos.set(1, v.get(1) + t * w.get(1)); pos.set(2, v.get(2) + t * w.get(2)); } //takes a surface coordinate, normal, original ray direction, array of lights, list of all objects in scene, ambient component //returns color public double[] shade(Vector3 pos, Vector3 normal, Light[] lights, Shape[] shapes, int[] ambient) { Vector3 eye = new Vector3(0, 0, 1); //eye/camera is at the origin looking at neg z //eye.normalize(); double r = 0, g = 0, b = 0; for (int li = 0; li < lights.length; li++) { //colors for this light double lr = 0, lg = 0, lb = 0; //shadow algorithm boolean skipLight = false; Vector3 lv = new Vector3(lights[li].getDirectionVector()); //light vector //lv.scale(-1); //opposite direction //if there's an object in between here and the light source, don't apply light source for (int si = 0; si < shapes.length; si++) { //make sure not to ray test against self! if (shapes[si] == this) continue; //v is point on object, and w is light's direction Vector3 foo = new Vector3(), bar = new Vector3(); //don't care about where it hit or how double[] roots = shapes[si].testRay(pos, lv, foo, bar); if (roots != null) { skipLight = true; break; } } if (skipLight) continue; //diffuse shading // f is L dot N double fDiff = normal.dot( lights[li].getDirectionVector() ); if (fDiff < 0) fDiff = 0; //System.err.println("fDiff = " + fDiff); lr += fDiff * diffuseColor[0]; lg += fDiff * diffuseColor[1]; lb += fDiff * diffuseColor[2]; //specular shading //R = 2*f*N - L //Ls = [rs,gs,bs]max(0, E ∙ R)^p Vector3 R = new Vector3(normal); //copy normal vector R.scale(-2 * fDiff); // r is now -2fN R.add( lights[li].getDirectionVector() ); //r is now L - 2fN R.scale(-1); R.normalize(); double fSpec = Math.pow(eye.dotProduct(R), shininess); //E ∙ R if (fSpec < 0) fSpec = 0; //System.err.println("fSpec = " + fSpec); lr += fSpec * specularColor[0]; lg += fSpec * specularColor[1]; lb += fSpec * specularColor[2]; //factor in light source, but //scale back down (compare 0.5 * 0.5 with (128 * 128)/256) lr *= lights[li].color[0] / 256.0; lg *= lights[li].color[1] / 256.0; lb *= lights[li].color[2] / 256.0; //add the light to object's light r += lr; g += lg; b += lb; } //add ambient component r += ambient[0]; g += ambient[1]; b += ambient[2]; if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; //System.err.println(r+","+g+","+b); double[] rgb = {0,0,0}; //copy color info back into shape rgb[0] = r; rgb[1] = g; rgb[2] = b; return rgb; } }