import java.lang.*; import java.io.*; public class Scene { public Colour Ambient; private int numberObjects; private int numberLights; private Object[] sceneObjects; private Light[] sceneLights; // Maximum reflection depth we will trace to private static int MaxDepth=2; // Temporary static variables for lighting phase // this saves some overhead in memory mangement private Vector n; private Vector h; private Colour kd; // temporary variable for diffuse private Colour ks; // temporary variable for specular public Scene() { numberObjects = 0; sceneObjects = null; numberLights = 0; sceneLights = null; // Default ambient light Ambient = new Colour (0.5,0.5,0.5); // Initialise static variables n = new Vector(); h = new Vector(); kd = new Colour(); ks = new Colour(); } // Note this deletes original scene public void setNumberObjects(int n) { numberObjects = n; sceneObjects = new Object[n]; } public int getNumberObjects() { return numberObjects; } public void setObject(int i, Object o) { sceneObjects[i]=o; } public void setNumberLights(int n) { numberLights = n; sceneLights = new Light[n]; } public int getNumberLights() { return numberLights; } public void setLight(int i, Light o) { sceneLights[i]=o; } public boolean intersect(Ray ray, Colour colour, int depth) { double tmin = java.lang.Double.MAX_VALUE; double t; int hitObject=-1; t = tmin; for (int i=0;i<numberObjects;i++) { t = sceneObjects[i].intersect(ray); if(t > 0.0) { //intersection found if(t < tmin){ tmin = t; hitObject = i; } } } if (hitObject > -1) { /* We have an intersection so calculate lighting */ Point p = ray.getPointAt(tmin); calculateColour(colour, sceneObjects[hitObject], p, ray, depth); colour.clamp(); return true; } else { return false; } } private void calculateColour(Colour colour, Object object, Point p, Ray ray, int depth) { Light light; // temporary reference to current light Vector direction = new Vector(); // ray indicating direction to light /* Ambient component */ colour.copy(object.SurfaceMaterial.Ambient); colour.mult(Ambient); /* Object normal at the intersection point */ n.copy(object.normal(p)); /* For each light in the scene */ /* Hint: the "nextlight" label can be used to jump back to the start if the point is in shadow from a particular light */ nextlight: for (int i=0;i<numberLights;i++) { light = sceneLights[i]; /* Find the direction to the light from the point */ if (light instanceof DirectionalLight) { direction.copy(((DirectionalLight)light).Direction); direction.negate(); } else { Vector.subtract(direction, ((PointLight)light).Origin, p); } double nl = Vector.dot(n,direction); /* does the light illuminate this point? */ if (nl > 0.0) { double pnh; direction.normalise(); /* Your code here (1) - is the light occluded by another object ?*/ Vector.subtract(h,ray.Origin,p); h.normalise(); Vector.add(h,h,direction); h.normalise(); double nh = Vector.dot(n,h); kd.copy(object.SurfaceMaterial.Diffuse); ks.copy(object.SurfaceMaterial.Specular); if (object.SurfaceMaterial.Shininess < 1) { pnh = 0.0; } else { pnh = Math.pow(nh, object.SurfaceMaterial.Shininess); } kd.scale(nl); ks.scale(pnh); kd.add(ks); kd.mult(light.Intensity); colour.add(kd); } } /* Your code here (2) - do a recursive ray trace. Use specular colour to modulate the colour returned by the recursive intersect call */ colour.clamp(); } public void read(SceneReader is) throws Exception { /* * read the objects */ numberObjects = is.readInt(); System.out.println("Scene has "+ numberObjects+ " objects"); setNumberObjects(numberObjects); for(int i=0; i<numberObjects; ++i){ int objectcode = -1; try { objectcode = is.readInt(); } catch (Exception e) { System.out.println("no ocode"); } Object tmp; /*I don't see any way around this*/ switch(objectcode){ case 0 : tmp = new Sphere(); try { tmp.read(is); } catch (IOException e) { throw new Exception("IO error in read sphere\n" + e.getMessage()); } catch (NumberFormatException e) { throw new Exception("Number format error in read sphere\n" + e.getMessage()); } setObject(i,tmp); break; case 1 : tmp = new Plane(); try { tmp.read(is); } catch (IOException e) { throw new Exception("IO error in read Plane\n" + e.getMessage()); } catch (NumberFormatException e) { throw new Exception("Number format error in read Plane\n" + e.getMessage()); } setObject(i,tmp); break; case 2 : tmp = new IndexedFaceSet(); try { tmp.read(is); } catch (IOException e) { throw new Exception("IO error in read IndexedFace\n" + e.getMessage()); } catch (NumberFormatException e) { throw new Exception("Number format error in read IndexedFace\n" + e.getMessage()); } setObject(i,tmp); break; default: break; } } /* * read the ambient light */ try { Ambient.read(is); } catch (IOException e) { throw new Exception("IO error in read ambient\n" + e.getMessage()); } catch (NumberFormatException e) { throw new Exception("Number format error in read ambient\n" + e.getMessage()); } /* * read the directional and point light */ numberLights = is.readInt(); System.out.println("Scene has "+ numberLights+ " lights"); setNumberLights(numberLights); for(int i=0; i<numberLights; ++i){ int objectcode = -1; try { objectcode = is.readInt(); } catch (Exception e) { System.out.println("no ocode"); } Light tmp; /*I don't see any way around this*/ switch(objectcode){ case 0 : tmp = new PointLight(); try { tmp.read(is); } catch (IOException e) { throw new Exception("IO error in read pointlight\n" + e.getMessage()); } catch (NumberFormatException e) { throw new Exception("Number format error in read directionalight\n" + e.getMessage()); } setLight(i,tmp); break; case 1 : tmp = new DirectionalLight(); try { tmp.read(is); } catch (IOException e) { throw new Exception("IO error in read directionallight\n" + e.getMessage()); } catch (NumberFormatException e) { throw new Exception("Number format error in read directionalight\n" + e.getMessage()); } setLight(i,tmp); break; } } System.out.println("Scene read"); } public void write(SceneWriter os) throws IOException { os.writeInt(numberObjects); os.writeString("\n"); for(int i=0; i<numberObjects; ++i){ if (sceneObjects[i] instanceof Sphere) { os.writeInt(0); } else if (sceneObjects[i] instanceof Plane) { os.writeInt(1); } else { os.writeInt(2); } os.writeChar(' '); sceneObjects[i].write(os); os.writeString("\n"); } Ambient.write(os); os.writeInt(numberLights); os.writeString("\n"); for(int i=0; i<numberLights; ++i){ if (sceneLights[i] instanceof PointLight) { os.writeInt(0); } else { os.writeInt(1); } os.writeChar(' '); sceneLights[i].write(os); os.writeString("\n"); } } public void print(SceneWriter os) throws IOException { os.writeString("Number of objects " + numberObjects + "\n"); for(int i=0; i<numberObjects; ++i){ sceneObjects[i].print(os); } os.writeString("Ambient light is "); Ambient.write(os); os.writeString("\n"); os.writeString("Number of lights " + numberLights + "\n"); for(int i=0; i<numberLights; ++i){ sceneLights[i].print(os); } } }