diff --git a/EVI - 2017/EVI 12/EVI_12 - Subsumption.pdf b/EVI - 2017/EVI 12/EVI_12 - Subsumption.pdf
new file mode 100644
index 0000000..876c927
Binary files /dev/null and b/EVI - 2017/EVI 12/EVI_12 - Subsumption.pdf differ
diff --git a/EVI - 2017/EVI 12/Examples/Arbitrator.java b/EVI - 2017/EVI 12/Examples/Arbitrator.java
new file mode 100644
index 0000000..37d34c5
--- /dev/null
+++ b/EVI - 2017/EVI 12/Examples/Arbitrator.java
@@ -0,0 +1,140 @@
+package lejos.robotics.subsumption;
+
+
+/**
+ * Arbitrator controls which Behavior object will become active in
+ * a behavior control system. Make sure to call start() after the
+ * Arbitrator is instantiated.
+ * This class has three major responsibilities:
+ * 1. Determine the highest priority behavior that returns true to takeControl()
+ * 2. Suppress the active behavior if its priority is less than highest
+ * priority.
+ * 3. When the action() method exits, call action() on the Behavior of highest priority.
+ *
The Arbitrator assumes that a Behavior is no longer active when action() exits,
+ *
therefore it will only call suppress() on the Behavior whose action() method is running.
+ *
It can make consecutive calls of action() on the same Behavior.
+ *
Requirements for a Behavior:
+ *
When suppress() is called, terminate action() immediately.
+ *
When action() exits, the robot is in a safe state (e.g. motors stopped)
+ * @see Behavior
+ * @author Roger Glassey
+ */
+public class Arbitrator
+{
+
+ private final int NONE = -1;
+ private Behavior[] _behavior;
+ // highest priority behavior that wants control ; set by start() usec by monitor
+ private int _highestPriority = NONE;
+ private int _active = NONE; // active behavior; set by montior, used by start();
+ private boolean _returnWhenInactive;
+ /**
+ * Monitor is an inner class. It polls the behavior array to find the behavior of hightst
+ * priority. If higher than the active behavior, it calls active.suppress()
+ */
+ private Monitor monitor;
+
+ /**
+ * Allocates an Arbitrator object and initializes it with an array of
+ * Behavior objects. The index of a behavior in this array is its priority level, so
+ * the behavior of the largest index has the highest the priority level.
+ * The behaviors in an Arbitrator can not
+ * be changed once the arbitrator is initialized.
+ * NOTE: Once the Arbitrator is initialized, the method start() must be
+ * called to begin the arbitration.
+ * @param behaviorList an array of Behavior objects.
+ * @param returnWhenInactive if true, the start() method returns when no Behavior is active.
+ */
+ public Arbitrator(Behavior[] behaviorList, boolean returnWhenInactive)
+ {
+ _behavior = behaviorList;
+ _returnWhenInactive = returnWhenInactive;
+ monitor = new Monitor();
+ monitor.setDaemon(true);
+ }
+
+ /**
+ * Same as Arbitrator(behaviorList, false) Arbitrator start() never exits
+ * @param behaviorList An array of Behavior objects.
+ */
+ public Arbitrator(Behavior[] behaviorList)
+ {
+ this(behaviorList, false);
+ }
+
+ /**
+ * This method starts the arbitration of Behaviors and runs an endless loop.
+ * Note: Arbitrator does not run in a separate thread. The start()
+ * method will never return unless
1. no action() method is running and
+ *
2. no behavior takeControl()
+ * returns true and
3. the returnWhenInacative flag is true,
+ */
+ public void start()
+ {
+ monitor.start();
+ while (_highestPriority == NONE)
+ {
+ Thread.yield();//wait for some behavior to take contro
+ }
+ while (true)
+ {
+ synchronized (monitor)
+ {
+ if (_highestPriority != NONE)
+ {
+ _active = _highestPriority;
+
+ } else if (_returnWhenInactive)
+ {// no behavior wants to run
+ monitor.more = false;//9 shut down monitor thread
+ return;
+ }
+ }// monotor released before action is called
+ if (_active != NONE) //_highestPrioirty could be NONE
+ {
+ _behavior[_active].action();
+ _active = NONE; // no active behavior at the moment
+ }
+ Thread.yield();
+ }
+ }
+
+ /**
+ * Finds the highest priority behavior that returns true to takeControl();
+ * If this priority is higher than the active behavior, it calls active.suppress().
+ * If there is no active behavior, calls suppress() on the most recently acrive behavior.
+ */
+ private class Monitor extends Thread
+ {
+
+ boolean more = true;
+ int maxPriority = _behavior.length - 1;
+
+ public void run()
+ {
+ while (more)
+ {
+ //FIND HIGHEST PRIORITY BEHAVIOR THAT WANTS CONTROL
+ synchronized (this)
+ {
+ _highestPriority = NONE;
+ for (int i = maxPriority; i >= 0; i--)
+ {
+ if (_behavior[i].takeControl())
+ {
+ _highestPriority = i;
+ break;
+ }
+ }
+ int active = _active;// local copy: avoid out of bounds error in 134
+ if (active != NONE && _highestPriority > active)
+ {
+ _behavior[active].suppress();
+ }
+ }// end synchronize block - main thread can run now
+ Thread.yield();
+ }
+ }
+ }
+}
+
diff --git a/EVI - 2017/EVI 12/Examples/Behavior.java b/EVI - 2017/EVI 12/Examples/Behavior.java
new file mode 100644
index 0000000..fc2d2f7
--- /dev/null
+++ b/EVI - 2017/EVI 12/Examples/Behavior.java
@@ -0,0 +1,55 @@
+package lejos.robotics.subsumption;
+
+
+/**
+* The Behavior interface represents an object embodying a specific
+* behavior belonging to a robot. Each behavior must define three things:
+* 1) The circumstances to make this behavior seize control of the robot.
+* e.g. When the touch sensor determines the robot has collided with an object.
+* 2) The action to perform when this behavior takes control.
+* e.g. Back up and turn.
+* 3) A way to quickly exit from the action when the Arbitrator selects a higher
+ * priority behavior to take control.
+* These are represented by defining the methods takeControl(), action(),
+* and suppress() respectively.
+* A behavior control system has one or more Behavior objects. When you have defined
+* these objects, create an array of them and use that array to initialize an
+* Arbitrator object.
+*
+* @see Arbitrator
+
+* @version 0.9 May 2011
+*/
+public interface Behavior {
+
+ /**
+ * The boolean return indicates if this behavior should seize control of the robot.
+ * For example, a robot that reacts if a touch sensor is pressed:
+ * public boolean takeControl() {
+ * return touch.isPressed();
+ * }
+ * @return boolean Indicates if this Behavior should seize control.
+ */
+ public boolean takeControl();
+
+ /**
+ * The code in action() represents the tasks the robot performs when this
+ * behavior becomes active. It can be as complex as navigating around a
+ * room, or as simple as playing a tune.
+ * The contract for implementing this method is:
+ * If its task is is complete, the method returns.
+ * It also must return promptly when the suppress() method
+ * is called, for example by testing the boolean suppress flag.
+ * When this method exits, the robot is in a safe state for another behavior
+ * to run its action() method
+ */
+ public void action();
+
+ /**
+ * The code in suppress() should cause the current behavior to exit.
+ * The contract for implementing this method is:
+ * Exit quickly, for example, just set boolean flag.
+ */
+ public void suppress();
+
+}
\ No newline at end of file
diff --git a/EVI - 2017/EVI 12/Examples/SubsumpRobot.java b/EVI - 2017/EVI 12/Examples/SubsumpRobot.java
new file mode 100644
index 0000000..ab2f7ea
--- /dev/null
+++ b/EVI - 2017/EVI 12/Examples/SubsumpRobot.java
@@ -0,0 +1,120 @@
+package miky;
+import robocode.*;
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * SubsumpRobot - a robot by (your name here)
+ */
+public class SubsumpRobot extends Robot {
+ abstract class SubsumptionBehavior {
+ public abstract boolean takeControl();
+ public abstract void action();
+ }
+
+ class WanderBehavior extends SubsumptionBehavior {
+ public boolean takeControl() {
+ return true;
+ }
+
+ public void action() {
+ ahead(200);
+ if (Math.random() > 0.5)
+ turnLeft(30.0);
+ else
+ turnRight(30.0);
+ scan();
+ }
+ }
+
+ class MoveToRobotBehavior extends SubsumptionBehavior {
+ public boolean takeControl() {
+ return scannedRobot != null;
+ }
+
+ public void action() {
+ turnRight(scannedRobot.getBearing());
+ ahead(50);
+ }
+ }
+
+ class FireBehavior extends SubsumptionBehavior {
+ public boolean takeControl() {
+ return scannedRobot != null && scannedRobot.getDistance() < 200;
+ }
+
+ public void action() {
+ fire(3);
+ }
+ }
+
+ class AvoidWallBehavior extends SubsumptionBehavior {
+ public boolean takeControl() {
+ return hitEvent != null;
+ }
+
+ public void action() {
+ hitEvent = null;
+ scannedRobot = null;
+ back(100);
+ turnLeft(180.0);
+ }
+ }
+
+ private List behaviors;
+ private ScannedRobotEvent scannedRobot;
+ private Event hitEvent;
+
+ public SubsumpRobot() {
+ super();
+ hitEvent = null;
+ scannedRobot = null;
+ behaviors = new LinkedList();
+ }
+
+ public void addBehavior(SubsumptionBehavior behavior) {
+ behaviors.add(behavior);
+ }
+
+ public void removeBehavior(SubsumptionBehavior behavior) {
+ behaviors.remove(behavior);
+ }
+
+ /**
+ * run: SubsumpRobot's default behavior
+ */
+ public void run() {
+ int behavior_index = 0;
+
+ // Add behaviors.
+ behaviors.add(new AvoidWallBehavior());
+ behaviors.add(new FireBehavior());
+ behaviors.add(new MoveToRobotBehavior());
+ behaviors.add(new WanderBehavior());
+
+ while(true) {
+ for (SubsumptionBehavior b : behaviors) {
+ if (b.takeControl()) {
+ b.action();
+ break;
+ }
+ }
+ }
+ }
+
+ public void onScannedRobot(ScannedRobotEvent e) {
+ scannedRobot = e;
+ }
+
+ public void onHitWall(HitWallEvent e) {
+ hitEvent = e;
+ }
+
+ public void onHitRobot(HitRobotEvent e) {
+ hitEvent = e;
+ }
+
+ public void onRobotDeath(RobotDeathEvent e) {
+ scannedRobot = null;
+ }
+}
diff --git a/EVI - 2017/EVI 21/EVI_21 - Raytracing.pdf b/EVI - 2017/EVI 21/EVI_21 - Raytracing.pdf
new file mode 100644
index 0000000..ed3fa4c
Binary files /dev/null and b/EVI - 2017/EVI 21/EVI_21 - Raytracing.pdf differ
diff --git a/EVI - 2017/EVI 21/EVIray/Makefile b/EVI - 2017/EVI 21/EVIray/Makefile
new file mode 100644
index 0000000..4343a9c
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/Makefile
@@ -0,0 +1,30 @@
+CXX = g++
+TARGET = ray
+OBJECTS = main.o sampling.o camera.o plane.o sphere.o \
+ phong_brdf.o directional_light.o point_light.o \
+ spot_light.o sphere_area_light.o scene.o tracer.o \
+ path_tracer.o whitted_tracer.o
+DEPENDS = $(OBJECTS:.o=.d)
+CXXFLAGS = -std=c++11 -pedantic -Wall -DGLM_FORCE_RADIANS -DUSE_CPP11_RANDOM -fno-builtin
+LDLIBS = -lfreeimage -ljson_spirit
+
+.PHONY: all
+all: CXXFLAGS += -O3 -DNDEBUG
+all: $(TARGET)
+
+.PHONY: debug
+debug: CXXFLAGS += -g
+debug: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+ $(CXX) -o $@ $^ $(CXXFLAGS) $(LDLIBS)
+
+-include $(DEPENDS)
+
+%.o: %.cpp
+ $(CXX) -c $(CXXFLAGS) $*.cpp -o $*.o
+ $(CXX) -MM $(CXXFLAGS) $*.cpp > $*.d
+
+.PHONY: clean
+clean:
+ $(RM) $(TARGET) $(OBJECTS) $(DEPENDS)
diff --git a/EVI - 2017/EVI 21/EVIray/area_light.hpp b/EVI - 2017/EVI 21/EVIray/area_light.hpp
new file mode 100644
index 0000000..0aa4a66
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/area_light.hpp
@@ -0,0 +1,90 @@
+#pragma once
+#ifndef AREA_LIGHT_HPP
+#define AREA_LIGHT_HPP
+
+#include "light.hpp"
+
+using glm::length;
+using glm::normalize;
+using glm::dot;
+
+class AreaLight: public Light {
+public:
+ float m_const_att;
+ float m_lin_att;
+ float m_quad_att;
+ Figure * m_figure;
+
+ AreaLight():
+ Light(AREA),
+ m_const_att(1.0),
+ m_lin_att(0.0),
+ m_quad_att(0.0),
+ m_figure(NULL),
+ m_last_sample(vec3()),
+ m_n_at_last_sample(vec3())
+ { }
+
+ AreaLight(Figure * _f, float _c = 1.0, float _l = 0.0, float _q = 0.0):
+ Light(AREA),
+ m_const_att(_c),
+ m_lin_att(_l),
+ m_quad_att(_q),
+ m_figure(_f),
+ m_last_sample(vec3()),
+ m_n_at_last_sample(vec3())
+ { }
+
+ virtual vec3 direction(vec3 point) const {
+ return normalize(m_last_sample - point);
+ }
+
+ virtual float distance(vec3 point) const {
+ return length(m_last_sample - point);
+ }
+
+ vec3 diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const {
+ float d, att, ln_dot_d, d2, g;
+ vec3 l_dir, ref;
+
+ l_dir = normalize(direction(i_pos));
+ ln_dot_d = dot(m_n_at_last_sample, l_dir);
+ if (ln_dot_d > 0.0f) {
+ d2 = distance(i_pos);
+ d2 *= d2;
+ g = ln_dot_d / d2;
+ d = distance(i_pos);
+ att = 1.0f / (m_const_att + (m_lin_att * d) + (m_quad_att * (d * d)));
+ return (att * m.m_brdf->diffuse(l_dir, normal, r, i_pos, m_figure->m_mat->m_emission) * g) / m_figure->pdf();
+
+ } else
+ return vec3(0.0f);
+ }
+
+ vec3 specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const {
+ float d, att, ln_dot_d;
+ vec3 l_dir, ref;
+
+ l_dir = normalize(direction(i_pos));
+ ln_dot_d = dot(m_n_at_last_sample, l_dir);
+ if (ln_dot_d > 0.0f) {
+ d = distance(i_pos);
+ att = 1.0f / (m_const_att + (m_lin_att * d) + (m_quad_att * (d * d)));
+ return (att * m.m_brdf->specular(l_dir, normal, r, i_pos, m_figure->m_mat->m_emission, m.m_shininess)) / m_figure->pdf();
+
+ } else
+ return vec3(0.0f);
+ }
+
+ virtual vec3 normal_at_last_sample() {
+ return m_n_at_last_sample;
+ }
+
+ virtual vec3 sample_at_surface() = 0;
+
+protected:
+ vec3 m_last_sample;
+ vec3 m_n_at_last_sample;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/brdf.hpp b/EVI - 2017/EVI 21/EVIray/brdf.hpp
new file mode 100644
index 0000000..5b8831e
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/brdf.hpp
@@ -0,0 +1,19 @@
+#pragma once
+#ifndef BRDF_HPP
+#define BRDF_HPP
+
+#include
+
+#include "ray.hpp"
+
+using glm::vec3;
+
+class BRDF {
+public:
+ virtual ~BRDF() { }
+
+ virtual vec3 diffuse(vec3 light_dir, vec3 surface_normal, Ray & incident_ray, vec3 intersection_point, vec3 light_diff_color) const = 0;
+ virtual vec3 specular(vec3 light_dir, vec3 surface_normal, Ray & incident_ray, vec3 intersection_point, vec3 light_spec_color, float shininess) const = 0;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/camera.cpp b/EVI - 2017/EVI 21/EVIray/camera.cpp
new file mode 100644
index 0000000..c52c43d
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/camera.cpp
@@ -0,0 +1,74 @@
+#include
+
+#include "camera.hpp"
+
+using glm::vec4;
+using glm::rotate;
+using glm::radians;
+using glm::cross;
+
+void Camera::reset() {
+ // Recalculate look at and invert it.
+ m_inv_view_matrix = inverse(lookAt(m_eye, m_look, m_up));
+}
+
+void Camera::translate(vec3 t) {
+ // Create a translation matrix.
+ mat4 t_matrix = glm::translate(mat4(1.0f), t);
+
+ // Compute new eye and look at position (in homogeneous coordinates).
+ vec4 new_eye = t_matrix * vec4(m_eye, 1.0f);
+ vec4 new_look = t_matrix * vec4(m_look, 1.0f);
+
+ // Set new eye and look at.
+ m_eye = vec3(new_eye.x, new_eye.y, new_eye.z);
+ m_look = vec3(new_look.x, new_look.y, new_look.z);
+
+ // Recalculate the view matrix.
+ reset();
+}
+
+void Camera::pitch(float angle) {
+ // Calculate view direction and left vector.
+ vec3 view_dir = normalize(m_look - m_eye);
+ vec3 left = cross(view_dir, m_up);
+
+ // Rotate the view direction.
+ view_dir = rotate(view_dir, radians(angle), left);
+
+ // Rotate the up vector
+ m_up = normalize(rotate(m_up, radians(angle), left));
+
+ // Compute new look at.
+ m_look = m_eye + view_dir;
+
+ // Recalculate the view matrix.
+ reset();
+}
+
+void Camera::yaw(float angle) {
+ // Compute and rotate the view direction.
+ vec3 view_dir = rotate(normalize(m_look - m_eye), radians(angle), m_up);
+
+ // Compute new look at.
+ m_look = m_eye + view_dir;
+
+ // Recalculate the view matrix.
+ reset();
+}
+
+void Camera::roll(float angle) {
+ // Rotate the up vector.
+ m_up = normalize(rotate(m_up, radians(angle), normalize(m_look - m_eye)));
+
+ // Recalculate the view matrix.
+ reset();
+}
+
+void Camera::view_to_world(Ray & r) const {
+ vec4 dir = m_inv_view_matrix * vec4(r.m_direction, 0.0f);
+ vec4 orig = m_inv_view_matrix * vec4(r.m_origin, 1.0f);
+
+ r.m_direction = vec3(dir.x, dir.y, dir.z);
+ r.m_origin = vec3(orig.x, orig.y, orig.z);
+}
diff --git a/EVI - 2017/EVI 21/EVIray/camera.hpp b/EVI - 2017/EVI 21/EVIray/camera.hpp
new file mode 100644
index 0000000..4e1d02e
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/camera.hpp
@@ -0,0 +1,71 @@
+#pragma once
+#ifndef CAMERA_HPP
+#define CAMERA_HPP
+
+#include
+#include
+
+#include "ray.hpp"
+
+using glm::mat4;
+using glm::vec2;
+using glm::vec3;
+using glm::normalize;
+using glm::lookAt;
+using glm::inverse;
+
+// Camera vector disposition:
+// up^
+// |
+// |
+// eye)-------->* look
+//
+class Camera {
+public:
+ vec3 m_eye; // Eye position.
+ vec3 m_look; // Look-up position.
+ vec3 m_up; // Up vector.
+
+ Camera(vec3 _e = vec3(0.0f), vec3 _l = vec3(0.0f, 0.0f, -1.0f), vec3 _u = vec3(0.0f, 1.0f, 0.0f)):
+ m_eye(_e),
+ m_look(_l),
+ m_up(normalize(_u)),
+ m_inv_view_matrix(inverse(lookAt(_e, _l, normalize(_u))))
+ { }
+
+ /**
+ * Restores the view matrix undoing any transformation.
+ */
+ void reset();
+
+ /**
+ * Translate the eye position.
+ */
+ void translate(vec3 t);
+
+ /**
+ * Rotate view direction around left vector (cross product of up vector and view direction).
+ */
+ void pitch(float angle);
+
+ /**
+ * Rotate view direction around up vector.
+ */
+ void yaw(float angle);
+
+ /**
+ * Rotate up vector around view direction.
+ */
+ void roll(float angle);
+
+ /**
+ * Apply the inverse view matrix to a ray to take it from view space to world space.
+ */
+ void view_to_world(Ray & r) const;
+
+private:
+ // Inverse view matrix.
+ mat4 m_inv_view_matrix;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/directional_light.cpp b/EVI - 2017/EVI 21/EVIray/directional_light.cpp
new file mode 100644
index 0000000..7f9f38b
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/directional_light.cpp
@@ -0,0 +1,29 @@
+#include
+
+#include
+#include
+
+#include "directional_light.hpp"
+
+using std::numeric_limits;
+using glm::pi;
+using glm::reflect;
+using glm::dot;
+using glm::pow;
+using glm::max;
+
+vec3 DirectionalLight::direction(vec3 point) const {
+ return m_position;
+}
+
+float DirectionalLight::distance(vec3 point) const {
+ return numeric_limits::max();
+}
+
+vec3 DirectionalLight::diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const {
+ return m.m_brdf->diffuse(m_position, normal, r, i_pos, m_diffuse);
+}
+
+vec3 DirectionalLight::specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const {
+ return m.m_brdf->specular(m_position, normal, r, i_pos, m_specular, m.m_shininess);
+}
diff --git a/EVI - 2017/EVI 21/EVIray/directional_light.hpp b/EVI - 2017/EVI 21/EVIray/directional_light.hpp
new file mode 100644
index 0000000..4794006
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/directional_light.hpp
@@ -0,0 +1,23 @@
+#pragma once
+#ifndef DIRECTIONAL_LIGHT_HPP
+#define DIRECTIONAL_LIGHT_HPP
+
+#include
+
+#include "light.hpp"
+
+using glm::normalize;
+
+class DirectionalLight: public InfinitesimalLight {
+public:
+ DirectionalLight(): InfinitesimalLight() { }
+
+ DirectionalLight(vec3 _p, vec3 _d, vec3 _s): InfinitesimalLight(normalize(_p), _d, _s) { }
+
+ virtual vec3 direction(vec3 point) const;
+ virtual float distance(vec3 point) const;
+ virtual vec3 diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const;
+ virtual vec3 specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/environment.hpp b/EVI - 2017/EVI 21/EVIray/environment.hpp
new file mode 100644
index 0000000..5bc3906
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/environment.hpp
@@ -0,0 +1,26 @@
+#pragma once
+#ifndef ENVIRONMENT_HPP
+#define ENVIRONMENT_HPP
+
+#include
+#include
+
+#include "ray.hpp"
+
+using glm::vec3;
+
+class Environment {
+public:
+ Environment(vec3 bckg = vec3(1.0f)): m_bckg_color(bckg) { }
+
+ ~Environment() { }
+
+ vec3 get_color(Ray & r) {
+ return m_bckg_color;
+ }
+
+private:
+ vec3 m_bckg_color;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/figure.hpp b/EVI - 2017/EVI 21/EVIray/figure.hpp
new file mode 100644
index 0000000..b544984
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/figure.hpp
@@ -0,0 +1,38 @@
+#pragma once
+#ifndef FIGURE_HPP
+#define FIGURE_HPP
+
+#include
+
+#include "ray.hpp"
+#include "material.hpp"
+
+using glm::vec3;
+
+class Figure {
+public:
+ Material * m_mat;
+
+ Figure(Material * mat = NULL): m_inv_area(0.0f) {
+ m_mat = mat == NULL ? new Material() : mat;
+ }
+
+ virtual ~Figure() {
+ delete m_mat;
+ }
+
+ virtual float pdf() const {
+ return m_inv_area;
+ }
+
+ virtual bool intersect(Ray & r, float & t) const = 0;
+ virtual vec3 normal_at_int(Ray & r, float & t) const = 0;
+ virtual vec3 sample_at_surface() const = 0;
+
+protected:
+ float m_inv_area;
+
+ virtual void calculate_inv_area() = 0;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/light.hpp b/EVI - 2017/EVI 21/EVIray/light.hpp
new file mode 100644
index 0000000..693c07e
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/light.hpp
@@ -0,0 +1,54 @@
+#pragma once
+#ifndef LIGHT_HPP
+#define LIGHT_HPP
+
+#include
+
+#include "figure.hpp"
+#include "material.hpp"
+#include "ray.hpp"
+
+using glm::vec3;
+
+class Light {
+public:
+ typedef enum LIGHT_TYPE { INFINITESIMAL = 0, AREA } ltype_t;
+
+ vec3 m_position;
+ vec3 m_diffuse;
+ vec3 m_specular;
+
+ Light(): m_position(vec3(0.0f)), m_diffuse(vec3(1.0f)), m_specular(vec3(1.0f)) { }
+
+ Light(ltype_t _t): m_position(vec3(0.0f)), m_diffuse(vec3(1.0f)), m_specular(vec3(1.0f)), m_type(_t) { }
+
+ Light(vec3 _p, vec3 _d, vec3 _s, ltype_t _t): m_position(_p), m_diffuse(_d), m_specular(_s), m_type(_t) { }
+
+ virtual ~Light() { }
+
+ virtual ltype_t light_type() {
+ return m_type;
+ }
+
+ virtual vec3 direction(vec3 point) const = 0;
+ virtual float distance(vec3 point) const = 0;
+ virtual vec3 diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const = 0;
+ virtual vec3 specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const = 0;
+
+protected:
+ ltype_t m_type;
+};
+
+class InfinitesimalLight: public Light {
+public:
+ InfinitesimalLight(): Light(INFINITESIMAL) { }
+
+ InfinitesimalLight(vec3 _p, vec3 _d, vec3 _s): Light(_p, _d, _s, INFINITESIMAL) { }
+
+ virtual vec3 direction(vec3 point) const = 0;
+ virtual float distance(vec3 point) const = 0;
+ virtual vec3 diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const = 0;
+ virtual vec3 specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const = 0;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/main.cpp b/EVI - 2017/EVI 21/EVIray/main.cpp
new file mode 100644
index 0000000..9aa4435
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/main.cpp
@@ -0,0 +1,375 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "sampling.hpp"
+#include "scene.hpp"
+#include "ray.hpp"
+#include "tracer.hpp"
+#include "path_tracer.hpp"
+#include "whitted_tracer.hpp"
+
+using namespace std;
+using namespace glm;
+
+////////////////////////////////////////////
+// Defines.
+////////////////////////////////////////////
+#define ANSI_BOLD_YELLOW "\x1b[1;33m"
+#define ANSI_RESET_STYLE "\x1b[m"
+#define MAX_W 1920
+#define MAX_H 1080
+
+////////////////////////////////////////////
+// Function prototypes.
+////////////////////////////////////////////
+static void print_usage(char ** const argv);
+static void parse_args(int argc, char ** const argv);
+
+////////////////////////////////////////////
+// Constants.
+////////////////////////////////////////////
+static const char * OUT_FILE = "output.png";
+
+////////////////////////////////////////////
+// Global variables.
+////////////////////////////////////////////
+typedef enum TRACERS { NONE, WHITTED, MONTE_CARLO } tracer_t;
+
+static char * g_input_file = NULL; // Input scene file name.
+static char * g_out_file_name = NULL; // Output image file name.
+static int g_samples = 25; // Samples per pixel.
+static float g_fov = 45.0f; // Camera field of view.
+static int g_w = 640; // Image width.
+static int g_h = 480; // Image height.
+static float g_a_ratio = 640.0f / 480.0f; // Image aspect ratio.
+static vec3 image[MAX_H][MAX_W]; // Image.
+static tracer_t g_tracer = NONE; // Ray tracer to use.
+static unsigned int g_max_depth = 5; // Max recursion depth.
+static float g_gamma = 2.2f; // Gamma correction factor.
+static float g_exposure = 0.0f; // Exposure correction factor.
+
+////////////////////////////////////////////
+// Main function.
+////////////////////////////////////////////
+int main(int argc, char ** argv) {
+ Ray r; // Primary ray.
+ vec2 sample; // Pixel sample position.
+ Tracer * tracer; // Tracer to use.
+ uint64_t total; // Total of samples to calculate;
+ uint64_t current = 0; // Samples calculated.
+ FIBITMAP * input_bitmap;
+ FIBITMAP * output_bitmap;
+ FREE_IMAGE_FORMAT fif;
+ BYTE * bits;
+ FIRGBF *pixel;
+ int pitch;
+ Scene * scn;
+
+ // Parse command line arguments.
+ parse_args(argc, argv);
+
+ // Initialize FreeImage.
+ FreeImage_Initialise();
+
+ // Try to read a scene file.
+ try {
+ scn = new Scene(g_input_file);
+ } catch (SceneError & e) {
+ cout << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ // Print run parameters.
+ cout << "Rendering the input file: " << ANSI_BOLD_YELLOW << g_input_file << ANSI_RESET_STYLE << endl;
+ cout << "The scene contains: " << endl;
+ cout << " " << ANSI_BOLD_YELLOW << scn->m_figures.size() << ANSI_RESET_STYLE << (scn->m_figures.size() != 1 ? " figures." : " figure.") << endl;
+ cout << " " << ANSI_BOLD_YELLOW << scn->m_lights.size() << ANSI_RESET_STYLE << " light " << (scn->m_lights.size() != 1 ? "sources." : "source.") << endl;
+ cout << "Output image resolution is " << ANSI_BOLD_YELLOW << g_w << "x" << g_h << ANSI_RESET_STYLE << " pixels." << endl;
+ cout << "Using " << ANSI_BOLD_YELLOW << g_samples << ANSI_RESET_STYLE << " samples per pixel." << endl;
+ cout << "Maximum ray tree depth is " << ANSI_BOLD_YELLOW << g_max_depth << ANSI_RESET_STYLE << "." << endl;
+
+ // Create the tracer object.
+ switch (g_tracer) {
+
+ // Basic recursive ray tracer.
+ case WHITTED:
+ cout << "Using " << ANSI_BOLD_YELLOW << "Whitted" << ANSI_RESET_STYLE << " ray tracing." << endl;
+ tracer = static_cast(new WhittedTracer(g_max_depth));
+ break;
+
+ // Monte Carlo path tracer.
+ case MONTE_CARLO:
+ cout << "Using " << ANSI_BOLD_YELLOW << "Monte Carlo" << ANSI_RESET_STYLE << " path tracing." << endl;
+ tracer = static_cast(new PathTracer(g_max_depth));
+ break;
+
+ // No tracer specified.
+ default:
+ cerr << "Must specify a ray tracer with \"-t\"." << endl;
+ print_usage(argv);
+ return EXIT_FAILURE;
+ }
+
+ // Generate the image.
+ // First calculate the number of samples to compute.
+ total = static_cast(g_h) * static_cast(g_w) * static_cast(g_samples);
+ cout << "Tracing a total of " << ANSI_BOLD_YELLOW << total << ANSI_RESET_STYLE << " primary rays:" << endl;
+
+ // Trace for every row of the image.
+ for (int i = 0; i < g_h; i++) {
+ // Trace for every column of the image.
+ for (int j = 0; j < g_w; j++) {
+ // Trace for every sample per pixel.
+ for (int k = 0; k < g_samples; k++) {
+ // Generate a pixel sample.
+ sample = sample_pixel(i, j, g_w, g_h, g_a_ratio, g_fov);
+ // Generate a primary ray.
+ r = Ray(normalize(vec3(sample, -0.5f) - vec3(0.0f)), // The direction of the ray is towards the sample in the image plane.
+ vec3(0.0f) // The origin of the ray is at the center of coordinates.
+ );
+ // Apply the inverse of the view matrix to take the primary ray from camera space to world space.
+ scn->m_cam->view_to_world(r);
+ // Trace the ray recursively.
+ image[i][j] += tracer->trace_ray(r, scn, 0);
+ // Add 1 to samples processed.
+ current++;
+ }
+ // Average the samples for this pixel.
+ image[i][j] /= g_samples;
+ }
+ cout << "\r" << ANSI_BOLD_YELLOW << current << ANSI_RESET_STYLE << " of " << ANSI_BOLD_YELLOW << total << ANSI_RESET_STYLE << " primary rays traced.";
+ }
+ cout << endl;
+
+ // Copy the pixels to the output bitmap.
+ cout << "Saving output image." << endl;
+ if (g_tracer == MONTE_CARLO) {
+ // Allocate an HDR image.
+ input_bitmap = FreeImage_AllocateT(FIT_RGBF, g_w, g_h, 96);
+
+ // Get image stride and pixels.
+ pitch = FreeImage_GetPitch(input_bitmap);
+ bits = (BYTE *)FreeImage_GetBits(input_bitmap);
+
+ // Fill every pixel of the temporary image with the traced image's.
+ for (unsigned int y = 0; y < FreeImage_GetHeight(input_bitmap); y++) {
+ pixel = (FIRGBF *)bits;
+ for (unsigned int x = 0; x < FreeImage_GetWidth(input_bitmap); x++) {
+ pixel[x].red = image[g_h - 1 - y][x].r;
+ pixel[x].green = image[g_h - 1 - y][x].g;
+ pixel[x].blue = image[g_h - 1 - y][x].b;
+ }
+ bits += pitch;
+ }
+
+ // If the tracer is the monte carlo path tracer, apply a tone mapping operator to reduce image range.
+ output_bitmap = FreeImage_ToneMapping(input_bitmap, FITMO_DRAGO03, g_gamma, g_exposure);
+
+ // Save the output image.
+ fif = FreeImage_GetFIFFromFilename(g_out_file_name != NULL ? g_out_file_name : OUT_FILE);
+ FreeImage_Save(fif, output_bitmap, g_out_file_name != NULL ? g_out_file_name : OUT_FILE);
+
+// Release the bitmaps.
+ FreeImage_Unload(input_bitmap);
+ FreeImage_Unload(output_bitmap);
+
+ } else {
+ // Allocate an RGB image.
+ input_bitmap = FreeImage_Allocate(g_w, g_h, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
+
+ // Get image stride and pixels.
+ pitch = FreeImage_GetLine(input_bitmap) / FreeImage_GetWidth(input_bitmap);
+ bits = (BYTE *)FreeImage_GetBits(input_bitmap);
+
+ // Fill every pixel of the temporary image with the traced image's.
+ for (unsigned int y = 0; y < FreeImage_GetHeight(input_bitmap); y++) {
+ bits = FreeImage_GetScanLine(input_bitmap, y);
+ for (unsigned int x = 0; x < FreeImage_GetWidth(input_bitmap); x++) {
+ bits[FI_RGBA_RED] = static_cast(image[g_h - 1 - y][x].r * 255.0f);
+ bits[FI_RGBA_GREEN] = static_cast(image[g_h - 1 - y][x].g * 255.0f);
+ bits[FI_RGBA_BLUE] = static_cast(image[g_h - 1 - y][x].b * 255.0f);
+ bits += pitch;
+ }
+ }
+
+ // Apply gamma correction.
+ FreeImage_AdjustGamma(input_bitmap, g_gamma);
+
+ // Save the output image.
+ fif = FreeImage_GetFIFFromFilename(g_out_file_name != NULL ? g_out_file_name : OUT_FILE);
+ FreeImage_Save(fif, input_bitmap, g_out_file_name != NULL ? g_out_file_name : OUT_FILE);
+
+ // Release the bitmaps.
+ FreeImage_Unload(input_bitmap);
+ }
+
+ // Clean up.
+ if (g_out_file_name != NULL)
+ free(g_out_file_name);
+
+ delete scn;
+ delete tracer;
+
+ // Close FreeImage.
+ FreeImage_DeInitialise();
+
+ return EXIT_SUCCESS;
+}
+
+////////////////////////////////////////////
+// Helper functions.
+////////////////////////////////////////////
+void print_usage(char ** const argv) {
+ cerr << "USAGE: " << argv[0] << " [OPTIONS]... FILE" << endl;
+ cerr << "Renders the scene specified by the scene file FILE." << endl << endl;
+ cerr << "Mandatory options: " << endl;
+ cerr << " -t\tRay tracing method to use. Valid values: " << endl;
+ cerr << " \t" << ANSI_BOLD_YELLOW << "whitted" << ANSI_RESET_STYLE << " Classic Whitted ray tracing." << endl;
+ cerr << " \t" << ANSI_BOLD_YELLOW << "monte_carlo" << ANSI_RESET_STYLE << " Monte Carlo path tracing." << endl;
+ cerr << "Extra options:" << endl;
+ cerr << " -o\tOutput image file name with extension." << endl;
+ cerr << " \tDefaults to \"output.png\"." << endl;
+ cerr << " -f\tField of view to use in degrees." << endl;
+ cerr << " \tDefaults to 45.0 degrees." << endl;
+ cerr << " -s\tNumber of samples per pixel." << endl;
+ cerr << " \tDefaults to 25 samples." << endl;
+ cerr << " -w\tImage size in pixels as \"WIDTHxHEIGHT\"." << endl;
+ cerr << " \tDefaults to 640x480 pixels." << endl;
+ cerr << " \tMinimum resolution is 1x1 pixels." << endl;
+ cerr << " \tMaxmimum resolution is " << MAX_W << "x" << MAX_H << " pixels." << endl;
+ cerr << " -r\tMaxmimum recursion depth." << endl;
+ cerr << " \tDefaults to 5." << endl;
+ cerr << " -g\tGamma correction value (>= 0)." << endl;
+ cerr << " \tDefaults to 2.2" << endl;
+ cerr << " -e\tExposure scale factor (in [-8, 8])." << endl;
+ cerr << " \tDefaults to 0.0 (no correction)." << endl;
+}
+
+void parse_args(int argc, char ** const argv) {
+ int opt;
+ int x_pos;
+
+ // Check command line arguments.
+ if(argc == 1) {
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+
+ while((opt = getopt(argc, argv, "-:t:s:w:f:o:r:g:e:p:h:k:c:l:m:z:")) != -1) {
+ switch (opt) {
+ case 1:
+ g_input_file = (char *)malloc((strlen(optarg) + 1) * sizeof(char));
+ strcpy(g_input_file, optarg);
+ break;
+
+ case 'g':
+ g_gamma = atof(optarg);
+ g_gamma = g_gamma < 0.0f ? 0.0f : g_gamma;
+ break;
+
+ case 'e':
+ g_exposure = atof(optarg);
+ g_exposure = clamp(g_exposure, -8.0f, 8.0f);
+ break;
+
+ case 't':
+ if (strcmp("whitted", optarg) == 0 )
+ g_tracer = WHITTED;
+ else if(strcmp("monte_carlo", optarg) == 0 || strcmp("montecarlo", optarg) == 0)
+ g_tracer = MONTE_CARLO;
+ else {
+ cerr << "Invalid ray tracer: " << optarg << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+
+ break;
+
+ case 'w':
+ for (x_pos = 0; optarg[x_pos]; x_pos++)
+ if (optarg[x_pos] == 'x')
+ break;
+
+ if (optarg[x_pos] == '\0') {
+ cerr << "Invalid screen resolution: " << optarg << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ } else {
+ optarg[x_pos] = '\0';
+ g_w = atoi(optarg);
+ g_h = atoi(&optarg[x_pos + 1]);
+ if (g_w <= 0 || g_h <= 0 || g_w >= MAX_W || g_h >= MAX_H) {
+ cerr << "Invalid screen resolution: " << optarg << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+ g_a_ratio = static_cast(g_w) / static_cast(g_h);
+ }
+
+ break;
+
+ case 's':
+ g_samples = atoi(optarg);
+ if (g_samples <= 0) {
+ cerr << "Samples per pixel must be a positive integer." << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+
+ break;
+
+ case 'o':
+ g_out_file_name = (char*)malloc((strlen(optarg) + 1) * sizeof(char));
+ strcpy(g_out_file_name, optarg);
+
+ break;
+
+ case 'f':
+ g_fov = atof(optarg);
+ if (g_fov < 1.0f) {
+ cerr << "FoV must be greater than or equal to 1.0 degrees." << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+
+ break;
+
+ case 'r':
+ g_max_depth = static_cast(abs(atoi(optarg)));
+ if (g_max_depth == 0) {
+ cerr << "Recursion depth must be a positive integer." << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+
+ break;
+
+ case ':':
+ cerr << "Option \"-" << static_cast(optopt) << "\" requires an argument." << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+
+ break;
+
+ case '?':
+ default:
+ cerr << "Unrecognized option: \"-" << static_cast(optopt) << "\"." << endl;
+ }
+ }
+
+ if (g_input_file == NULL) {
+ cerr << "Must specify an input file." << endl;
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+}
diff --git a/EVI - 2017/EVI 21/EVIray/material.hpp b/EVI - 2017/EVI 21/EVIray/material.hpp
new file mode 100644
index 0000000..a9c0721
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/material.hpp
@@ -0,0 +1,56 @@
+#pragma once
+#ifndef MATERIAL_HPP
+#define MATERIAL_HPP
+
+#include
+
+#include "brdf.hpp"
+#include "phong_brdf.hpp"
+
+using glm::vec3;
+
+class Material {
+public:
+ vec3 m_emission; // Light emission color.
+ vec3 m_diffuse; // Diffuse color.
+ vec3 m_specular; // Specular reflection color.
+ float m_rho; // Reflection coefficient.
+ float m_shininess; // Shininess.
+ float m_ref_index; // Refraction index.
+ bool m_refract; // Refraction enabled.
+ BRDF * m_brdf; // BRDF.
+
+ /**
+ * Default material constructor.
+ */
+ Material(BRDF * _brdf = NULL):
+ m_emission(vec3(0.0f)),
+ m_diffuse(vec3(1.0f)),
+ m_specular(vec3(1.0f)),
+ m_rho(0.0f),
+ m_shininess(89.0f),
+ m_ref_index(1.0f),
+ m_refract(false)
+ {
+ m_brdf = _brdf != NULL ? _brdf : static_cast(new PhongBRDF());
+ }
+
+ ~Material() {
+ delete m_brdf;
+ }
+
+ /**
+ * Copy constructor.
+ */
+ Material(const Material & m) {
+ m_diffuse = m.m_diffuse;
+ m_specular = m.m_specular;
+ m_rho = m.m_rho;
+ m_shininess = m.m_shininess;
+ m_ref_index = m.m_ref_index;
+ m_refract = m.m_refract;
+ m_brdf = m.m_brdf;
+ }
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/output.png b/EVI - 2017/EVI 21/EVIray/output.png
new file mode 100644
index 0000000..a335f2b
Binary files /dev/null and b/EVI - 2017/EVI 21/EVIray/output.png differ
diff --git a/EVI - 2017/EVI 21/EVIray/path_tracer.cpp b/EVI - 2017/EVI 21/EVIray/path_tracer.cpp
new file mode 100644
index 0000000..534ab3b
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/path_tracer.cpp
@@ -0,0 +1,159 @@
+#include
+
+#include
+
+#include "path_tracer.hpp"
+#include "sampling.hpp"
+#include "area_light.hpp"
+
+using std::numeric_limits;
+using namespace glm;
+
+PathTracer::~PathTracer() { }
+
+vec3 PathTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const {
+ float t, _t;
+ Figure * _f;
+ vec3 n, color, i_pos, ref, sample, dir_diff_color, dir_spec_color, ind_color, amb_color;
+ Ray mv_r, sr, rr;
+ bool vis, is_area_light = false;
+ float kr, r1, r2;
+ AreaLight * al;
+
+ t = numeric_limits::max();
+ _f = NULL;
+
+ // Find the closest intersecting surface.
+ for (size_t f = 0; f < s->m_figures.size(); f++) {
+ if (s->m_figures[f]->intersect(r, _t) && _t < t) {
+ t = _t;
+ _f = s->m_figures[f];
+ }
+ }
+
+ // If this ray intersects something:
+ if (_f != NULL) {
+ // Take the intersection point and the normal of the surface at that point.
+ i_pos = r.m_origin + (t * r.m_direction);
+ n = _f->normal_at_int(r, t);
+
+ is_area_light = false;
+ // Check if the object is an area light;
+ for (vector::iterator it = s->m_lights.begin(); it != s->m_lights.end(); it++) {
+ if ((*it)->light_type() == Light::AREA && static_cast(*it)->m_figure == _f)
+ is_area_light = true;
+ }
+
+ // If the object is an area light, return it's emission value.
+ if (is_area_light) {
+ return _f->m_mat->m_emission;
+
+ // Check if the material is not reflective/refractive.
+ } else if (!_f->m_mat->m_refract) {
+ // Calculate the direct lighting.
+ for (size_t l = 0; l < s->m_lights.size(); l++) {
+ // For every light source
+ vis = true;
+
+ if (s->m_lights[l]->light_type() == Light::INFINITESIMAL) {
+ // Cast a shadow ray to determine visibility.
+ sr = Ray(s->m_lights[l]->direction(i_pos), i_pos + (n * BIAS));
+
+ for (size_t f = 0; f < s->m_figures.size(); f++) {
+ if (s->m_figures[f]->intersect(sr, _t) && _t < s->m_lights[l]->distance(i_pos)) {
+ vis = false;
+ break;
+ }
+ }
+
+ // Evaluate the shading model accounting for visibility.
+ dir_diff_color += vis ? s->m_lights[l]->diffuse(n, r, i_pos, *_f->m_mat) : vec3(0.0f);
+ dir_spec_color += vis ? s->m_lights[l]->specular(n, r, i_pos, *_f->m_mat) : vec3(0.0f);
+
+ } else if (s->m_lights[l]->light_type() == Light::AREA) {
+ // Cast a shadow ray towards a sample point on the surface of the light source.
+ al = static_cast(s->m_lights[l]);
+ al->sample_at_surface();
+ sr = Ray(al->direction(i_pos), i_pos + (n * BIAS));
+
+ for (size_t f = 0; f < s->m_figures.size(); f++) {
+ // Avoid self-intersection with the light source.
+ if (al->m_figure != s->m_figures[f]) {
+ if (s->m_figures[f]->intersect(sr, _t) && _t < al->distance(i_pos)) {
+ vis = false;
+ break;
+ }
+ }
+ }
+
+ // Evaluate the shading model accounting for visibility.
+ dir_diff_color += vis ? s->m_lights[l]->diffuse(n, r, i_pos, *_f->m_mat) : vec3(0.0f);
+ dir_spec_color += vis ? s->m_lights[l]->specular(n, r, i_pos, *_f->m_mat) : vec3(0.0f);
+ }
+ }
+
+ // Calculate indirect lighting contribution.
+ if (rec_level < m_max_depth) {
+ r1 = random01();
+ r2 = random01();
+ sample = sample_hemisphere(r1, r2);
+ rotate_sample(sample, n);
+ rr = Ray(normalize(sample), i_pos + (sample * BIAS));
+ ind_color += r1 * trace_ray(rr, s, rec_level + 1) / PDF;
+ }
+
+ // Calculate environment light contribution
+ vis = true;
+
+ r1 = random01();
+ r2 = random01();
+ sample = sample_hemisphere(r1, r2);
+ rotate_sample(sample, n);
+ rr = Ray(normalize(sample), i_pos + (sample * BIAS));
+
+ // Cast a shadow ray to determine visibility.
+ for (size_t f = 0; f < s->m_figures.size(); f++) {
+ if (s->m_figures[f]->intersect(rr, _t)) {
+ vis = false;
+ break;
+ }
+ }
+
+ amb_color = vis ? s->m_env->get_color(rr) * max(dot(n, rr.m_direction), 0.0f) / PDF : vec3(0.0f);
+
+ // Add lighting.
+ color += ((dir_diff_color + ind_color + amb_color) * (_f->m_mat->m_diffuse / pi())) + (_f->m_mat->m_specular * dir_spec_color);
+
+ // Determine the specular reflection color.
+ if (_f->m_mat->m_rho > 0.0f && rec_level < m_max_depth) {
+ rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS);
+ color += _f->m_mat->m_rho * trace_ray(rr, s, rec_level + 1);
+ } else if (_f->m_mat->m_rho > 0.0f && rec_level >= m_max_depth)
+ return vec3(0.0f);
+
+ } else {
+ // If the material has transmission enabled, calculate the Fresnel term.
+ kr = fresnel(r.m_direction, n, r.m_ref_index, _f->m_mat->m_ref_index);
+
+ // Determine the specular reflection color.
+ if (kr > 0.0f && rec_level < m_max_depth) {
+ rr = Ray(normalize(reflect(r.m_direction, n)), i_pos + n * BIAS);
+ color += kr * trace_ray(rr, s, rec_level + 1);
+ } else if (rec_level >= m_max_depth)
+ return vec3(0.0f);
+
+ // Determine the transmission color.
+ if (_f->m_mat->m_refract && kr < 1.0f && rec_level < m_max_depth) {
+ rr = Ray(normalize(refract(r.m_direction, n, r.m_ref_index / _f->m_mat->m_ref_index)), i_pos - n * BIAS, _f->m_mat->m_ref_index);
+ color += (1.0f - kr) * trace_ray(rr, s, rec_level + 1);
+ } else if (rec_level >= m_max_depth)
+ return vec3(0.0f);
+
+ }
+
+ // Return final color.
+ return _f->m_mat->m_emission + color;
+
+ } else
+ return s->m_env->get_color(r);
+}
diff --git a/EVI - 2017/EVI 21/EVIray/path_tracer.hpp b/EVI - 2017/EVI 21/EVIray/path_tracer.hpp
new file mode 100644
index 0000000..1e1da0c
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/path_tracer.hpp
@@ -0,0 +1,18 @@
+#pragma once
+#ifndef PATH_TRACER_HPP
+#define PATH_TRACER_HPP
+
+#include "tracer.hpp"
+
+class PathTracer: public Tracer {
+public:
+ PathTracer(): Tracer() { }
+
+ PathTracer(unsigned int max_depth): Tracer(max_depth) { };
+
+ virtual ~PathTracer();
+
+ virtual vec3 trace_ray(Ray & r, Scene * s, unsigned int rec_level) const;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/phong_brdf.cpp b/EVI - 2017/EVI 21/EVIray/phong_brdf.cpp
new file mode 100644
index 0000000..e71096d
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/phong_brdf.cpp
@@ -0,0 +1,19 @@
+#include "glm/glm.hpp"
+
+#include "phong_brdf.hpp"
+
+using glm::reflect;
+using glm::pow;
+using glm::max;
+using glm::dot;
+
+vec3 PhongBRDF::diffuse(vec3 light_dir, vec3 surface_normal, Ray & incident_ray, vec3 intersection_point, vec3 light_diff_color) const {
+ float n_dot_l = max(dot(surface_normal, light_dir), 0.0f);
+ return light_diff_color * n_dot_l;
+}
+
+vec3 PhongBRDF::specular(vec3 light_dir, vec3 surface_normal, Ray & incident_ray, vec3 intersection_point, vec3 light_spec_color, float shininess) const {
+ vec3 ref = reflect(light_dir, surface_normal);
+ float r_dot_l = pow(max(dot(ref, incident_ray.m_direction), 0.0f), shininess);
+ return light_spec_color * r_dot_l;
+}
diff --git a/EVI - 2017/EVI 21/EVIray/phong_brdf.hpp b/EVI - 2017/EVI 21/EVIray/phong_brdf.hpp
new file mode 100644
index 0000000..510d41b
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/phong_brdf.hpp
@@ -0,0 +1,16 @@
+#pragma once
+#ifndef PHONG_BRDF_HPP
+#define PHONG_BRDF_HPP
+
+#include "brdf.hpp"
+
+class PhongBRDF: public BRDF {
+public:
+ PhongBRDF() { }
+ virtual ~PhongBRDF() { }
+
+ virtual vec3 diffuse(vec3 light_dir, vec3 surface_normal, Ray & incident_ray, vec3 intersection_point, vec3 light_diff_color) const;
+ virtual vec3 specular(vec3 light_dir, vec3 surface_normal, Ray & incident_ray, vec3 intersection_point, vec3 light_spec_color, float shininess) const;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/plane.cpp b/EVI - 2017/EVI 21/EVIray/plane.cpp
new file mode 100644
index 0000000..48f1d3e
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/plane.cpp
@@ -0,0 +1,29 @@
+#include "plane.hpp"
+
+#define TOL 1e-6
+
+using glm::abs;
+using glm::dot;
+
+bool Plane::intersect(Ray & r, float & t) const {
+ float d = dot(r.m_direction, m_normal);
+
+ if (abs(d) > TOL) {
+ t = dot(m_normal, (m_point - r.m_origin)) / d;
+ return t >= 0.0f;
+ }
+
+ return false;
+}
+
+vec3 Plane::normal_at_int(Ray & r, float & t) const {
+ return vec3(m_normal);
+}
+
+vec3 Plane::sample_at_surface() const {
+ return vec3(0.0f);
+}
+
+void Plane::calculate_inv_area() {
+ m_inv_area = 0.0f;
+}
diff --git a/EVI - 2017/EVI 21/EVIray/plane.hpp b/EVI - 2017/EVI 21/EVIray/plane.hpp
new file mode 100644
index 0000000..fa17ef5
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/plane.hpp
@@ -0,0 +1,42 @@
+#pragma once
+#ifndef PLANE_HPP
+#define PLANE_HPP
+
+#include
+
+#include "figure.hpp"
+
+using glm::vec3;
+using glm::normalize;
+
+class Plane : public Figure {
+public:
+ vec3 m_point;
+ vec3 m_normal;
+
+ Plane(Material * mat = NULL): Figure(mat), m_point(vec3(0.0f)), m_normal(vec3(0.0f, 0.0f, 1.0f)) {
+ calculate_inv_area();
+ }
+
+ Plane(float x, float y, float z, float nx, float ny, float nz, Material * mat = NULL):
+ Figure(mat),
+ m_point(vec3(x, y, z)),
+ m_normal(normalize(vec3(nx, ny, nz)))
+ {
+ calculate_inv_area();
+ }
+
+ Plane(vec3 _p, vec3 _n, Material * mat = NULL): Figure(mat), m_point(_p), m_normal(normalize(_n)) { }
+
+ virtual ~Plane() { }
+
+ virtual bool intersect(Ray & r, float & t) const;
+ virtual vec3 normal_at_int(Ray & r, float & t) const;
+ virtual vec3 sample_at_surface() const;
+
+protected:
+ virtual void calculate_inv_area();
+};
+
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/point_light.cpp b/EVI - 2017/EVI 21/EVIray/point_light.cpp
new file mode 100644
index 0000000..62142a5
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/point_light.cpp
@@ -0,0 +1,42 @@
+#include
+#include
+
+#include "point_light.hpp"
+
+using glm::pi;
+using glm::reflect;
+using glm::length;
+using glm::normalize;
+using glm::dot;
+using glm::pow;
+using glm::max;
+
+vec3 PointLight::direction(vec3 point) const {
+ return normalize(m_position - point);
+}
+
+float PointLight::distance(vec3 point) const {
+ return length(m_position - point);
+}
+
+vec3 PointLight::diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const {
+ float d, att;
+ vec3 l_dir, ref;
+
+ l_dir = direction(i_pos);
+ d = distance(i_pos);
+ att = 1.0f / (m_const_att + (m_lin_att * d) + (m_quad_att * (d * d)));
+
+ return att * m.m_brdf->diffuse(l_dir, normal, r, i_pos, m_diffuse);
+}
+
+vec3 PointLight::specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const {
+ float d, att;
+ vec3 l_dir, ref;
+
+ l_dir = direction(i_pos);
+ d = distance(i_pos);
+ att = 1.0f / (m_const_att + (m_lin_att * d) + (m_quad_att * (d * d)));
+
+ return att * m.m_brdf->specular(l_dir, normal, r, i_pos, m_specular, m.m_shininess);
+}
diff --git a/EVI - 2017/EVI 21/EVIray/point_light.hpp b/EVI - 2017/EVI 21/EVIray/point_light.hpp
new file mode 100644
index 0000000..9bbe9f4
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/point_light.hpp
@@ -0,0 +1,23 @@
+#pragma once
+#ifndef POINT_LIGHT_HPP
+#define POINT_LIGHT_HPP
+
+#include "light.hpp"
+
+class PointLight: public InfinitesimalLight {
+public:
+ float m_const_att;
+ float m_lin_att;
+ float m_quad_att;
+
+ PointLight(): InfinitesimalLight(), m_const_att(1.0f), m_lin_att(0.0f), m_quad_att(0.0f) { }
+
+ PointLight(vec3 _p, vec3 _d, vec3 _s, float _c, float _l, float _q): InfinitesimalLight(_p, _d, _s), m_const_att(_c), m_lin_att(_l), m_quad_att(_q) { }
+
+ virtual vec3 direction(vec3 point) const;
+ virtual float distance(vec3 point) const;
+ virtual vec3 diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const;
+ virtual vec3 specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const;
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/ray.hpp b/EVI - 2017/EVI 21/EVIray/ray.hpp
new file mode 100644
index 0000000..162b889
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/ray.hpp
@@ -0,0 +1,22 @@
+#pragma once
+#ifndef RAY_HPP
+#define RAY_HPP
+
+#include
+
+using glm::vec3;
+
+class Ray {
+public:
+ vec3 m_direction;
+ vec3 m_origin;
+ float m_ref_index;
+
+ Ray(): m_direction(vec3(0.0f, 0.0f, -1.0f)), m_origin(vec3(0.0f)), m_ref_index(1.0f) { }
+ Ray(float dx, float dy, float dz, float ox, float oy, float oz, float _r = 1.0f): m_direction(vec3(dx, dy, dz)),
+ m_origin(vec3(ox, oy, oz)),
+ m_ref_index(_r) { }
+ Ray(vec3 _d, vec3 _o, float _r = 1.0f): m_direction(_d), m_origin(_o), m_ref_index(_r) { }
+};
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/sampling.cpp b/EVI - 2017/EVI 21/EVIray/sampling.cpp
new file mode 100644
index 0000000..83be604
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/sampling.cpp
@@ -0,0 +1,108 @@
+#ifdef USE_CPP11_RANDOM
+#include
+#include
+#include
+#else
+#include
+#include
+#endif
+
+#include
+#include
+
+#include "sampling.hpp"
+
+#ifdef USE_CPP11_RANDOM
+using std::uniform_real_distribution;
+using std::mt19937;
+using std::bind;
+#endif
+using glm::mat3;
+using glm::abs;
+using glm::normalize;
+using glm::cross;
+using glm::radians;
+using glm::pi;
+
+const float PDF = (1.0f / (2.0f * pi()));
+
+static bool seeded = false;
+
+#ifdef USE_CPP11_RANDOM
+static uniform_real_distribution dist(0, 1);
+static mt19937 engine;
+static auto generator = bind(dist, engine);
+#endif
+
+float random01() {
+ if (!seeded) {
+#ifdef USE_CPP11_RANDOM
+ engine.seed(std::chrono::system_clock::now().time_since_epoch().count());
+#else
+ srand(time(NULL));
+#endif
+ seeded = true;
+ }
+#ifdef USE_CPP11_RANDOM
+ return generator();
+#else
+ return static_cast(rand()) / RAND_MAX;
+#endif
+}
+
+vec2 sample_pixel(int i, int j, float w, float h, float a_ratio, float fov) {
+ float pxNDC;
+ float pyNDC;
+ float pxS;
+ float pyS;
+ pyNDC = (static_cast(i) + random01()) / h;
+ pyS = (1.0f - (2.0f * pyNDC)) * glm::tan(radians(fov / 2.0f));
+ pxNDC = (static_cast(j) + random01()) / w;
+ pxS = (2.0f * pxNDC) - 1.0f;
+ pxS *= a_ratio * glm::tan(radians(fov / 2.0f));
+
+ return vec2(pxS, pyS);
+}
+
+/* Sampling functions pretty much taken from scratchapixel.com */
+void create_coords_system(const vec3 &n, vec3 &nt, vec3 &nb) {
+ if (abs(n.x) > abs(n.y))
+ nt = normalize(vec3(n.z, 0.0f, -n.x));
+ else
+ nt = normalize(vec3(0.0f, -n.z, n.y));
+ nb = normalize(cross(n, nt));
+}
+
+vec3 sample_hemisphere(const float r1, float r2) {
+ float sin_t = glm::sqrt(1.0f - (r1 * r1));
+ float phi = 2 * pi() * r2;
+ float x = sin_t * glm::cos(phi);
+ float z = sin_t * glm::sin(phi);
+ return vec3(x, r1, z);
+}
+
+void rotate_sample(vec3 & sample, const vec3 & n) {
+ vec3 nt, nb;
+ mat3 rot_m;
+
+ create_coords_system(n, nt, nb);
+ sample = vec3(sample.x * nb.x + sample.y * n.x + sample.z * nt.x,
+ sample.x * nb.y + sample.y * n.y + sample.z * nt.y,
+ sample.x * nb.z + sample.y * n.z + sample.z * nt.z);
+}
+
+vec3 sample_sphere(const vec3 center, const float radius) {
+ float theta;
+ float u, sqrt1muu, x, y, z;
+
+ // Sampling formula from Wolfram Mathworld:
+ // http://mathworld.wolfram.com/SpherePointPicking.html
+ theta = random01()* (2.0f * pi());
+ u = (random01() * 2.0f) - 1.0f;
+ sqrt1muu = glm::sqrt(1.0f - (u * u));
+ x = radius * sqrt1muu * cos(theta);
+ y = radius * sqrt1muu * sin(theta);
+ z = radius * u;
+
+ return vec3(vec3(x, y, z) + center);
+}
diff --git a/EVI - 2017/EVI 21/EVIray/sampling.hpp b/EVI - 2017/EVI 21/EVIray/sampling.hpp
new file mode 100644
index 0000000..aea0eaa
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/sampling.hpp
@@ -0,0 +1,20 @@
+#pragma once
+#ifndef SAMPLING_HPP
+#define SAMPLING_HPP
+
+#include
+#include
+
+using glm::vec2;
+using glm::vec3;
+
+extern const float PDF;
+
+extern float random01();
+extern vec2 sample_pixel(int i, int j, float w, float h, float a_ratio, float fov);
+extern void create_coords_system(const vec3 &n, vec3 &nt, vec3 &nb);
+extern vec3 sample_hemisphere(const float r1, float r2);
+extern void rotate_sample(vec3 & sample, const vec3 & n);
+extern vec3 sample_sphere(const vec3 center, const float radius);
+
+#endif
diff --git a/EVI - 2017/EVI 21/EVIray/scene.cpp b/EVI - 2017/EVI 21/EVIray/scene.cpp
new file mode 100644
index 0000000..97e2c20
--- /dev/null
+++ b/EVI - 2017/EVI 21/EVIray/scene.cpp
@@ -0,0 +1,442 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "scene.hpp"
+#include "brdf.hpp"
+#include "phong_brdf.hpp"
+#include "sphere.hpp"
+#include "plane.hpp"
+#include "directional_light.hpp"
+#include "point_light.hpp"
+#include "spot_light.hpp"
+#include "sphere_area_light.hpp"
+
+using std::cerr;
+using std::endl;
+using std::string;
+using std::ostringstream;
+using std::ifstream;
+using std::ios;
+using std::streamsize;
+using glm::vec3;
+using glm::normalize;
+using glm::cross;
+using json_spirit::read;
+using json_spirit::Error_position;
+using json_spirit::Object;
+using json_spirit::Array;
+
+static const string ENV_KEY = "environment";
+static const string CAM_KEY = "camera";
+static const string SPH_KEY = "sphere";
+static const string PLN_KEY = "plane";
+static const string MSH_KEY = "mesh";
+static const string DLT_KEY = "directional_light";
+static const string PLT_KEY = "point_light";
+static const string SLT_KEY = "spot_light";
+static const string SAL_KEY = "sphere_area_light";
+static const string PAL_KEY = "planar_area_light";
+
+static const string ENV_COL_KEY = "color";
+
+static const string CAM_EYE_KEY = "eye";
+static const string CAM_CNT_KEY = "look";
+static const string CAM_LFT_KEY = "left";
+static const string CAM_UPV_KEY = "up";
+static const string CAM_RLL_KEY = "roll";
+static const string CAM_PTC_KEY = "pitch";
+static const string CAM_YAW_KEY = "yaw";
+
+static const string FIG_POS_KEY = "position";
+static const string FIG_MAT_KEY = "material";
+static const string FIG_RAD_KEY = "radius";
+static const string FIG_NOR_KEY = "normal";
+
+static const string PLN_PNT_KEY = "point";
+
+static const string MLT_EMS_KEY = "emission";
+static const string MLT_DIF_KEY = "diffuse";
+static const string MLT_SPC_KEY = "specular";
+static const string MLT_RHO_KEY = "rho";
+static const string MLT_SHN_KEY = "shininess";
+static const string MLT_RFI_KEY = "ref_index";
+static const string MLT_BRF_KEY = "transmissive";
+static const string MLT_BRD_KEY = "brdf";
+
+static const string BRD_PHN_KEY = "phong";
+
+static const string GEO_TRN_KEY = "translation";
+static const string GEO_SCL_KEY = "scaling";
+static const string GEO_ROT_KEY = "rotation";
+
+static const string LGT_DIR_KEY = "direction";
+static const string LGT_CAT_KEY = "const_attenuation";
+static const string LGT_LAT_KEY = "linear_attenuation";
+static const string LGT_QAT_KEY = "quad_attenuation";
+static const string LGT_SPD_KEY = "spot_direction";
+static const string LGT_SPC_KEY = "spot_cutoff";
+static const string LGT_SPE_KEY = "spot_exponent";
+
+Scene::Scene(const char * file_name, int h, int w, float fov) {
+ ostringstream oss;
+ ifstream ifs(file_name, ios::in);
+ Value val;
+ Object top_level;
+
+ m_cam = NULL;
+ m_env = NULL;
+
+ if (ifs.is_open()) {
+ try {
+ read_or_throw(ifs, val);
+ } catch (Error_position & e) {
+ ifs.close();
+ oss << "Failed to parse the input file: " << endl << "Reason: " << e.reason_ << endl << "Line: " << e.line_ << endl << "Column: " << e.column_;
+ throw SceneError(oss.str());
+ }
+
+ ifs.close();
+
+ top_level = val.get_value