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(); + + try { + for (Object::iterator it = top_level.begin(); it != top_level.end(); it++) { + if ((*it).name_ == ENV_KEY) + read_environment((*it).value_); + + else if ((*it).name_ == CAM_KEY) + read_camera((*it).value_); + + else if ((*it).name_ == SPH_KEY) + m_figures.push_back(read_sphere((*it).value_)); + + else if ((*it).name_ == PLN_KEY) + m_figures.push_back(read_plane((*it).value_)); + + else if ((*it).name_ == DLT_KEY) + m_lights.push_back(read_light((*it).value_, DIRECTIONAL)); + + else if ((*it).name_ == PLT_KEY) + m_lights.push_back(read_light((*it).value_, POINT)); + + else if ((*it).name_ == SLT_KEY) + m_lights.push_back(read_light((*it).value_, SPOT)); + + else if((*it).name_ == SAL_KEY) + m_lights.push_back(read_area_light((*it).value_, SPHERE)); + + else + cerr << "Unrecognized key \"" << (*it).name_ << "\" in the input file." << endl; + } + } catch (SceneError & e) { + throw e; + } catch (runtime_error & r) { + throw SceneError("Type error in input file."); + } + + // If there were no camera and/or environment defined, create some default ones. + if (m_cam == NULL) + m_cam = new Camera(); + if (m_env == NULL) + m_env = new Environment(); + + } else + throw SceneError("Could not open the input file."); +} + +Scene::~Scene() { + delete m_env; + delete m_cam; + + for (size_t i = 0; i < m_figures.size(); i++) { + delete m_figures[i]; + } + m_figures.clear(); + + for (size_t i = 0; i < m_lights.size(); i++) { + delete m_lights[i]; + } + m_lights.clear(); +} + +void Scene::read_vector(Value & val, vec3 & vec) { + Array a = val.get_value(); + + if (a.size() < 3) + throw SceneError("Vector value must have 3 elements."); + + vec = vec3(a[0].get_value(), a[1].get_value(), a[2].get_value()); +} + +void Scene::read_environment(Value & v) { + string t_name = ""; + bool has_color = false; + vec3 color = vec3(1.0f); + Object env_obj = v.get_value(); + + for (Object::iterator it = env_obj.begin(); it != env_obj.end(); it++) { + if ((*it).name_ == ENV_COL_KEY) { + try { + read_vector((*it).value_, color); + } catch (SceneError & e) { + throw e; + } + has_color = true; + } + + else + cerr << "Unrecognized key \"" << (*it).name_ << "\" in environment." << endl; + } + + if (!has_color) + throw SceneError("Environment must specify a color."); + + m_env = new Environment(color); +} + +void Scene::read_camera(Value & v) { + bool has_up = false, has_left = false, has_eye = false, has_look = false; + vec3 eye, look, left, up, translation; + float pitch = 0.0f, yaw = 0.0f, roll = 0.0f; + Object cam_obj = v.get_value(); + + for (Object::iterator it = cam_obj.begin(); it != cam_obj.end(); it++) { + if ((*it).name_ == CAM_EYE_KEY) { + read_vector((*it).value_, eye); + has_eye = true; + + } else if ((*it).name_ == CAM_CNT_KEY) { + read_vector((*it).value_, look); + has_look = true; + + } else if ((*it).name_ == CAM_LFT_KEY) { + read_vector((*it).value_, left); + has_left = true; + + } else if ((*it).name_ == CAM_UPV_KEY) { + read_vector((*it).value_, up); + has_up = true; + + } else if ((*it).name_ == GEO_TRN_KEY) + read_vector((*it).value_, translation); + + else if ((*it).name_ == CAM_RLL_KEY) + roll = static_cast((*it).value_.get_value()); + + else if ((*it).name_ == CAM_PTC_KEY) + pitch = static_cast((*it).value_.get_value()); + + else if ((*it).name_ == CAM_YAW_KEY) + yaw = static_cast((*it).value_.get_value()); + + else + cerr << "Unrecognized key \"" << (*it).name_ << "\" in camera." << endl; + } + + if (!has_eye || !has_look) + throw SceneError("Must specify an eye and look positions for the camera."); + + if (has_up) + m_cam = new Camera(eye, look, up); + else if(!has_up && has_left) { + up = cross(normalize(look - eye), left); + m_cam = new Camera(eye, look, up); + } else + throw SceneError("Must specify either an up or left vector for the camera."); + + m_cam->pitch(pitch); + m_cam->yaw(yaw); + m_cam->roll(roll); + m_cam->translate(translation); +} + +Material * Scene::read_material(Value & v) { + vec3 emission = vec3(0.0f), diffuse = vec3(1.0f), specular = vec3(1.0f); + bool transmissive = false; + float rho = 0.0f, ref_index = 1.0f, shininess = 89.0f; + Material * mat = NULL; + Object mat_obj = v.get_value(); + + for (Object::iterator it = mat_obj.begin(); it != mat_obj.end(); it++) { + if ((*it).name_ == MLT_EMS_KEY) { + read_vector((*it).value_, emission); + + } else if ((*it).name_ == MLT_DIF_KEY) { + read_vector((*it).value_, diffuse); + + } else if ((*it).name_ == MLT_SPC_KEY) { + read_vector((*it).value_, specular); + + } else if ((*it).name_ == MLT_RHO_KEY) { + rho = static_cast((*it).value_.get_value()); + + } else if ((*it).name_ == MLT_SHN_KEY) { + shininess = static_cast((*it).value_.get_value()); + + } else if ((*it).name_ == MLT_RFI_KEY) { + ref_index = static_cast((*it).value_.get_value()); + + } else if ((*it).name_ == MLT_BRF_KEY) { + transmissive = (*it).value_.get_value(); + + } else if ((*it).name_ == MLT_BRD_KEY) { + if ((*it).value_.get_value() == BRD_PHN_KEY) + mat = new Material(new PhongBRDF()); + else + throw SceneError("Unrecognized BRDF in material."); + + } else + cerr << "Unrecognized key \"" << (*it).name_ << "\" in material." << endl; + } + + if (mat == NULL) + mat = new Material(); + mat->m_emission = emission; + mat->m_diffuse = diffuse; + mat->m_specular = specular; + mat->m_rho = rho; + mat->m_ref_index = ref_index; + mat->m_shininess = shininess; + mat->m_refract = transmissive; + + return mat; +} + +Figure * Scene::read_sphere(Value &v) { + bool has_position = false, has_radius = false; + vec3 position; + float radius = 1.0f; + Material * mat = NULL; + Object sph_obj = v.get_value(); + + for (Object::iterator it = sph_obj.begin(); it != sph_obj.end(); it++) { + if ((*it).name_ == FIG_POS_KEY) { + read_vector((*it).value_, position); + has_position = true; + + } else if ((*it).name_ == FIG_MAT_KEY) { + try { + mat = read_material((*it).value_); + } catch (SceneError & e) { + throw e; + } + + } else if ((*it).name_ == FIG_RAD_KEY) { + radius = static_cast((*it).value_.get_value()); + + if (radius <= 0.0f) + throw SceneError("Sphere radius must be greater than 0."); + + has_radius = true; + + } else + cerr << "Unrecognized key \"" << (*it).name_ << "\" in sphere." << endl; + } + + if (!has_position || !has_radius) + throw SceneError("Sphere must specify a position and radius."); + + return static_cast
(new Sphere(position, radius, mat)); +} + +Figure * Scene::read_plane(Value &v) { + bool has_position = false, has_normal = false; + vec3 position, normal = vec3(0.0f, 1.0f, 0.0f); + Material * mat = NULL; + Object pln_obj = v.get_value(); + + for (Object::iterator it = pln_obj.begin(); it != pln_obj.end(); it++) { + if ((*it).name_ == FIG_POS_KEY || (*it).name_ == PLN_PNT_KEY) { + read_vector((*it).value_, position); + has_position = true; + + } else if ((*it).name_ == FIG_MAT_KEY) { + try { + mat = read_material((*it).value_); + } catch (SceneError & e) { + throw e; + } + + } else if ((*it).name_ == FIG_NOR_KEY) { + read_vector((*it).value_, normal); + has_normal = true; + + } else + cerr << "Unrecognized key \"" << (*it).name_ << "\" in plane." << endl; + } + + if (!has_position || !has_normal) + throw SceneError("Plane must specify a point and normal vector."); + + return static_cast
(new Plane(position, normal, mat)); +} + +Light * Scene::read_light(Value & v, light_type_t t) { + vec3 position, diffuse = vec3(1.0f), specular = vec3(1.0f), spot_dir = vec3(0.0f, -1.0f, 0.0f); + float const_att = 1.0f, lin_att = 0.0f, quad_att = 0.0f, spot_cutoff = 45.0f, spot_exp = 0.0f; + Object lght_obj = v.get_value(); + + for (Object::iterator it = lght_obj.begin(); it != lght_obj.end(); it++) { + if ((*it).name_ == FIG_POS_KEY || (*it).name_ == LGT_DIR_KEY) + read_vector((*it).value_, position); + + else if((*it).name_ == MLT_DIF_KEY) + read_vector((*it).value_, diffuse); + + else if((*it).name_ == MLT_SPC_KEY) + read_vector((*it).value_, specular); + + else if((*it).name_ == LGT_SPD_KEY) + read_vector((*it).value_, spot_dir); + + else if ((*it).name_ == LGT_CAT_KEY) + const_att = static_cast((*it).value_.get_value()); + + else if ((*it).name_ == LGT_LAT_KEY) + lin_att = static_cast((*it).value_.get_value()); + + else if ((*it).name_ == LGT_QAT_KEY) + quad_att = static_cast((*it).value_.get_value()); + + else if ((*it).name_ == LGT_SPC_KEY) + spot_cutoff = static_cast((*it).value_.get_value()); + + else if ((*it).name_ == LGT_SPE_KEY) + spot_exp = static_cast((*it).value_.get_value()); + } + + if (t == DIRECTIONAL) + return static_cast(new DirectionalLight(position, diffuse, specular)); + else if (t == POINT) + return static_cast(new PointLight(position, diffuse, specular, const_att, lin_att, quad_att)); + else if (t == SPOT) + return static_cast(new SpotLight(position, diffuse, specular, const_att, lin_att, quad_att, spot_cutoff, spot_exp, spot_dir)); + else + throw SceneError("Unknown light type."); + + return NULL; +} + +Light * Scene::read_area_light(Value & v, light_type_t t) { + Sphere * s; + SphereAreaLight * sal; + Light * l; + + if (t == SPHERE) { + s = static_cast(read_sphere(v)); + sal = new SphereAreaLight(s); + m_figures.push_back(static_cast
(s)); + l = static_cast(sal); + + } else + throw SceneError("Unknown area light type"); + + return l; +} diff --git a/EVI - 2017/EVI 21/EVIray/scene.hpp b/EVI - 2017/EVI 21/EVIray/scene.hpp new file mode 100644 index 0000000..2d58e6a --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scene.hpp @@ -0,0 +1,50 @@ +#pragma once +#ifndef SCENE_HPP +#define SCENE_HPP + +#include +#include +#include + +#include + +#include "camera.hpp" +#include "figure.hpp" +#include "light.hpp" +#include "material.hpp" +#include "environment.hpp" + +using std::string; +using std::vector; +using std::runtime_error; +using json_spirit::Value; + +class SceneError: public runtime_error { +public: + explicit SceneError(const string & what_arg): runtime_error(what_arg) { } +}; + +class Scene { +public: + typedef enum LIGHT_TYPE { DIRECTIONAL, POINT, SPOT, SPHERE, DISK, PLANE } light_type_t; + + vector
m_figures; + vector m_lights; + Environment * m_env; + Camera * m_cam; + + Scene(const char * file_name, int h = 480, int w = 640, float fov = 90.0f); + ~Scene(); + +private: + void read_vector(Value & val, vec3 & vec); + void read_environment(Value & v); + void read_camera(Value & v); + Material * read_material(Value & v); + Figure * read_sphere(Value & v); + Figure * read_plane(Value & v); + Light * read_light(Value & v, light_type_t t); + Light * read_area_light(Value & v, light_type_t t); +}; + +#endif diff --git a/EVI - 2017/EVI 21/EVIray/scenes/furnace.json b/EVI - 2017/EVI 21/EVIray/scenes/furnace.json new file mode 100644 index 0000000..ea30ed9 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/furnace.json @@ -0,0 +1,13 @@ +{ + "environment": { + "color": [1.0, 1.0, 1.0] + }, + + "sphere": { + "position": [0.0, 0.0, -2.0], + "radius": 1.0, + "material": { + "diffuse": [0.1, 0.1, 0.1] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene1.json b/EVI - 2017/EVI 21/EVIray/scenes/scene1.json new file mode 100644 index 0000000..b4013f2 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene1.json @@ -0,0 +1,124 @@ +{ + "directional_light": { + "direction": [1.0, 1.0, 1.0], + "diffuse": [0.0, 1.0, 1.0] + }, + + "directional_light": { + "direction": [-1.0, 1.0, 1.0], + "diffuse": [1.0, 1.0, 0.0] + }, + + "directional_light": { + "direction": [0.0, 1.0, -1.0], + "diffuse": [1.0, 0.0, 1.0] + }, + + "disk": { + "position": [-0.0, -0.0, -0.5], + "normal": [0.0, 0.0, 0.1], + "radius": 0.25, + "material": { + "diffuse": [1.0, 0.0, 0.0], + "rho": 0.3, + "transmissive": true, + "ref_index": 1.33 + } + }, + + "plane": { + "point": [0.0, -1.5, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [1.0, 0.5, 0.4] + } + }, + + "sphere": { + "position": [1.0, 1.0, -2.0], + "radius": 0.5, + "material": { + "diffuse": [1.0, 0.0, 0.0] + } + }, + + "sphere": { + "position": [-1.0, 1.0, -2.0], + "radius": 0.5, + "material": { + "diffuse": [0.0, 1.0, 0.0] + } + }, + + "sphere": { + "position": [1.0, -1.0, -2.0], + "radius": 0.5, + "material": { + "diffuse": [0.0, 0.0, 1.0] + } + }, + + "sphere": { + "position": [-1.0, -1.0, -2.0], + "radius": 0.5, + "material": { + "diffuse": [1.0, 0.0, 1.0] + } + }, + + "sphere": { + "position": [0.0, 0.0, -2.0], + "radius": 1.0, + "material": { + "diffuse": [1.0, 1.0, 0.0] + } + }, + + "sphere": { + "position": [-1.5, 0.0, -2.0], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.3 + } + }, + + "sphere": { + "position": [1.5, 0.0, -2.0], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.08, + "transmissive": true, + "ref_index": 1.1 + } + }, + + "sphere": { + "position": [0.0, 1.5, -2.0], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.5 + } + }, + + "sphere": { + "position": [0.0, 0.0, -1.0], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.1 + } + }, + + "environment": { + "color": [0.7, 0.4, 0.05] + }, + + "camera": { + "eye": [0.0, 0.0, 1.0], + "look": [0.0, 0.0, -1.0], + "up": [0.0, 1.0, 0.0] + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene10.json b/EVI - 2017/EVI 21/EVIray/scenes/scene10.json new file mode 100644 index 0000000..945ecd6 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene10.json @@ -0,0 +1,98 @@ +{ + "camera": { + "eye": [0.0, 0.0, 1.0], + "look": [0.0, 0.0, -1.0], + "left": [-1.0, 0.0, 0.0] + }, + + "point_light": { + "position": [0.0, 0.9, -1.0] + }, + + "sphere": { + "position": [-0.4, -0.75, -0.65], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.4 + } + }, + + "sphere": { + "position": [-0.75, -0.5, -1.5], + "radius": 0.5, + "material": { + "diffuse": [0.0, 0.0, 0.0], + "rho": 1.0 + } + }, + + "sphere": { + "position": [1.0, -0.5, -1.1], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 0.0], + "transmissive": true, + "ref_index": 1.33 + } + }, + + "plane": { + "position": [0.0, -1.0, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0], + "transmissive": true + } + }, + + "plane": { + "position": [-2.0, 0.0, 0.0], + "normal": [1.0, 0.0, 0.0], + "material": { + "diffuse": [1.0, 0.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [2.0, 0.0, 0.0], + "normal": [-1.0, 0.0, 0.0], + "material": { + "diffuse": [0.0, 0.0, 1.0], + "transmissive": true, + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 1.0, 0.0], + "normal": [0.0, -1.0, 0.0], + "material": { + "diffuse": [0.0, 1.0, 1.0], + "transmissive": true, + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, -2.0], + "normal": [0.0, 0.0, 1.0], + "material": { + "diffuse": [1.0, 0.0, 1.0], + "transmissive": true, + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, 1.1], + "normal": [0.0, 0.0, -1.0], + "material": { + "diffuse": [1.0, 1.0, 0.0], + "transmissive": true, + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene2.json b/EVI - 2017/EVI 21/EVIray/scenes/scene2.json new file mode 100644 index 0000000..daf5859 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene2.json @@ -0,0 +1,127 @@ +{ + "point_light": { + "position": [0.0, 0.9, -1.0] + }, + + "sphere": { + "position": [0.2, 0.0, -0.75], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.2 + } + }, + + "sphere": { + "position": [-0.5, -0.5, -1.5], + "radius": 0.5, + "material": { + "diffuse": [0.0, 0.0, 0.0], + "rho": 1.0 + } + }, + + "sphere": { + "position": [-0.5, -0.5, 0.6], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 0.0], + "transmissive": true, + "ref_index": 1.33 + } + }, + + "disk": { + "position": [-0.25, 1.0, -1.0], + "normal": [1.0, 0.0, 0.0], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "disk": { + "position": [0.25, 1.0, -1.0], + "normal": [-1.0, 0.0, 0.0], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "disk": { + "position": [0.0, 1.0, -1.25], + "normal": [0.0, 0.0, 1.0], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "disk": { + "position": [0.0, 1.0, -0.75], + "normal": [0.0, 0.0, -1.0], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, -1.0, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [0.0, 1.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [-2.0, 0.0, 0.0], + "normal": [1.0, 0.0, 0.0], + "material": { + "diffuse": [1.0, 0.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [2.0, 0.0, 0.0], + "normal": [-1.0, 0.0, 0.0], + "material": { + "diffuse": [0.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 1.0, 0.0], + "normal": [0.0, -1.0, 0.0], + "material": { + "diffuse": [0.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, -2.0], + "normal": [0.0, 0.0, 1.0], + "material": { + "diffuse": [1.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, 1.1], + "normal": [0.0, 0.0, -1.0], + "material": { + "diffuse": [1.0, 1.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene3.json b/EVI - 2017/EVI 21/EVIray/scenes/scene3.json new file mode 100644 index 0000000..af530af --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene3.json @@ -0,0 +1,52 @@ +{ + "environment": { + "texture": "textures/pisa.hdr", + "light_probe": false + }, + + "camera": { + "eye": [0.0, 1.5, 1.0], + "look": [0.0, 0.0, -2.0], + "left": [-1.0, 0.0, 0.0], + "translation": [1.0, 0.0, 0.0] + }, + + "sphere": { + "position": [2.0, 0.0, -2.0], + "radius": 1.5, + "material": { + "diffuse": [1.0, 1.0, 0.0], + "shininess": 128.0, + "brdf": "heidrich-seidel" + } + }, + + "sphere":{ + "position": [-1.0, 0.0, -3.25], + "radius": 1.5, + "material": { + "diffuse": [1.0, 0.0, 1.0], + "rho": 0.4 + } + }, + + "sphere_area_light":{ + "position": [1.0, 0.0, -3.25], + "radius": 1.5, + "material": { + "emission": [10.0, 10.0, 10.0], + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.4 + } + }, + + "disk": { + "position": [1.0, -1.5, -3.25], + "normal": [0.0, 1.0, 0.0], + "radius": 3.0, + "material": { + "diffuse": [0.0, 0.5, 0.5], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene4.json b/EVI - 2017/EVI 21/EVIray/scenes/scene4.json new file mode 100644 index 0000000..3267c42 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene4.json @@ -0,0 +1,30 @@ +{ + "environment": { + "texture": "textures/pisa.hdr", + "light_probe": false + }, + + "camera": { + "eye": [0.0, 1.0, 0.0], + "look": [0.0, 0.0, -2.0], + "up": [0.0, 1.0, 0.0] + }, + + "sphere": { + "position": [0.0, 0.0, -2.0], + "radius": 1.0, + "material": { + "diffuse": [0.5, 0.5, 0.5], + "rho": 1.0 + } + }, + + "plane": { + "position": [0.0, -1.0, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [0.0, 0.5, 1.0], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene5.json b/EVI - 2017/EVI 21/EVIray/scenes/scene5.json new file mode 100644 index 0000000..2d8abce --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene5.json @@ -0,0 +1,42 @@ +{ + "environment": { + "color": [0.0, 0.0, 0.0] + }, + + "sphere": { + "position": [0.0, 0.0, -2.0], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "transmissive": true, + "ref_index": 1.33 + } + }, + + "sphere": { + "position": [0.0, 0.0, -2.0], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "transmissive": true, + "ref_index": 1.0 + } + }, + + "sphere_area_light": { + "position": [0.0, 1.4, -2.0], + "radius": 0.05, + "material": { + "emission": [1.0, 1.0, 1.0] + } + }, + + "plane": { + "position": [0.0, -1.0, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [1.0, 1.0, 0.2], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene6.json b/EVI - 2017/EVI 21/EVIray/scenes/scene6.json new file mode 100644 index 0000000..8d7318c --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene6.json @@ -0,0 +1,91 @@ +{ + "sphere_area_light": { + "position": [0.0, 1.0, -1.0], + "radius": 0.15, + "material": { + "emission": [1.0, 1.0, 1.0] + } + }, + + "sphere": { + "position": [0.2, 0.0, -0.75], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.4 + } + }, + + "sphere": { + "position": [-0.5, -0.5, -1.5], + "radius": 0.5, + "material": { + "diffuse": [0.0, 0.0, 0.0], + "rho": 1.0 + } + }, + + "sphere": { + "position": [-0.5, -0.5, 0.6], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 0.0], + "transmissive": true, + "ref_index": 1.33 + } + }, + + "plane": { + "position": [0.0, -1.0, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [0.0, 1.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [-2.0, 0.0, 0.0], + "normal": [1.0, 0.0, 0.0], + "material": { + "diffuse": [1.0, 0.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [2.0, 0.0, 0.0], + "normal": [-1.0, 0.0, 0.0], + "material": { + "diffuse": [0.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 1.0, 0.0], + "normal": [0.0, -1.0, 0.0], + "material": { + "diffuse": [0.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, -2.0], + "normal": [0.0, 0.0, 1.0], + "material": { + "diffuse": [1.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, 1.1], + "normal": [0.0, 0.0, -1.0], + "material": { + "diffuse": [1.0, 1.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene7.json b/EVI - 2017/EVI 21/EVIray/scenes/scene7.json new file mode 100644 index 0000000..97132c1 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene7.json @@ -0,0 +1,97 @@ +{ + "camera": { + "eye": [0.0, 0.0, 1.0], + "look": [0.0, 0.0, -1.0], + "left": [-1.0, 0.0, 0.0] + }, + + "sphere_area_light": { + "position": [0.0, 0.7, -1.0], + "radius": 0.15, + "material": { + "emission": [1.0, 1.0, 1.0] + } + }, + + "sphere": { + "position": [-0.4, -0.75, -0.65], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.4 + } + }, + + "sphere": { + "position": [-0.75, -0.5, -1.5], + "radius": 0.5, + "material": { + "diffuse": [0.0, 0.0, 0.0], + "rho": 1.0 + } + }, + + "sphere": { + "position": [1.0, -0.5, -1.1], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 0.0], + "transmissive": true, + "ref_index": 1.33 + } + }, + + "plane": { + "position": [0.0, -1.0, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [-2.0, 0.0, 0.0], + "normal": [1.0, 0.0, 0.0], + "material": { + "diffuse": [1.0, 0.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [2.0, 0.0, 0.0], + "normal": [-1.0, 0.0, 0.0], + "material": { + "diffuse": [0.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 1.0, 0.0], + "normal": [0.0, -1.0, 0.0], + "material": { + "diffuse": [0.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, -2.0], + "normal": [0.0, 0.0, 1.0], + "material": { + "diffuse": [1.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, 1.1], + "normal": [0.0, 0.0, -1.0], + "material": { + "diffuse": [1.0, 1.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene8.json b/EVI - 2017/EVI 21/EVIray/scenes/scene8.json new file mode 100644 index 0000000..88a2ce9 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene8.json @@ -0,0 +1,39 @@ +{ + "environment": { + "color": [0.0, 0.0, 0.0] + }, + + "camera": { + "eye": [2.0, 0.0, 0.0], + "look": [-1.0, -0.5, 0.0], + "left": [0.0, 0.0, 1.0], + "translation": [1.0, 0.0, 0.0] + }, + + "sphere":{ + "position": [0.0, 0.0, 0.0], + "radius": 1.0, + "material": { + "diffuse": [0.0, 0.25, 1.0], + "rho": 0.2 + } + }, + + "sphere_area_light":{ + "position": [0.0, 0.0, -15.0], + "radius": 10.0, + "material": { + "emission": [10.0, 10.0, 10.0] + } + }, + + "disk": { + "position": [0, -1.0, 0], + "normal": [0.0, 1.0, 0.0], + "radius": 2.0, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/scenes/scene9.json b/EVI - 2017/EVI 21/EVIray/scenes/scene9.json new file mode 100644 index 0000000..a98d993 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/scenes/scene9.json @@ -0,0 +1,93 @@ +{ + "camera": { + "eye": [0.0, 0.0, 1.0], + "look": [0.0, 0.0, -1.0], + "left": [-1.0, 0.0, 0.0] + }, + + "point_light": { + "position": [0.0, 0.9, -1.0] + }, + + "sphere": { + "position": [-0.4, -0.75, -0.65], + "radius": 0.25, + "material": { + "diffuse": [1.0, 1.0, 1.0], + "rho": 0.4 + } + }, + + "sphere": { + "position": [-0.75, -0.5, -1.5], + "radius": 0.5, + "material": { + "diffuse": [0.0, 0.0, 0.0], + "rho": 1.0 + } + }, + + "sphere": { + "position": [1.0, -0.5, -1.1], + "radius": 0.5, + "material": { + "diffuse": [1.0, 1.0, 0.0], + "transmissive": true, + "ref_index": 1.33 + } + }, + + "plane": { + "position": [0.0, -1.0, 0.0], + "normal": [0.0, 1.0, 0.0], + "material": { + "diffuse": [1.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [-2.0, 0.0, 0.0], + "normal": [1.0, 0.0, 0.0], + "material": { + "diffuse": [1.0, 0.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [2.0, 0.0, 0.0], + "normal": [-1.0, 0.0, 0.0], + "material": { + "diffuse": [0.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 1.0, 0.0], + "normal": [0.0, -1.0, 0.0], + "material": { + "diffuse": [0.0, 1.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, -2.0], + "normal": [0.0, 0.0, 1.0], + "material": { + "diffuse": [1.0, 0.0, 1.0], + "specular": [0.0, 0.0, 0.0] + } + }, + + "plane": { + "position": [0.0, 0.0, 1.1], + "normal": [0.0, 0.0, -1.0], + "material": { + "diffuse": [1.0, 1.0, 0.0], + "specular": [0.0, 0.0, 0.0] + } + } +} diff --git a/EVI - 2017/EVI 21/EVIray/sphere.cpp b/EVI - 2017/EVI 21/EVIray/sphere.cpp new file mode 100644 index 0000000..84de230 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/sphere.cpp @@ -0,0 +1,52 @@ +#include +#include + +#include "sphere.hpp" +#include "sampling.hpp" + +using namespace glm; + +bool Sphere::intersect(Ray & r, float & t) const { + float t1, t2; + float d; + + float a = (r.m_direction.x * r.m_direction.x) + + (r.m_direction.y * r.m_direction.y) + + (r.m_direction.z * r.m_direction.z); + + float b = (2 * r.m_direction.x * (r.m_origin.x - m_center.x)) + + (2 * r.m_direction.y * (r.m_origin.y - m_center.y)) + + (2 * r.m_direction.z * (r.m_origin.z - m_center.z)); + + float c = (m_center.x * m_center.x) + + (m_center.y * m_center.y) + + (m_center.z * m_center.z) + + (r.m_origin.x * r.m_origin.x) + + (r.m_origin.y * r.m_origin.y) + + (r.m_origin.z * r.m_origin.z) - + 2 * ((m_center.x * r.m_origin.x) + (m_center.y * r.m_origin.y) + (m_center.z * r.m_origin.z)) - (m_radius * m_radius); + + d = (b * b) - (4 * a * c); + + if (d >= 0.0f) { + t1 = (-b - sqrt(d)) / (2 * a); + t2 = (-b + sqrt(d)) / (2 * a); + t = t1 < t2 ? t1 : t2; + return t >= 0.0f; + + } else + return false; +} + +vec3 Sphere::normal_at_int(Ray & r, float & t) const { + vec3 i = vec3(r.m_origin + (t * r.m_direction)); + return normalize(vec3((i - m_center) / m_radius)); +} + +vec3 Sphere::sample_at_surface() const { + return sample_sphere(m_center, m_radius); +} + +void Sphere::calculate_inv_area() { + m_inv_area = 1.0f / (4.0 * pi() * (m_radius * m_radius)); +} diff --git a/EVI - 2017/EVI 21/EVIray/sphere.hpp b/EVI - 2017/EVI 21/EVIray/sphere.hpp new file mode 100644 index 0000000..80f84a3 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/sphere.hpp @@ -0,0 +1,38 @@ +#pragma once +#ifndef SPHERE_HPP +#define SPHERE_HPP + +#include + +#include "figure.hpp" + +using glm::vec3; + +class Sphere : public Figure { +public: + vec3 m_center; + float m_radius; + + Sphere(Material * mat = NULL): Figure(mat), m_center(vec3(0.0f)), m_radius(0.5f) { + calculate_inv_area(); + } + + Sphere(float x, float y, float z, float r, Material * mat = NULL): Figure(mat), m_center(vec3(x, y, z)), m_radius(r) { + calculate_inv_area(); + } + + Sphere(vec3 _c, float r, Material * mat = NULL): Figure(mat), m_center(_c), m_radius(r) { + calculate_inv_area(); + } + + virtual ~Sphere() { } + + virtual bool intersect(Ray & r, float & t) const; + virtual vec3 normal_at_int(Ray & r, float & t) const; + virtual vec3 sample_at_surface() const; + +private: + virtual void calculate_inv_area(); +}; + +#endif diff --git a/EVI - 2017/EVI 21/EVIray/sphere_area_light.cpp b/EVI - 2017/EVI 21/EVIray/sphere_area_light.cpp new file mode 100644 index 0000000..8cc22c0 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/sphere_area_light.cpp @@ -0,0 +1,8 @@ +#include "sphere_area_light.hpp" + +vec3 SphereAreaLight::sample_at_surface() { + Sphere * s = static_cast(m_figure); + m_last_sample = m_figure->sample_at_surface(); + m_n_at_last_sample = normalize(vec3((m_last_sample - s->m_center) / s->m_radius)); + return m_last_sample; +} diff --git a/EVI - 2017/EVI 21/EVIray/sphere_area_light.hpp b/EVI - 2017/EVI 21/EVIray/sphere_area_light.hpp new file mode 100644 index 0000000..23e2951 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/sphere_area_light.hpp @@ -0,0 +1,15 @@ +#pragma once +#ifndef SPHERE_AREA_LIGHT_HPP +#define SPHERE_AREA_LIGHT_HPP + +#include "area_light.hpp" +#include "sphere.hpp" + +class SphereAreaLight: public AreaLight { +public: + SphereAreaLight(Sphere * _s, float _c = 1.0, float _l = 0.0, float _q = 0.0): AreaLight(static_cast
(_s), _c, _l, _q) { } + + virtual vec3 sample_at_surface(); +}; + +#endif diff --git a/EVI - 2017/EVI 21/EVIray/spot_light.cpp b/EVI - 2017/EVI 21/EVIray/spot_light.cpp new file mode 100644 index 0000000..7f0619a --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/spot_light.cpp @@ -0,0 +1,47 @@ +#include +#include + +#include "spot_light.hpp" + +using glm::pi; +using glm::reflect; +using glm::length; +using glm::normalize; +using glm::dot; +using glm::pow; +using glm::max; +using glm::acos; +using glm::radians; + +vec3 SpotLight::diffuse(vec3 normal, Ray & r, vec3 i_pos, Material & m) const { + float d, att, spot_effect; + vec3 l_dir, ref; + + l_dir = direction(i_pos); + d = distance(i_pos); + spot_effect = dot(m_spot_dir, -l_dir); + + if (acos(spot_effect) < radians(m_spot_cutoff)) { + spot_effect = pow(spot_effect, m_spot_exponent); + att = spot_effect / (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); + + } else + return vec3(0.0f); +} + +vec3 SpotLight::specular(vec3 normal, Ray & r, vec3 i_pos, Material & m) const { + float d, att, spot_effect; + vec3 l_dir, ref; + + l_dir = direction(i_pos); + d = distance(i_pos); + spot_effect = dot(m_spot_dir, -l_dir); + + if (acos(spot_effect) < radians(m_spot_cutoff)) { + spot_effect = pow(spot_effect, m_spot_exponent); + att = spot_effect / (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); + } else + return vec3(0.0f); +} diff --git a/EVI - 2017/EVI 21/EVIray/spot_light.hpp b/EVI - 2017/EVI 21/EVIray/spot_light.hpp new file mode 100644 index 0000000..bad09db --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/spot_light.hpp @@ -0,0 +1,39 @@ +#pragma once +#ifndef SPOT_LIGHT_HPP +#define SPOT_LIGHT_HPP + +#include + +#include "point_light.hpp" + +using glm::vec3; +using glm::normalize; + +class SpotLight: public PointLight { +public: + float m_spot_cutoff; + float m_spot_exponent; + vec3 m_spot_dir; + + SpotLight(): PointLight(), m_spot_cutoff(45.0f), m_spot_exponent(0.0f), m_spot_dir(vec3(0.0f, -1.0f, 0.0f)) { } + + SpotLight(vec3 _p, + vec3 _d, + vec3 _s, + float _c, + float _l, + float _q, + float _sco, + float _se, + vec3 _sd): + PointLight(_p, _d, _s, _c, _l, _q), + m_spot_cutoff(_sco), + m_spot_exponent(_se), + m_spot_dir(normalize(_sd)) + { } + + 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/tracer.cpp b/EVI - 2017/EVI 21/EVIray/tracer.cpp new file mode 100644 index 0000000..7a0cbf5 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/tracer.cpp @@ -0,0 +1,26 @@ +#include "tracer.hpp" + +using glm::dot; +using glm::normalize; +using glm::refract; + +const float BIAS = 0.000001f; + +const vec3 BCKG_COLOR = vec3(0.1f); + +float Tracer::fresnel(const vec3 & i, const vec3 & n, const float ir1, const float ir2) const { + float cos_t1 = dot(i, n); + float cos_t2 = dot(normalize(refract(i, n, ir1 / ir2)), n); + float cos_t2s = (cos_t2 * cos_t2); + float omcos_t2s = 1.0f - cos_t2s; + omcos_t2s = omcos_t2s < 0.0f ? 0.0f : omcos_t2s; + float sin_t2 = (ir1 / ir2) * glm::sqrt(omcos_t2s); + + if (sin_t2 >= 1.0f) + return 1.0f; + + float fr_par = ((ir2 * cos_t1) - (ir1 * cos_t2)) / ((ir2 * cos_t1) + (ir1 * cos_t2)); + float fr_per = ((ir1 * cos_t2) - (ir2 * cos_t1)) / ((ir1 * cos_t2) + (ir2 * cos_t1)); + + return ((fr_par * fr_par) + (fr_per * fr_per)) / 2.0f; +} diff --git a/EVI - 2017/EVI 21/EVIray/tracer.hpp b/EVI - 2017/EVI 21/EVIray/tracer.hpp new file mode 100644 index 0000000..9558632 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/tracer.hpp @@ -0,0 +1,45 @@ +#pragma once +#ifndef TRACER_HPP +#define TRACER_HPP + +#include + +#include + +#include "ray.hpp" +#include "scene.hpp" + +using std::vector; +using glm::vec2; +using glm::vec3; + +// Intersection displacement bias. +extern const float BIAS; + +// Default background color. +extern const vec3 BCKG_COLOR; + +/** + * Base class for ray tracers. + */ +class Tracer { +public: + unsigned int m_max_depth; // Max recursion depth. + + Tracer(unsigned int max_depth = 5): m_max_depth(max_depth) { } + + virtual ~Tracer() { } + + /** + * Recursively trace a ray into a scene, up until the max recursion depth. + */ + virtual vec3 trace_ray(Ray & r, Scene * s, unsigned int rec_level) const = 0; + +protected: + /** + * Fresnel law for refractions. + */ + float fresnel(const vec3 & i, const vec3 & n, const float ir1, const float ir2) const; +}; + +#endif diff --git a/EVI - 2017/EVI 21/EVIray/whitted_tracer.cpp b/EVI - 2017/EVI 21/EVIray/whitted_tracer.cpp new file mode 100644 index 0000000..9ca0794 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/whitted_tracer.cpp @@ -0,0 +1,125 @@ +#include +#include + +#include + +#include "whitted_tracer.hpp" +#include "area_light.hpp" + +using std::numeric_limits; +using namespace glm; + +WhittedTracer::~WhittedTracer() { } + +vec3 WhittedTracer::trace_ray(Ray & r, Scene * s, unsigned int rec_level) const { + float t, _t; + Figure * _f; + vec3 n, color, i_pos, ref, dir_diff_color, dir_spec_color; + Ray mv_r, sr, rr; + bool vis, is_area_light; + float kr; + 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 (size_t l = 0; l < s->m_lights.size(); l++) { + if (s->m_lights[l]->light_type() == Light::AREA && static_cast(s->m_lights[l])->m_figure == _f) + is_area_light = true; + } + + // If the object is an area light, return it's emission value. + if (is_area_light) { + return clamp(_f->m_mat->m_emission, 0.0f, 1.0f); + + // 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; + } + } + + } 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); + } + + color += (1.0f - _f->m_mat->m_rho) * ((dir_diff_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 clamp(_f->m_mat->m_emission + color, 0.0f, 1.0f); + + } else + return clamp(s->m_env->get_color(r), 0.0f, 1.0f); +} diff --git a/EVI - 2017/EVI 21/EVIray/whitted_tracer.hpp b/EVI - 2017/EVI 21/EVIray/whitted_tracer.hpp new file mode 100644 index 0000000..8e3f802 --- /dev/null +++ b/EVI - 2017/EVI 21/EVIray/whitted_tracer.hpp @@ -0,0 +1,18 @@ +#pragma once +#ifndef WHITTED_TRACER_HPP +#define WHITTED_TRACER_HPP + +#include "tracer.hpp" + +class WhittedTracer: public Tracer { +public: + WhittedTracer(): Tracer() { } + + WhittedTracer(unsigned int max_depth): Tracer(max_depth) { }; + + virtual ~WhittedTracer(); + + virtual vec3 trace_ray(Ray & r, Scene * s, unsigned int rec_level) const; +}; + +#endif