sixth level
diff --git a/src/elements/AmbientLight.java b/src/elements/AmbientLight.java
index 88a95cd..362c750 100644
--- a/src/elements/AmbientLight.java
+++ b/src/elements/AmbientLight.java
@@ -8,33 +8,20 @@
* @author Adiel
*
*/
-public class AmbientLight {
-
- /**
- * Intensity of ambient light color
- */
- final private Color _intensity;
+public class AmbientLight extends Light {
/**
*
- * AmbientLight constructor calculates the final power of fill lighting stored in
- * a field _intensity
- *
- * @param iA for original fill light (light intensity according to RGB components)
+ * AmbientLight constructor calculates the final power of fill lighting stored
+ * in a field _intensity in superClass
+ *
+ * @param iA for original fill light (light intensity according to RGB
+ * components)
* @param kA for coefficient of attenuation of filler light
*/
public AmbientLight(Color iA, double kA) {
+ super(iA.scale(kA));
- this._intensity = iA.scale(kA);
- }
-
- /**
- * Getter intensity color
- *
- * @return the _intensity
- */
- public Color getIntensity() {
- return _intensity;
}
}
diff --git a/src/elements/DirectionalLight.java b/src/elements/DirectionalLight.java
new file mode 100644
index 0000000..2ab2a7e
--- /dev/null
+++ b/src/elements/DirectionalLight.java
@@ -0,0 +1,36 @@
+package elements;
+
+import primitives.Color;
+import primitives.Point3D;
+import primitives.Vector;
+
+public class DirectionalLight extends Light implements LightSource {
+
+
+ private Vector direction;
+
+ /**
+ * DirectionalLight constructor initializes directional light with it's intensity and direction
+ *
+ * @param intensity for the light
+ * @param direction for direction vector
+ */
+ public DirectionalLight(Color intensity, Vector direction) {
+ super(intensity);
+ this.direction = direction.normalized();
+ }
+
+ @Override
+ public Color getIntensity(Point3D p) {
+
+ return super.getIntensity();
+ }
+
+ @Override
+ public Vector getL(Point3D p) {
+
+ return direction;
+ }
+
+
+}
diff --git a/src/elements/Light.java b/src/elements/Light.java
new file mode 100644
index 0000000..97412f2
--- /dev/null
+++ b/src/elements/Light.java
@@ -0,0 +1,34 @@
+/**
+ *
+ */
+package elements;
+
+import primitives.Color;
+
+/**
+ * @author Adiel
+ *
+ */
+ abstract class Light {
+
+ private Color intensity;
+
+ /**
+ * Light constructor
+ * @param intensity
+ */
+ protected Light(Color intensity) {
+ this.intensity = intensity;
+ }
+
+ /**
+ * Getter the intensity
+ * @return the intensity
+ */
+ public Color getIntensity() {
+ return intensity;
+ }
+
+
+
+}
diff --git a/src/elements/LightSource.java b/src/elements/LightSource.java
new file mode 100644
index 0000000..5b98f07
--- /dev/null
+++ b/src/elements/LightSource.java
@@ -0,0 +1,12 @@
+package elements;
+
+import primitives.Color;
+import primitives.Point3D;
+import primitives.Vector;
+
+public interface LightSource {
+
+ public Color getIntensity(Point3D p);
+ public Vector getL(Point3D p);
+
+}
diff --git a/src/elements/PointLight.java b/src/elements/PointLight.java
new file mode 100644
index 0000000..2d5efa8
--- /dev/null
+++ b/src/elements/PointLight.java
@@ -0,0 +1,42 @@
+package elements;
+
+import primitives.Color;
+import primitives.Point3D;
+import primitives.Vector;
+
+public class PointLight extends Light implements LightSource {
+
+ private Point3D position;
+ private double kC;
+ private double kL;
+ private double kQ;
+
+ /**
+ * @param intensity
+ * @param position
+ * @param kC
+ * @param kL
+ * @param kQ
+ */
+ public PointLight(Color intensity, Point3D position, double kC, double kL, double kQ) {
+ super(intensity);
+ this.position = position;
+ this.kC = kC;
+ this.kL = kL;
+ this.kQ = kQ;
+ }
+
+ @Override
+ public Color getIntensity(Point3D p) {
+
+ return getIntensity().reduce(kC + kL * p.distance(position) + kQ * p.distanceSquared(position));
+ }
+
+ @Override
+ public Vector getL(Point3D p) {
+
+
+ return p.subtract(position).normalize();
+ }
+
+}
diff --git a/src/elements/SpotLight.java b/src/elements/SpotLight.java
new file mode 100644
index 0000000..783ebbd
--- /dev/null
+++ b/src/elements/SpotLight.java
@@ -0,0 +1,43 @@
+
+package elements;
+
+import primitives.Color;
+import primitives.Point3D;
+import primitives.Vector;
+
+public class SpotLight extends PointLight {
+
+ private Vector direction;
+
+ /**
+ * @param direction
+ * @param intensity
+ * @param position
+ * @param kC
+ */
+ public SpotLight(Color intensity, Point3D position,Vector direction,double kC,double kL,double kQ) {
+ super(intensity, position, kC, kL, kQ);
+ this.direction = direction.normalized();
+ }
+
+ @Override
+ public Color getIntensity(Point3D p) {
+ Vector l=getL(p);
+ /*
+ * if(l==null) { return Color.BLACK; }
+ */
+ double d=direction.dotProduct(l);
+ if(d<=0) {
+ return Color.BLACK;
+ }
+ //d=Math.pow(d, d)
+
+ return super.getIntensity(p).scale(d);
+ }
+
+ /*
+ * @Override public Vector getL(Point3D p) {
+ *
+ * // TODO Auto-generated method stub return null; }
+ */
+}
diff --git a/src/geometries/Geometries.java b/src/geometries/Geometries.java
index e84fde0..4889a8b 100644
--- a/src/geometries/Geometries.java
+++ b/src/geometries/Geometries.java
@@ -5,7 +5,6 @@
import primitives.Point3D;
import primitives.Ray;
-
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -27,6 +26,7 @@
/**
* Constructor for the geometries
+ *
* @param geometries for the intersections
*/
public Geometries(Intersectable... geometries) {
@@ -37,6 +37,7 @@
/**
* Adding to list
+ *
* @param geometries
*/
public void add(Intersectable... geometries) {
@@ -44,21 +45,34 @@
}
- @Override
- public List<Point3D> findIntersections(Ray ray) {
- List<Point3D> result = null;
+ /*
+ * @Override public List<Point3D> findIntersections(Ray ray) { List<Point3D>
+ * result = null;
+ *
+ * // A loop that adds to the list all the intersection points that the ray has
+ * // with // all the geometric bodies for (Intersectable item :
+ * _intersectableList) { List<Point3D> elementList =
+ * item.findIntersections(ray); if (elementList != null) { if (result == null) {
+ * result = new LinkedList<>(); } result.addAll(elementList); } } return result;
+ * }
+ */
- //A loop that adds to the list all the intersection points that the ray has with
- //all the geometric bodies
- for (Intersectable item : _intersectableList) {
- List<Point3D> elementList = item.findIntersections(ray);
- if (elementList != null) {
- if (result == null) {
- result = new LinkedList<>();
+ @Override
+ public List<GeoPoint> findGeoIntersections(Ray ray) {
+ List<GeoPoint> intersections = null;
+
+ for (Intersectable geometry : _intersectableList ) {
+ var geoIntersectoions = geometry.findGeoIntersections(ray);
+ if (geoIntersectoions != null) {
+ if(intersections==null) {
+ intersections=new LinkedList<>();
+
}
- result.addAll(elementList);
+ intersections.addAll(geoIntersectoions);
}
}
- return result;
+ return intersections;
}
+
+
}
\ No newline at end of file
diff --git a/src/geometries/Geometry.java b/src/geometries/Geometry.java
index dcd47be..502f387 100644
--- a/src/geometries/Geometry.java
+++ b/src/geometries/Geometry.java
@@ -1,22 +1,71 @@
package geometries;
+import primitives.Color;
+import primitives.Material;
import primitives.Point3D;
import primitives.Vector;
/**
- * Interface for the geometric shapes
+ * Abstract class for the geometric shapes
*
* @author Adiel
*
*/
-public interface Geometry extends Intersectable{
+public abstract class Geometry implements Intersectable{
+
+ protected Color emission=Color.BLACK;
+ private Material material=new Material();
+
+
+ /**
+ * Getter for the emission
+ * @return the emission
+ */
+ public Color getEmission() {
+ return emission;
+ }
+
+
+ /**
+ * Getter for material
+ * @return the material
+ */
+ public Material getMaterial() {
+ return material;
+ }
+
+
+
+ /**
+ * Setter for material
+ * @param material the material to set
+ * @return the Geometry itself
+ */
+ public Geometry setMaterial(Material material) {
+ this.material = material;
+ return this;
+ }
+
+
+
+ /**
+ * Setter for the emission
+ * @param emmission the emission to set
+ * @return the Geometry itself
+ */
+ public Geometry setEmission(Color emission) {
+ this.emission = emission;
+ return this;
+ }
+
+
/**
*
* @param point3D of the vector
* @return normalized vector
*/
- Vector getNormal(Point3D point3D);
+ public abstract Vector getNormal(Point3D point3D);
}
diff --git a/src/geometries/Intersectable.java b/src/geometries/Intersectable.java
index c3e8508..c132e20 100644
--- a/src/geometries/Intersectable.java
+++ b/src/geometries/Intersectable.java
@@ -6,6 +6,7 @@
import primitives.*;
import java.util.List;
+import java.util.stream.Collectors;
/**
* @author Adiel
@@ -13,11 +14,62 @@
* Interface for intersection points
*/
public interface Intersectable {
- /**
+ /**
+ * Static Internal Auxiliary Class (PDS) that is a tuple of references to a specific geometry
+ * and its intersection point
+ *
+ *
+ */
+ public static class GeoPoint{
+ public Geometry geometry;
+ public Point3D point;
+
+ /**
+ * GeoPoint constructor for geometry and point
+ *
+ * @param geometry reference to current geometry
+ * @param point reference to current point on geometry
+ */
+ public GeoPoint(Geometry geometry, Point3D point) {
+
+ this.geometry = geometry;
+ this.point = point;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof GeoPoint))
+ return false;
+ GeoPoint other = (GeoPoint) obj;
+ return geometry.equals(other.geometry) && point.equals(other.point);
+
+ }
+
+
+
+
+ }
+
+ /**
+ * Find all intersection points from the ray with the geometry
+ *
+ * @param ray the famous Ray pointing to
+ * @return list of intersection points
+ */
+ List<GeoPoint> findGeoIntersections(Ray ray);
+
+ /**
* Find all intersection points from the ray
*
* @param ray the famous Ray pointing to
* @return intersection points
*/
- List<Point3D> findIntersections(Ray ray);
+ default List<Point3D> findIntersections(Ray ray){
+ var geoList=findGeoIntersections(ray);
+ return geoList==null ? null : geoList.stream().map(gp->gp.point).collect(Collectors.toList());
+ }
}
diff --git a/src/geometries/Plane.java b/src/geometries/Plane.java
index 26ae874..8f8d1c1 100644
--- a/src/geometries/Plane.java
+++ b/src/geometries/Plane.java
@@ -12,7 +12,7 @@
* @author Adiel
*
*/
-public class Plane implements Geometry {
+public class Plane extends Geometry {
final Point3D q0;
final Vector normal;
@@ -72,9 +72,30 @@
}
+ /*
+ * @Override public List<Point3D> findIntersections(Ray ray) { List<Point3D>
+ * result = null;
+ *
+ * //Check if q0=p0 if (q0.equals(ray.getP0())) { return null; }
+ *
+ * double numerator = alignZero(normal.dotProduct(q0.subtract(ray.getP0())));
+ * double denominator = alignZero(normal.dotProduct(ray.getDir()));
+ *
+ * //Check if numerator or denominator equal zero if (isZero(numerator) ||
+ * isZero(denominator)) { return null; }
+ *
+ * double t = numerator / denominator; if (t < 0) { return result;//result=null
+ * }
+ *
+ *
+ * return List.of(ray.getPoint(t));
+ *
+ * }
+ */
+
@Override
- public List<Point3D> findIntersections(Ray ray) {
- List<Point3D> result = null;
+ public List<GeoPoint> findGeoIntersections(Ray ray) {
+List<GeoPoint> result = null;
//Check if q0=p0
if (q0.equals(ray.getP0())) {
@@ -95,7 +116,7 @@
}
- return List.of(ray.getPoint(t));
+ return List.of(new GeoPoint(this,ray.getPoint(t)));
}
diff --git a/src/geometries/Polygon.java b/src/geometries/Polygon.java
index ec98b6b..d55d95a 100644
--- a/src/geometries/Polygon.java
+++ b/src/geometries/Polygon.java
@@ -10,7 +10,7 @@
*
* @author Dan
*/
-public class Polygon implements Geometry {
+public class Polygon extends Geometry {
/**
* List of polygon's vertices
*/
@@ -86,16 +86,42 @@
return plane.getNormal();
}
+ /*
+ * @Override public List<Point3D> findIntersections(Ray ray) { List<Point3D>
+ * result = plane.findIntersections(ray);
+ *
+ * // Check if intersect ray with the plane. if (result == null) { return null;
+ * }
+ *
+ * // Check if the intersection point with its plane is inside the polygon
+ * Vector v = ray.getDir(); Point3D P0 = ray.getP0(); Vector v1 =
+ * vertices.get(0).subtract(P0); Vector v2 = vertices.get(1).subtract(P0);
+ *
+ * double t = alignZero(v.dotProduct(v1.crossProduct(v2).normalize())); if
+ * (isZero(t)) { return null; }
+ *
+ * boolean sign = t > 0; int size = vertices.size(); Vector vn =
+ * vertices.get(size - 1).subtract(P0); t =
+ * alignZero(v.dotProduct(vn.crossProduct(v1).normalize())); if (isZero(t) ||
+ * sign ^ (t > 0)) { return null; }
+ *
+ * // Check if all vertices have the same sign for (int i = 2; i < size; i++) {
+ * v1 = v2; v2 = vertices.get(i).subtract(P0); t =
+ * alignZero(v.dotProduct(v1.crossProduct(v2).normalize())); if (isZero(t) ||
+ * sign ^ (t > 0)) { return null; }
+ *
+ * } return result; }
+ */
@Override
- public List<Point3D> findIntersections(Ray ray) {
- List<Point3D> result = plane.findIntersections(ray);
-
- //Check if intersect ray with the plane.
+ public List<GeoPoint> findGeoIntersections(Ray ray) {
+ List<GeoPoint> result = plane.findGeoIntersections(ray);
+
+ // Check if intersect ray with the plane.
if (result == null) {
return null;
}
-
- //Check if the intersection point with its plane is inside the polygon
+
+ // Check if the intersection point with its plane is inside the polygon
Vector v = ray.getDir();
Point3D P0 = ray.getP0();
Vector v1 = vertices.get(0).subtract(P0);
@@ -105,7 +131,7 @@
if (isZero(t)) {
return null;
}
-
+
boolean sign = t > 0;
int size = vertices.size();
Vector vn = vertices.get(size - 1).subtract(P0);
@@ -113,8 +139,8 @@
if (isZero(t) || sign ^ (t > 0)) {
return null;
}
-
- //Check if all vertices have the same sign
+
+ // Check if all vertices have the same sign
for (int i = 2; i < size; i++) {
v1 = v2;
v2 = vertices.get(i).subtract(P0);
@@ -124,6 +150,6 @@
}
}
- return result;
+ return List.of(new GeoPoint(this,result.get(0).point));
}
}
diff --git a/src/geometries/Sphere.java b/src/geometries/Sphere.java
index 45bc424..4b8c071 100644
--- a/src/geometries/Sphere.java
+++ b/src/geometries/Sphere.java
@@ -13,7 +13,7 @@
* @author Adiel
*
*/
-public class Sphere implements Geometry {
+public class Sphere extends Geometry {
final Point3D center;
final double radius;
@@ -58,15 +58,42 @@
return vector.normalize();
}
+ /*
+ * @Override public List<Point3D> findIntersections(Ray ray) { List<Point3D>
+ * result = null; Point3D P0 = ray.getP0(); Vector v = ray.getDir();
+ * //P0==center if (center.equals(P0)) {
+ *
+ * return List.of(ray.getPoint(radius));
+ *
+ * }
+ *
+ * Vector u = center.subtract(P0);
+ *
+ * double tm = alignZero(u.dotProduct(v)); double d =
+ * alignZero(Math.sqrt(u.lengthSquared() - tm * tm));
+ *
+ * if (d > radius) { return null; } double th = alignZero(Math.sqrt(radius *
+ * radius - d * d));
+ *
+ * double t1 = alignZero(tm - th); double t2 = alignZero(tm + th);
+ *
+ * if (t1 > 0 && t2 > 0) { return List.of(ray.getPoint(t1), ray.getPoint(t2));
+ *
+ * } else if (t1 > 0) { return List.of(ray.getPoint(t1));
+ *
+ * } else if (t2 > 0) { return List.of(ray.getPoint(t2)); }
+ *
+ * return result; }
+ */
@Override
- public List<Point3D> findIntersections(Ray ray) {
- List<Point3D> result = null;
+ public List<GeoPoint> findGeoIntersections(Ray ray) {
+ List<GeoPoint> result = null;
Point3D P0 = ray.getP0();
Vector v = ray.getDir();
//P0==center
if (center.equals(P0)) {
- return List.of(ray.getPoint(radius));
+ return List.of(new GeoPoint(this,ray.getPoint(radius)));
}
@@ -84,13 +111,14 @@
double t2 = alignZero(tm + th);
if (t1 > 0 && t2 > 0) {
- return List.of(ray.getPoint(t1), ray.getPoint(t2));
+ return List.of(new GeoPoint(this,ray.getPoint(t1)),
+ new GeoPoint(this, ray.getPoint(t2)));
} else if (t1 > 0) {
- return List.of(ray.getPoint(t1));
+ return List.of(new GeoPoint(this,ray.getPoint(t1)));
} else if (t2 > 0) {
- return List.of(ray.getPoint(t2));
+ return List.of(new GeoPoint(this,ray.getPoint(t2)));
}
return result;
diff --git a/src/geometries/Triangle.java b/src/geometries/Triangle.java
index 9efcba7..25044dc 100644
--- a/src/geometries/Triangle.java
+++ b/src/geometries/Triangle.java
@@ -27,4 +27,5 @@
return vertices + ", " + plane;
}
+
}
diff --git a/src/geometries/Tube.java b/src/geometries/Tube.java
index c7df809..5580660 100644
--- a/src/geometries/Tube.java
+++ b/src/geometries/Tube.java
@@ -13,7 +13,7 @@
* @author Adiel
*
*/
-public class Tube implements Geometry {
+public class Tube extends Geometry {
protected Ray axisRay;
protected double radius;
@@ -71,8 +71,10 @@
return vector.normalize();
}
+
+
@Override
- public List<Point3D> findIntersections(Ray ray) {
+ public List<GeoPoint> findGeoIntersections(Ray ray) {
// TODO Auto-generated method stub
return null;
}
diff --git a/src/primitives/Material.java b/src/primitives/Material.java
new file mode 100644
index 0000000..d0e2dd6
--- /dev/null
+++ b/src/primitives/Material.java
@@ -0,0 +1,35 @@
+package primitives;
+
+public class Material {
+
+ public double kD=0.0;
+ public double kS=0.0;
+ public int nShininess=0;
+
+ /**
+ * @param kD the kD to set
+ * @return
+ */
+ public Material setkD(double kD) {
+ this.kD = kD;
+ return this;
+ }
+ /**
+ * @param kS the kS to set
+ * @return
+ */
+ public Material setkS(double kS) {
+ this.kS = kS;
+ return this;
+ }
+ /**
+ * @param nShininess the nShininess to set
+ * @return
+ */
+ public Material setnShininess(int nShininess) {
+ this.nShininess = nShininess;
+ return this;
+ }
+
+
+}
diff --git a/src/primitives/Ray.java b/src/primitives/Ray.java
index 6ccd995..3a27aca 100644
--- a/src/primitives/Ray.java
+++ b/src/primitives/Ray.java
@@ -1,6 +1,7 @@
package primitives;
import java.util.List;
+import geometries.Intersectable.GeoPoint;
/**
* Class Ray is the class representing a set of points on a line that are on one
@@ -80,12 +81,12 @@
public Point3D findClosestPoint(List<Point3D> points) {
Point3D result;
-
- //Check that the list is not empty
+
+ // Check that the list is not empty
if (points.size() > 0) {
result = points.get(0);
- //A loop that goes through on the list
- //and checks what is the closest point to the beginning of the ray
+ // A loop that goes through on the list
+ // and checks what is the closest point to the beginning of the ray
for (Point3D other : points) {
if ((p0.distance(other)) < p0.distance(result)) {
result = other;
@@ -98,4 +99,33 @@
return null;
}
+ /**
+ *
+ * Finding the closest point and geometry to the p0 of the camera
+ *
+ * @param intersections list of points and geometries, the function should find from this list
+ * the closest point and geometry to p0 of the camera in the scene
+ * @return the closest point and geometry to the camera
+ */
+ public GeoPoint getClosestGeoPoint(List<GeoPoint> intersections) {
+ GeoPoint result;
+
+ // Check that the list is not empty
+ if (intersections.size() > 0) {
+ result = intersections.get(0);
+
+ // A loop that goes through on the list
+ // and checks what is the closest point to the beginning of the ray
+ for (GeoPoint other : intersections) {
+ if ((other.point.distance(p0)) < result.point.distance(p0)) {
+ result = other;
+
+ }
+ }
+ return result;
+ }
+
+ return null;
+
+ }
}
diff --git a/src/renderer/RayTracerBasic.java b/src/renderer/RayTracerBasic.java
index 3cc47c5..958a2b5 100644
--- a/src/renderer/RayTracerBasic.java
+++ b/src/renderer/RayTracerBasic.java
@@ -1,11 +1,14 @@
package renderer;
-import java.util.List;
+import geometries.Intersectable.GeoPoint;
import primitives.Color;
-import primitives.Point3D;
import primitives.Ray;
+import primitives.Vector;
import scene.Scene;
+import static primitives.Util.*;
+
+import elements.LightSource;
/**
* The class inherits from the abstract class RayTracerBase
@@ -28,25 +31,64 @@
/**
* A private auxiliary function that receives a point and returns color
+ * @param ray
*
* @param point for point
* @return color of ambient light of the scene
*/
- private Color calcColor(Point3D point) {
- return scene.ambientLight.getIntensity();
+ private Color calcColor(GeoPoint intersection, Ray ray) {
+ return scene.ambientLight.getIntensity().add(intersection.geometry.getEmission())
+ .add(calcLocalEffects(intersection, ray));
}
@Override
public Color traceRay(Ray ray) {
- List<Point3D> intersections = scene.geometries.findIntersections(ray);
+ var intersections=scene.geometries.findGeoIntersections(ray);
// If no intersection points were found
if (intersections == null) {
return scene.background;
}
- Point3D closestPoint = ray.findClosestPoint(intersections);
- return calcColor(closestPoint);
+ GeoPoint closestPoint = ray.getClosestGeoPoint(intersections);
+ return calcColor(closestPoint,ray);
}
+ private Color calcLocalEffects(GeoPoint intersection,Ray ray) {
+ Vector v=ray.getDir();
+ Vector n=intersection.geometry.getNormal(ray.getP0());
+ double nv=alignZero(n.dotProduct(v));
+ if(nv==0)
+ return Color.BLACK;
+ int nShininess=intersection.geometry.getMaterial().nShininess;
+ double kd=intersection.geometry.getMaterial().kD;
+ double ks=intersection.geometry.getMaterial().kS;
+
+ Color color=Color.BLACK;
+ for(LightSource lightSource:scene.lights) {
+ Vector l=lightSource.getL(intersection.point);
+ double nl=alignZero(n.dotProduct(l));
+ if(nl*nv>0) {//sign(nl)==sign(nv)
+ Color lightIntensity=lightSource.getIntensity(intersection.point);
+ color=color.add(calcDiffusive(kd,l,n,lightIntensity)
+ .add(calcSpecular(ks,l,n,v,nShininess,lightIntensity)));
+ }
+ }
+ return color;
+ }
+
+ private Color calcSpecular(double ks, Vector l, Vector n, Vector v, int nShininess, Color lightIntensity) {
+
+ Vector r=l.subtract(n.scale(2*l.dotProduct(n)));
+ double vr=alignZero(-v.dotProduct(r));
+ if(vr>0) {
+ return lightIntensity.scale(ks* Math.pow(vr,nShininess));
+ }
+ return lightIntensity.scale(0);
+ }
+
+ private Color calcDiffusive(double kd, Vector l, Vector n, Color lightIntensity) {
+ return lightIntensity.scale(kd*Math.abs(l.dotProduct(n)));
+
+ }
}
diff --git a/src/renderer/Render.java b/src/renderer/Render.java
index 9a82a63..396516d 100644
--- a/src/renderer/Render.java
+++ b/src/renderer/Render.java
@@ -7,6 +7,7 @@
import primitives.Ray;
import scene.Scene;
+
/**
* This class creates from the scene the color matrix of the image
*
@@ -86,7 +87,7 @@
for (int j = 0; j < nY; ++j) {
ray = camera.constructRayThroughPixel(nX, nY, j, i);
color = rayTracer.traceRay(ray);
- imageWriter.writePixel(i, j, color);
+ imageWriter.writePixel(j, i, color);
}
}
diff --git a/src/scene/Scene.java b/src/scene/Scene.java
index 270e7a0..dd09625 100644
--- a/src/scene/Scene.java
+++ b/src/scene/Scene.java
@@ -1,7 +1,11 @@
package scene;
+import java.util.LinkedList;
+import java.util.List;
+
import elements.AmbientLight;
+import elements.LightSource;
import geometries.Geometries;
import primitives.Color;
@@ -17,6 +21,7 @@
public Color background=Color.BLACK;
public AmbientLight ambientLight=new AmbientLight(Color.BLACK, 0.0);
public Geometries geometries=null;
+ public List<LightSource> lights=new LinkedList<LightSource>();
/**
* Scene constructor who gets the name of the scene and
@@ -64,6 +69,17 @@
this.geometries = geometries;
return this;
}
+
+
+
+
+ /**
+ * @param lights the lights to set
+ */
+ public Scene setLights(List<LightSource> lights) {
+ this.lights = lights;
+ return this;
+ }
diff --git a/src/unittests/lights/LightsTests.java b/src/unittests/lights/LightsTests.java
new file mode 100644
index 0000000..70ae5fd
--- /dev/null
+++ b/src/unittests/lights/LightsTests.java
@@ -0,0 +1,178 @@
+package unittests.lights;
+
+import org.junit.Test;
+
+import elements.*;
+import geometries.*;
+import primitives.*;
+import renderer.*;
+import scene.Scene;
+
+/**
+ * Test rendering a basic image
+ *
+ * @author Dan
+ */
+public class LightsTests {
+ private Scene scene1 = new Scene("Test scene");
+ private Scene scene2 = new Scene("Test scene") //
+ .setAmbientLight(new AmbientLight(new Color(java.awt.Color.WHITE), 0.15));
+ private Camera camera1 = new Camera(new Point3D(0, 0, 1000), new Vector(0, 0, -1), new Vector(0, 1, 0)) //
+ .setViewPlaneSize(150, 150) //
+ .setVpDistance(1000);
+ private Camera camera2 = new Camera(new Point3D(0, 0, 1000), new Vector(0, 0, -1), new Vector(0, 1, 0)) //
+ .setViewPlaneSize(200, 200) //
+ .setVpDistance(1000);
+
+ private static Geometry triangle1 = new Triangle( //
+ new Point3D(-150, -150, -150), new Point3D(150, -150, -150), new Point3D(75, 75, -150));
+ private static Geometry triangle2 = new Triangle( //
+ new Point3D(-150, -150, -150), new Point3D(-70, 70, -50), new Point3D(75, 75, -150));
+ private static Geometry sphere = new Sphere(50, new Point3D(0, 0, -50)) //
+ .setEmission(new Color(java.awt.Color.BLUE)) //
+ .setMaterial(new Material().setkD(0.5).setkS(0.5).setnShininess(100));
+
+ /**
+ * Produce a picture of a sphere lighted by a directional light
+ */
+ @Test
+ public void sphereDirectional() {
+ scene1.geometries.add(sphere);
+ scene1.lights.add(new DirectionalLight(new Color(500, 300, 0), new Vector(1, 1, -1)));
+
+ ImageWriter imageWriter = new ImageWriter("sphereDirectional", 500, 500);
+ Render render = new Render()//
+ .setImageWriter(imageWriter) //
+ .setScene(scene1) //
+ .setCamera(camera1) //
+ .setRayTracer(new RayTracerBasic(scene1));
+ render.renderImage();
+ render.writeToImage();
+ }
+
+ /**
+ * Produce a picture of a sphere lighted by a point light
+ */
+ @Test
+ public void spherePoint() {
+ scene1.geometries.add(sphere);
+ scene1.lights.add(new PointLight(new Color(500, 300, 0), new Point3D(-50, -50, 50), 1, 0.00001, 0.000001));
+
+ ImageWriter imageWriter = new ImageWriter("spherePoint", 500, 500);
+ Render render = new Render()//
+ .setImageWriter(imageWriter) //
+ .setScene(scene1) //
+ .setCamera(camera1) //
+ .setRayTracer(new RayTracerBasic(scene1));
+ render.renderImage();
+ render.writeToImage();
+ }
+
+ /**
+ * Produce a picture of a sphere lighted by a spot light
+ */
+ @Test
+ public void sphereSpot() {
+ scene1.geometries.add(sphere);
+ scene1.lights.add(new SpotLight(new Color(500, 300, 0), new Point3D(-50, -50, 50), new Vector(1, 1, -2), 1,
+ 0.00001, 0.00000001));
+
+ ImageWriter imageWriter = new ImageWriter("sphereSpot", 500, 500);
+ Render render = new Render()//
+ .setImageWriter(imageWriter) //
+ .setScene(scene1) //
+ .setCamera(camera1) //
+ .setRayTracer(new RayTracerBasic(scene1));
+ render.renderImage();
+ render.writeToImage();
+ }
+
+ /**
+ * Produce a picture of a two triangles lighted by a directional light
+ */
+ @Test
+ public void trianglesDirectional() {
+ scene2.geometries.add(triangle1.setMaterial(new Material().setkD(0.8).setkS(0.2).setnShininess(300)), //
+ triangle2.setMaterial(new Material().setkD(0.8).setkS(0.2).setnShininess(300)));
+ scene2.lights.add(new DirectionalLight(new Color(300, 150, 150), new Vector(0, 0, -1)));
+
+ ImageWriter imageWriter = new ImageWriter("trianglesDirectional", 500, 500);
+ Render render = new Render()//
+ .setImageWriter(imageWriter) //
+ .setScene(scene2) //
+ .setCamera(camera2) //
+ .setRayTracer(new RayTracerBasic(scene2));
+ render.renderImage();
+ render.writeToImage();
+ }
+
+ /**
+ * Produce a picture of a two triangles lighted by a point light
+ */
+ @Test
+ public void trianglesPoint() {
+ scene2.geometries.add(triangle1.setMaterial(new Material().setkD(0.5).setkS(0.5).setnShininess(300)), //
+ triangle2.setMaterial(new Material().setkD(0.5).setkS(0.5).setnShininess(300)));
+ scene2.lights.add(new PointLight(new Color(500, 250, 250), new Point3D(10, -10, -130), 1, 0.0005, 0.0005));
+
+ ImageWriter imageWriter = new ImageWriter("trianglesPoint", 500, 500);
+ Render render = new Render()//
+ .setImageWriter(imageWriter) //
+ .setScene(scene2) //
+ .setCamera(camera2) //
+ .setRayTracer(new RayTracerBasic(scene2));
+ render.renderImage();
+ render.writeToImage();
+ }
+
+ /**
+ * Produce a picture of a two triangles lighted by a spot light
+ */
+ @Test
+ public void trianglesSpot() {
+ scene2.geometries.add(triangle1.setMaterial(new Material().setkD(0.5).setkS(0.5).setnShininess(300)),
+ triangle2.setMaterial(new Material().setkD(0.5).setkS(0.5).setnShininess(300)));
+ scene2.lights.add(new SpotLight(new Color(500, 250, 250), new Point3D(10, -10, -130), new Vector(-2, -2, -1), 1,
+ 0.0001, 0.000005));
+
+ ImageWriter imageWriter = new ImageWriter("trianglesSpot", 500, 500);
+ Render render = new Render()//
+ .setImageWriter(imageWriter) //
+ .setScene(scene2) //
+ .setCamera(camera2) //
+ .setRayTracer(new RayTracerBasic(scene2));
+ render.renderImage();
+ render.writeToImage();
+ }
+
+ /* *//**
+ * Produce a picture of a sphere lighted by a narrow spot light
+ */
+ /*
+ * @Test public void sphereSpotSharp() { scene1.geometries.add(sphere);
+ * scene1.lights.add(new SpotLight(new Color(500, 300, 0), new Point3D(-50, -50,
+ * 50), new Vector(1, 1, -2), 1, 0.000005, 0.00000025, 5));
+ *
+ * ImageWriter imageWriter = new ImageWriter("sphereSpotSharp", 500, 500);
+ * Render render = new Render()// .setImageWriter(imageWriter) //
+ * .setScene(scene1) // .setCamera(camera1) // .setRayTracer(new
+ * RayTracerBasic(scene1)); render.renderImage(); render.writeToImage(); }
+ *
+ *//**
+ * Produce a picture of a two triangles lighted by a narrow spot light
+ */
+ /*
+ * @Test public void trianglesSpotSharp() {
+ * scene2.geometries.add(triangle1.setMaterial(new
+ * Material().setkD(0.5).setkS(0.5).setnShininess(300)),
+ * triangle2.setMaterial(new
+ * Material().setkD(0.5).setkS(0.5).setnShininess(300))); scene2.lights.add(new
+ * SpotLight(new Color(800, 400, 400), new Point3D(10, -10, -130), new
+ * Vector(-2, -2, -1), 1, 0.00005, 0.0000025, 5));
+ *
+ * ImageWriter imageWriter = new ImageWriter("trianglesSpotSharp", 500, 500);
+ * Render render = new Render()// .setImageWriter(imageWriter) //
+ * .setScene(scene2) // .setCamera(camera2) // .setRayTracer(new
+ * RayTracerBasic(scene2)); render.renderImage(); render.writeToImage(); }
+ *
+ */}
diff --git a/src/unittests/primitives/RayTests.java b/src/unittests/primitives/RayTests.java
index 50449b0..cd52412 100644
--- a/src/unittests/primitives/RayTests.java
+++ b/src/unittests/primitives/RayTests.java
@@ -67,4 +67,10 @@
}
+
+ /**
+ * Test method for {@link primitives.Ray#findClosestPoint(java.util.List)}.
+ */
+ @Test
+ public void testGetClosestGeoPoint() {}
}
diff --git a/src/unittests/renderer/ImageWriterTest.java b/src/unittests/renderer/ImageWriterTest.java
index b85d9b6..dd4371d 100644
--- a/src/unittests/renderer/ImageWriterTest.java
+++ b/src/unittests/renderer/ImageWriterTest.java
@@ -3,7 +3,6 @@
*/
package unittests.renderer;
-
import org.junit.Test;
import renderer.ImageWriter;
@@ -24,21 +23,22 @@
public void writeImageTest() {
ImageWriter picture = new ImageWriter("test blue", 800, 500);
-
- //A loop that passes over the view plane and creates an image in one color
- //and a grid of lines in a second color
+
+ // A loop that passes over the view plane and creates an image in one color
+ // and a grid of lines in a second color
for (int i = 0; i < 800; i++) {
- for (int j = 0; j <500; j++) {
- if (i % 50 == 0) {//for rows
- //Writing pixel for grid
- picture.writePixel(i, j, new Color(255, 0, 255));
- }
- else if (j % 50== 0) {//for columns
- //Writing pixel for grid
+ for (int j = 0; j < 500; j++) {
+ if (i % 50 == 0) {// for rows
+ // Writing pixel for grid
picture.writePixel(i, j, new Color(255, 0, 255));
- }
+ }
+
+ else if (j % 50== 0) {//for columns
+ //Writing pixel for grid
+ picture.writePixel(i, j, new Color(255, 0, 255)); }
+
else {
- //Writing blue pixel
+ // Writing blue pixel
picture.writePixel(i, j, new Color(0, 0, 255));
}
}
diff --git a/src/unittests/renderer/RenderTests.java b/src/unittests/renderer/RenderTests.java
index f5386cc..3adbd0f 100644
--- a/src/unittests/renderer/RenderTests.java
+++ b/src/unittests/renderer/RenderTests.java
@@ -1,6 +1,17 @@
package unittests.renderer;
+import java.io.IOException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
import elements.*;
import geometries.*;
@@ -8,15 +19,13 @@
import renderer.*;
import scene.Scene;
-
-
/**
* Test rendering a basic image
*
* @author Dan
*/
public class RenderTests {
- private Camera camera = new Camera(Point3D.ZERO, new Vector(0, 0, -1), new Vector(0, -1, 0)) //
+ private Camera camera = new Camera(Point3D.ZERO, new Vector(0, 0, -1), new Vector(0, 1, 0)) //
.setVpDistance(100) //
.setViewPlaneSize(500, 500);
@@ -38,8 +47,8 @@
// right
new Triangle(new Point3D(-100, 0, -100), new Point3D(0, -100, -100), new Point3D(-100, -100, -100)), // down
// left
- new Triangle(new Point3D(100, 0, -100), new Point3D(0, -100, -100), new Point3D(100, -100, -100))); // down
- // right
+ new Triangle(new Point3D(100, 0, -100), new Point3D(0, -100, -100), new Point3D(100, -100, -100))); // down
+ // right
ImageWriter imageWriter = new ImageWriter("base render test", 1000, 1000);
Render render = new Render() //
@@ -54,25 +63,65 @@
}
/**
-
- * Test for XML based scene - for bonus
+ *
+ * Test for XML based scene - for bonus
*
*
*/
+
/*
* @Test public void basicRenderXml() { Scene scene = new
* Scene("XML Test scene"); // enter XML file name and parse from XML file into
- * scene object //
+ * scene object // DocumentBuilderFactory
+ * factory=DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder=
+ * factory.newDocumentBuilder(); Document doc=builder.parse("scene.xml");
+ * NodeList geometriesList=doc.getElementsByTagName("geometries"); for(int i=0;
+ * i<geometriesList.getLength(); i++) { Node p=geometriesList.item(i);
+ * if(p.getNodeType()==Node.ELEMENT_NODE) { Element geometry=(Element) p; String
+ * radius=geometry.getAttribute("radius"); NodeList
+ * nameList=geometry.getChildNodes(); for(int j=0;j<nameList.getLength();j++) {
+ * Node n= nameList.item(j); if(n.getNodeType()==Node.ELEMENT_NODE) { Element
+ * name=(Element) n; System.out.println("geometries "+radius+":"+
+ * name.getTagName()+"="+name.getAttribute("radius")); } }
*
+ * }
+ *
+ * } } catch (ParserConfigurationException e) { // TODO Auto-generated catch
+ * block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated
+ * catch block e.printStackTrace(); } catch (IOException e) { // TODO
+ * Auto-generated catch block e.printStackTrace(); }
*
* ImageWriter imageWriter = new ImageWriter("xml render test", 1000, 1000);
- * Render render = new Render() // .setImageWriter(imageWriter) //
- * .setScene(scene) // .setCamera(camera) // .setRayTracer(new
- * RayTracerBasic(scene));
+ * Render render = new Render() .setImageWriter(imageWriter) .setScene(scene)
+ * .setCamera(camera) .setRayTracer(new RayTracerBasic(scene));
*
* render.renderImage(); render.printGrid(100, new
* Color(java.awt.Color.YELLOW)); render.writeToImage(); }
*/
+ @Test
+ public void basicRenderMultiColorTest() {
+ Scene scene = new Scene("Test scene")//
+ .setAmbientLight(new AmbientLight(new Color(java.awt.Color.WHITE), 0.2)); //
+ scene.geometries.add(new Sphere(50, new Point3D(0, 0, -100)), //
+ new Triangle(new Point3D(-100, 0, -100), new Point3D(0, 100, -100), new Point3D(-100, 100, -100)) // up left
+ .setEmission(new Color(java.awt.Color.GREEN)),
+ new Triangle(new Point3D(100, 0, -100), new Point3D(0, 100, -100), new Point3D(100, 100, -100)), // up right
+ new Triangle(new Point3D(-100, 0, -100), new Point3D(0, -100, -100), new Point3D(-100, -100, -100)) // down left
+ .setEmission(new Color(java.awt.Color.RED)),
+ new Triangle(new Point3D(100, 0, -100), new Point3D(0, -100, -100), new Point3D(100, -100, -100)) // down right
+ .setEmission(new Color(java.awt.Color.BLUE)));
+
+ ImageWriter imageWriter = new ImageWriter("color render test", 1000, 1000);
+ Render render = new Render() //
+ .setImageWriter(imageWriter) //
+ .setScene(scene) //
+ .setCamera(camera) //
+ .setRayTracer(new RayTracerBasic(scene));
+
+ render.renderImage();
+ render.printGrid(100, new Color(java.awt.Color.WHITE));
+ render.writeToImage();
+ }
}