diff --git a/CMakeLists.txt b/CMakeLists.txt index a2b2fca..20dcad8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(Ray_Tracer) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -set(SOURCE_FILES lib/whitted_rt.cpp lib/whitted_rt.h lib/math/vec4.cpp lib/math/vec4.h lib/math/vec2.cpp lib/math/vec2.h lib/math/mat4.cpp lib/math/mat4.h lib/camera/perspective_camera.cpp lib/camera/perspective_camera.h lib/geometry/ray.h lib/geometry/sphere.cpp lib/geometry/sphere.h lib/geometry/shape.cpp lib/geometry/shape.h lib/math/helper.cpp lib/math/helper.h lib/geometry/geometry_exception.cpp lib/geometry/geometry_exception.h lib/light/light.cpp lib/light/light.h lib/light/parallel_light.cpp lib/light/parallel_light.h lib/geometry/material/material.h lib/geometry/material/phong_material.cpp lib/geometry/material/phong_material.h lib/geometry/material/solid_material.h lib/geometry/point.cpp lib/geometry/point.h lib/geometry/direction.cpp lib/geometry/direction.h lib/geometry/normal.cpp lib/geometry/normal.h lib/geometry/transform.cpp lib/geometry/transform.h lib/geometry/intersection.h lib/geometry/color.cpp lib/geometry/color.h lib/geometry/material/lambertian_material.cpp lib/geometry/material/lambertian_material.h lib/light/ambient_light.cpp lib/light/ambient_light.h lib/camera/camera.h) +set(SOURCE_FILES lib/whitted_rt.cpp lib/whitted_rt.h lib/math/vec4.cpp lib/math/vec4.h lib/math/vec2.cpp lib/math/vec2.h lib/math/mat4.cpp lib/math/mat4.h lib/camera/perspective_camera.cpp lib/camera/perspective_camera.h lib/geometry/ray.h lib/geometry/sphere.cpp lib/geometry/sphere.h lib/geometry/shape.cpp lib/geometry/shape.h lib/math/helper.cpp lib/math/helper.h lib/light/light.cpp lib/light/light.h lib/light/parallel_light.cpp lib/light/parallel_light.h lib/geometry/material/material.h lib/geometry/material/phong_material.cpp lib/geometry/material/phong_material.h lib/geometry/material/solid_material.h lib/geometry/point.cpp lib/geometry/point.h lib/geometry/direction.cpp lib/geometry/direction.h lib/geometry/normal.cpp lib/geometry/normal.h lib/geometry/transform.cpp lib/geometry/transform.h lib/geometry/intersection.h lib/geometry/color.cpp lib/geometry/color.h lib/geometry/material/lambertian_material.cpp lib/geometry/material/lambertian_material.h lib/light/ambient_light.cpp lib/light/ambient_light.h lib/camera/camera.h lib/camera/camera.cpp lib/geometry/ray.cpp lib/geometry/material/solid_material.cpp) add_executable(Ray_Tracer ${SOURCE_FILES} main.cpp) add_executable(Test ${SOURCE_FILES} test.cpp) target_link_libraries(Ray_Tracer png16) \ No newline at end of file diff --git a/classes.dot b/classes.dot index cb56a30..955eed7 100644 --- a/classes.dot +++ b/classes.dot @@ -17,7 +17,7 @@ digraph Classes { - cam : camera\l - lights : std::vector\\l - scene : std::vector\\l - - max_bounces : int\l| + - max_bounces : unsigned long\l| + whitted_rt(bg_color : color &, cam : camera &, lights : std::vector\ &, @@ -40,10 +40,16 @@ digraph Classes { camera [ label = "{camera| # transforms : transform\l - # resolution : unsigned long[2]\l - # data : std::vector\\l| - - camera()\l - + get_ray(x : int, y : int) : ray &\l + # resolution : std::array\\l + # data : std::vector\\>\>\l| + # camera(position : point &, + look_at : point &, + up : direction &, + resolution : std::array &, + samples : unsigned long &)\l + + camera()\l + + get_rays(x : int, y : int) : ray &\l + + set_data(x : unsigned long, y : unsigned long, data : std::vector\) : void\l + get_pixel(x : int, y : int) : color\l }" ] @@ -54,22 +60,24 @@ digraph Classes { + perspective_camera(position : point &, look_at : point &, up : direction &, - fov : float, - resolution : int *)\l + fov : float &, + resolution : std::array &, + samples : unsigned long &)\l }" ] ray [ label = "{ray| + o : point\l - + d : direction\l + + d : direction\l| + + ray(o : point &, d : direction &)\l }" ] shape_ [ label = "{ shape| - - transforms : transform\l - - matrl : material *\l| - + shape(matrl : material *)\l + # transforms : transform\l + # matrl : material *\l| + # shape(matrl : material *)\l + intersect_full(r : ray) : intersection\l + intersect_shadow(r : ray) : bool\l + shade(lcol : color, l : direction, n : normal, v : direction, pos : vec2, internal : bool) : color\l @@ -102,7 +110,7 @@ digraph Classes { - diffuse : float\l| + lambertian_material(col : color, ambient : float, - diffuse : float) + diffuse : float)\l }" ] phong_material [ @@ -116,7 +124,7 @@ digraph Classes { ambient : float, diffuse : float, specular : float, - exponent : float) + exponent : float)\l }" ] light [ diff --git a/lib/camera/camera.cpp b/lib/camera/camera.cpp new file mode 100644 index 0000000..9f9983b --- /dev/null +++ b/lib/camera/camera.cpp @@ -0,0 +1,44 @@ +// +// Created by chais on 09.09.15. +// + +#include "camera.h" + +camera::camera(const point &position, const point &look_at, const direction &up, + const std::array &resolution, const unsigned long &samples) : resolution(resolution) { + assert(resolution[0] > 0 && resolution[1] > 0); + assert(samples > 0); + direction dir = normalise(look_at-position); + direction left = cross(normalise(up), dir); + direction new_up = cross(dir, left); + std::array, 4> d = {{ + {left[0], new_up[0], dir[0], position[0]}, + {left[1], new_up[1], dir[1], position[1]}, + {left[2], new_up[2], dir[2], position[2]}, + {0, 0, 0, 1} + }}; + mat4 *m = new mat4(d); + transforms = transform(m); + data.resize(resolution[0]); + for (auto &i : data) { + i.resize(resolution[1]); + for (auto &j : i) + j.resize(samples); + } +} + +void camera::set_data(const unsigned long &x, const unsigned long &y, const std::vector data) { + this->data[x][y] = data; +} + +color *camera::get_pixel(const unsigned long &x, const unsigned long &y) const { + color *out = new color(); + for (auto &i : this->data[x][y]) + *out += i; + *out = *out*(1/this->data[x][y].capacity()); + return out; +} + +const std::array &camera::get_resolution() const { + return resolution; +} \ No newline at end of file diff --git a/lib/camera/camera.h b/lib/camera/camera.h index 1d675a6..2943778 100644 --- a/lib/camera/camera.h +++ b/lib/camera/camera.h @@ -12,14 +12,69 @@ class camera { protected: transform transforms; - unsigned long resolution[2]; - std::vector data; + std::array resolution; + std::vector>> data; + + camera() { }; + + /** + * @brief Explicit constructor + * + * Initialises the values common to all camera implementations. Transforms and resolution are set as given. Memory + * for the data variable is allocated according to the resolution. + * + * @param &position the position of the camera + * + * @param &look_at the position the camera is centred on + * + * @param &up the up direction of the image + * + * @param &resolution the resolution of the image + * + * @param &samples the number of samples per pixel + */ + camera(const point &position, const point &look_at, const direction &up, + const std::array &resolution, const unsigned long &samples); - virtual camera() { }; public: - virtual ray &get_ray(const int &x, const int &y) const = 0; +/** + * @brief Grants access to the initial rays of the camera + * + * Calculates the rays for the given image coordinates and returns them. + * + * @param &x the x coordinate + * + * @param &y the y coordinate + * + * @return a std::vector containing all rays contributing to the pixel with the given coordinates + */ + virtual std::vector *get_rays(const unsigned long &x, const unsigned long &y) = 0; + + /** + * @brief Sets the data for the designated pixel + * + * @param &x the X coordinate + * + * @param &y the Y coordinate + * + * @param &data the std::vector of colors contributing the the pixel + */ + void set_data(const unsigned long &x, const unsigned long &y, const std::vector data); + + /** + * @brief Returns the color of a pixel + * + * Calculates the final color of a pixel from all colors contributing to it. + * + * @param &x the x coordinate + * + * @param &y the y coordinate + * + * @return the final color of the pixel with the given coordinates + */ + color *get_pixel(const unsigned long &x, const unsigned long &y) const; - virtual color &get_pixel(const int &x, const int &y) const = 0; + const std::array &get_resolution() const; }; -#endif //RAY_TRACER_CAMERA_H +#endif //RAY_TRACER_CAMERA_H \ No newline at end of file diff --git a/lib/camera/perspective_camera.cpp b/lib/camera/perspective_camera.cpp index b0623a7..7e6040d 100644 --- a/lib/camera/perspective_camera.cpp +++ b/lib/camera/perspective_camera.cpp @@ -1,41 +1,23 @@ #include "perspective_camera.h" -#include "../math/mat4.h" -perspective_camera::perspective_camera() { - std::array, 4> d = {{ - {-1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, -1, 0}, - {0, 0, 0, 1} - }}; - mat4 m = mat4(d); - transforms = transform(mat4(m), mat4(m)); - resolution = {1024, 768}; - data.reserve(1024*768); - fov = 75; +perspective_camera::perspective_camera() : perspective_camera(point(0, 0, 0), point(0, 0, -1), direction(0, 1, 0), + {1024, 768}, 1, 45) { } perspective_camera::perspective_camera(const point &position, const point &look_at, const direction &up, - const float fov, const unsigned long resolution[2]) : resolution(resolution), - fov(fov) { - direction dir = normalise(look_at-position); - direction left = normalise(cross(normalise(up), dir)); - direction new_up = cross(dir, left); - std::array, 4> d = {{ - {left[0], new_up[0], dir[0], position[0]}, - {left[1], new_up[1], dir[1], position[1]}, - {left[2], new_up[2], dir[2], position[2]}, - {0, 0, 0, 1} - }}; - mat4 m = mat4(d); - transforms = transform(m, invert(m)); - data.reserve(resolution[0]*resolution[1]); + const std::array &resolution, const unsigned long &samples, + const float &fov) : + camera(position, look_at, up, resolution, samples), fov(fov) { + assert(0 < fov && fov < 90); + stepwidth = tan(helper::to_radians(this->fov))/(resolution[0]/2); + start = direction(0, 0, 1)+direction(1, 0, 0)*(((resolution[0]-1)/2.0)*stepwidth)+ + direction(0, 1, 0)*(((resolution[1]-1)/2.0)*stepwidth); } -std::ostream &operator<<(std::ostream &out, const perspective_camera &cam) { +std::vector *perspective_camera::get_rays(const unsigned long &x, const unsigned long &y) { + // TODO extend to support multisampling + std::vector *out = new std::vector(); + out->push_back(this->transforms( + ray(point(), this->start+direction(-1, 0, 0)*(this->stepwidth*x)+direction(0, -1, 0)*(this->stepwidth*y)))); return out; -} - -double perspective_camera::getFov() const { - return 0; -} +} \ No newline at end of file diff --git a/lib/camera/perspective_camera.h b/lib/camera/perspective_camera.h index 2192e47..bfadbba 100644 --- a/lib/camera/perspective_camera.h +++ b/lib/camera/perspective_camera.h @@ -2,48 +2,51 @@ // Created by chais on 10.07.15. // -#ifndef RAY_TRACER_CAMERA_H -#define RAY_TRACER_CAMERA_H +#ifndef RAY_TRACER_PERSPECTIVE_CAMERA_H +#define RAY_TRACER_PERSPECTIVE_CAMERA_H -#include "../geometry/ray.h" #include "camera.h" -#include -#include -#include class perspective_camera : public camera { private: float fov; + double stepwidth; + direction start; public: /** * @brief Default constructor * - * Creates a perspective camera at world origin looking down the negative Z-axis. + * Creates a perspective camera with the following specification: + * \p position = [0, 0, 0] + * \p look_at = [0, 0, -1] + * \p up = [0, 1, 0] + * \p resolution = [1024, 768] + * \p samples = 1 + * \p fov = 45 */ perspective_camera(); - perspective_camera(const point &position, const point &look_at, const direction &up, const float fov, - const unsigned long resolution[2]); - - /** - * @brief Puts m description of the camera on the stream - * Puts the names of all variables followed by their values on the stream, one variable per line - */ - friend std::ostream &operator<<(std::ostream &out, const perspective_camera &cam); - /** - * @brief Grants easy access to the camera's rays - * Allows access to the rays cast by the camera. Index 0 is the upper left corner pixel, 1 the next one to the right. - * @param i the index to access + * @brief Explicit constructor + * + * Creates a perspective camera with the given parameters + * + * @param &position the position of the camera in world coordinates + * + * @param &look_at the position the camera is centered on in world coordinates + * + * @param &up the up direction of the image + * + * @param &resolution the std::array with the x and y resolution of the image + * + * @param &samples the number of samples per pixel + * + * @param &fov the half horizontal field-of-view angle of the camera */ - ray &operator[](const int i); + perspective_camera(const point &position, const point &look_at, const direction &up, + const std::array &resolution, const unsigned long &samples, const float &fov); - /** - * @brief Returns the camera's Field Of View angle - * The FOV is the angle between the center of the picture and the right border. - * @return the field of view - */ - double getFov() const; + virtual std::vector *get_rays(const unsigned long &x, const unsigned long &y); }; #endif //RAY_TRACER_CAMERA_H diff --git a/lib/geometry/color.cpp b/lib/geometry/color.cpp index a472283..ff0768e 100644 --- a/lib/geometry/color.cpp +++ b/lib/geometry/color.cpp @@ -35,6 +35,13 @@ color operator+(const color &lhs, const color &rhs) { return color(lhs[0]+rhs[0], lhs[1]+rhs[1], lhs[2]+rhs[2]); } +color &operator+=(color &lhs, const color &rhs) { + lhs[0]+=rhs[0]; + lhs[1]+=rhs[1]; + lhs[2]+=rhs[2]; + return lhs; +} + color operator*(const color &lhs, const float &rhs) { return color(lhs[0]*rhs, lhs[1]*rhs, lhs[2]*rhs); } @@ -53,9 +60,9 @@ color scale(const color &col, const color &sf) { std::array rgb(const color &col) { std::array out = {{ - col[0] > 255 ? 255 : std::round(col[0]), - col[1] > 255 ? 255 : std::round(col[1]), - col[2] > 255 ? 255 : std::round(col[2]) + col[0] > 1 ? 255 : int(std::round(col[0]*255)), + col[1] > 1 ? 255 : int(std::round(col[1]*255)), + col[2] > 1 ? 255 : int(std::round(col[2]*255)) }}; return out; } diff --git a/lib/geometry/color.h b/lib/geometry/color.h index d6f06dd..466b110 100644 --- a/lib/geometry/color.h +++ b/lib/geometry/color.h @@ -8,6 +8,7 @@ #include #include #include +#include /** * @name color @@ -33,6 +34,8 @@ class color { color operator+(const color &lhs, const color &rhs); +color &operator+=(color &lhs, const color &rhs); + color operator*(const color &lhs, const float &rhs); color operator*(const float &lhs, const color &rhs); diff --git a/lib/geometry/direction.cpp b/lib/geometry/direction.cpp index 0ba6548..494711b 100644 --- a/lib/geometry/direction.cpp +++ b/lib/geometry/direction.cpp @@ -12,46 +12,6 @@ direction::direction(const vec4 &in) : vec4(in[0], in[1], in[2], 0) { } direction::direction(const direction &in) : vec4(in) { } -std::ostream &operator<<(std::ostream &out, const direction &a) { - out << vec4::operator<<(out, dynamic_cast(a)); - return out; -} - -direction operator+(const direction &lhs, const direction &rhs) { - return direction(dynamic_cast(lhs)+dynamic_cast(rhs)); -} - -direction &operator+=(direction &lhs, const direction &rhs) { - dynamic_cast(lhs) += dynamic_cast(rhs); - return lhs; -} - -direction operator-(const direction &lhs, const direction &rhs) { - return direction(dynamic_cast(lhs)-dynamic_cast(rhs)); -} - -direction &operator-=(direction &lhs, const direction &rhs) { - dynamic_cast(lhs) -= dynamic_cast(rhs); - return lhs; -} - -direction operator*(const direction &lhs, const float &rhs) { - return direction(dynamic_cast(lhs)*rhs); -} - -direction operator*(const float &lhs, const direction &rhs) { - return direction(lhs*dynamic_cast(rhs)); -} - -direction &operator*=(direction &lhs, const float &rhs) { - dynamic_cast(lhs)*=rhs; - return lhs; -} - -float dot(const direction &lhs, const direction &rhs) { - return dot(dynamic_cast(lhs), dynamic_cast(rhs)); -} - direction cross(const direction &lhs, const direction &rhs) { return direction(lhs[1]*rhs[2]-lhs[2]*rhs[1], lhs[2]*rhs[0]-lhs[0]*rhs[2], lhs[0]*rhs[1]-lhs[1]*rhs[0]); } \ No newline at end of file diff --git a/lib/geometry/direction.h b/lib/geometry/direction.h index 0ba0559..bf8d86c 100644 --- a/lib/geometry/direction.h +++ b/lib/geometry/direction.h @@ -53,126 +53,8 @@ class direction : public vec4 { * @param &in the original vector */ direction(const direction &in); - - /** - * @brief Output operator - * - * Puts the vector on an output stream in an Octave/Matlab-compatible format. - * - * @param &out the output stream - * - * @param &a the vector - * - * @return the output stream - */ - friend std::ostream &operator<<(std::ostream &out, const direction &a); }; -/** - * @brief Addition operator - * - * Adds two direction vectors. - * - * @param &lhs the left operand - * - * @param &rhs the right operand - * - * @return the resulting direction vector - */ -direction operator+(const direction &lhs, const direction &rhs); - -/** - * @brief Addition assignment - * - * Adds two direction vectors. The result is assigned the left one. this is equivalent to lhs=lhs+rhs. - * - * @param &lhs the left operand - * - * @param &rhs the right operand - * - * @return the updated lhs vector - */ -direction &operator+=(direction &lhs, const direction &rhs); - -/** - * @brief Subtraction operator - * - * Subtracts two direction vectors. - * - * @param &lhs the left operand - * - * @param &rhs the right operand - * - * @return the resulting direction vector - */ -direction operator-(const direction &lhs, const direction &rhs); - -/** - * @brief Subtraction assignment - * - * Subtracts two direction vectors. The result is assigned the left one. this is equivalent to lhs=lhs-rhs. - * - * @param &lhs the left operand - * - * @param &rhs the right operand - * - * @return the updated lhs vector - */ -direction &operator-=(direction &lhs, const direction &rhs); - -/** - * @brief Multiplication operator - * - * Multiplies a direction vector by a scalar. - * - * @param &lhs the direction vector - * - * @param &rhs the scalar - * - * @return the scaled direction vector - */ -direction operator*(const direction &lhs, const float &rhs); - -/** - * @brief Multiplication operator - * - * Multiplies a direction vector by a scalar. - * - * @param &lhs the scalar - * - * @param &rhs the direction vector - * - * @return the scaled direction vector - */ -direction operator*(const float &lhs, const direction &rhs); - -/** - * @brief Multiplication assignment - * - * Multiplies a direction vector by a scalar and assigns the result to the original vector. This is equivalent to - * lhs=lhs*rhs. - * - * @param &lhs the direction vector - * - * @param &rhs the scalar - * - * @return the updated lhs vector - */ -direction &operator*=(direction &lhs, const float &rhs); - -/** - * @brief Dot product - * - * Calculates the dot product of two direction vectors. - * - * @param &lhs the left operand - * - * @param &rhs the right operand - * - * @return the dot product - */ -float dot(const direction &lhs, const direction &rhs); - /** * @brief Cross product * diff --git a/lib/geometry/geometry_exception.cpp b/lib/geometry/geometry_exception.cpp deleted file mode 100644 index 73f0f12..0000000 --- a/lib/geometry/geometry_exception.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by chais on 03.08.15. -// - -#include "geometry_exception.h" diff --git a/lib/geometry/geometry_exception.h b/lib/geometry/geometry_exception.h deleted file mode 100644 index d05ec94..0000000 --- a/lib/geometry/geometry_exception.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// Created by chais on 03.08.15. -// - -#include - -#ifndef RAY_TRACER_GEOMETRY_EXCEPTION_H -#define RAY_TRACER_GEOMETRY_EXCEPTION_H - -class geometry_exception : std::runtime_error{ -public: - geometry_exception(const std::string &__arg) : runtime_error(__arg) { } - geometry_exception(const char *msg) : runtime_error(msg){ } -}; - -#endif //RAY_TRACER_GEOMETRY_EXCEPTION_H \ No newline at end of file diff --git a/lib/geometry/intersection.h b/lib/geometry/intersection.h index d9c0460..d3ca36e 100644 --- a/lib/geometry/intersection.h +++ b/lib/geometry/intersection.h @@ -5,10 +5,12 @@ #ifndef RAY_TRACER_INTERSECTION_H #define RAY_TRACER_INTERSECTION_H -#include "shape.h" #include "normal.h" +#include "point.h" #include "../math/vec2.h" +class shape; + struct intersection { shape *object = nullptr; normal *norm = nullptr; diff --git a/lib/geometry/material/lambertian_material.cpp b/lib/geometry/material/lambertian_material.cpp index cba782b..8e793e7 100644 --- a/lib/geometry/material/lambertian_material.cpp +++ b/lib/geometry/material/lambertian_material.cpp @@ -4,7 +4,7 @@ #include "lambertian_material.h" -lambertian_material::lambertian_material(color col, float ambient, float diffuse) : col(col), ambient(ambient), +lambertian_material::lambertian_material(color col, float ambient, float diffuse) : solid_material(col), ambient(ambient), diffuse(diffuse) { } std::ostream &operator<<(std::ostream &out, const lambertian_material &a) { diff --git a/lib/geometry/material/material.h b/lib/geometry/material/material.h index c38437e..c076d0e 100644 --- a/lib/geometry/material/material.h +++ b/lib/geometry/material/material.h @@ -12,34 +12,24 @@ /** * @name material - * * @brief Abstract material class - * - * Defines the interface every material has to implement. + * @details Defines the interface every material has to implement. */ class material { -private: +protected: material() {}; public: /** * @brief Shading - * - * Determines the intensity of the material's color at the specified texture coordinates, based on light- and - * viewing direction as well as the normal and whether the material is viewed from the inside or the outside. - * + * Determines the intensity of the material's color at the specified texture coordinates, based on light- + * and viewing direction as well as the normal and whether the material is viewed from the inside or the outside. * @param &lcol the color of the light - * * @param &l the direction the light is in. Expected to be a 0 vector for ambient light. - * * @param &n the normal at the point that is being shaded - * * @param &v the direction the ray is coming from - * * @param &pos the texture coordinates as calculated by shape::intersect_full - * * @param internal a flag denoting whether the ray originated from inside or outside the shape this material belongs * to. - * * @return the base color multiplied by a factor according to the viewing situation */ virtual color shade(const color &lcol, const direction &l, const normal &n, const direction &v, const vec2 &pos, const bool internal) = 0; diff --git a/lib/geometry/material/phong_material.cpp b/lib/geometry/material/phong_material.cpp index d874b1c..b5c42e4 100644 --- a/lib/geometry/material/phong_material.cpp +++ b/lib/geometry/material/phong_material.cpp @@ -5,7 +5,7 @@ #include "phong_material.h" phong_material::phong_material(color col, float ambient, float diffuse, float specular, - float exponent) : col(col), ambient(ambient), diffuse(diffuse), specular(specular), + float exponent) : solid_material(col), ambient(ambient), diffuse(diffuse), specular(specular), exponent(exponent) { } std::ostream &operator<<(std::ostream &out, const phong_material &a) { @@ -23,8 +23,8 @@ color phong_material::shade(const color &lcol, const direction &l, const normal float phi = std::max(0.0, dot(n, l)); if (phi > 0) { direction r = n*(2*phi)-l; - return scale(this->col, lcol*(this->diffuse*phi)+ - lcol*(std::pow(std::max(0.0, dot(v, r)), this->exponent)*this->specular)); + return scale(this->col, lcol*(this->diffuse*phi))+ + lcol*(std::pow(std::max(0.0, dot(v, r)), this->exponent)*this->specular); } } } else diff --git a/lib/geometry/material/solid_material.cpp b/lib/geometry/material/solid_material.cpp new file mode 100644 index 0000000..c30f321 --- /dev/null +++ b/lib/geometry/material/solid_material.cpp @@ -0,0 +1,7 @@ +// +// Created by chais on 10.09.15. +// + +#include "solid_material.h" + +solid_material::solid_material(const color &col) : col(col) { } \ No newline at end of file diff --git a/lib/geometry/material/solid_material.h b/lib/geometry/material/solid_material.h index 5367ece..0fc50ea 100644 --- a/lib/geometry/material/solid_material.h +++ b/lib/geometry/material/solid_material.h @@ -17,6 +17,7 @@ class solid_material : public material { protected: color col; + solid_material(const color &col); }; #endif //RAY_TRACER_SOLID_MATERIAL_H diff --git a/lib/geometry/normal.cpp b/lib/geometry/normal.cpp index 0574679..e755bc6 100644 --- a/lib/geometry/normal.cpp +++ b/lib/geometry/normal.cpp @@ -10,9 +10,4 @@ normal::normal(const float &x, const float &y, const float &z) : vec4(x, y, z, 0 normal::normal(const vec4 &in) : vec4(in[0], in[1], in[2], 0) { } -normal::normal(const normal &in) : vec4(in) { } - -std::ostream &operator<<(std::ostream &out, const normal &a) { - out << vec4::operator<<(out, dynamic_cast(a)); - return out; -} +normal::normal(const normal &in) : vec4(in) { } \ No newline at end of file diff --git a/lib/geometry/normal.h b/lib/geometry/normal.h index 9d6a8f5..cbedbe5 100644 --- a/lib/geometry/normal.h +++ b/lib/geometry/normal.h @@ -54,19 +54,6 @@ class normal : public vec4 { * @param &in the original vector */ normal(const normal &in); - - /** - * @brief Output operator - * - * Puts the vector on an output stream in an Octave/Matlab-compatible format. - * - * @param &out the output stream - * - * @param &a the vector - * - * @return the output stream - */ - friend std::ostream &operator<<(std::ostream &out, const normal &a); }; #endif //RAY_TRACER_NORMAL_H \ No newline at end of file diff --git a/lib/geometry/point.cpp b/lib/geometry/point.cpp index a701f1b..2f63099 100644 --- a/lib/geometry/point.cpp +++ b/lib/geometry/point.cpp @@ -12,20 +12,15 @@ point::point(const vec4 &in) : vec4(in[0], in[1], in[2], 1) { } point::point(const point &in) : vec4(in) { } -std::ostream &operator<<(std::ostream &out, const point &a) { - out << vec4::operator<<(out, dynamic_cast(a)); - return out; -} - point operator+(const point &lhs, const direction &rhs) { - return point(dynamic_cast(lhs)+dynamic_cast(rhs)); + return point(dynamic_cast(lhs)+dynamic_cast(rhs)); } point &operator+=(point &lhs, const direction &rhs) { - dynamic_cast(lhs)+= dynamic_cast(rhs); + dynamic_cast(lhs) += dynamic_cast(rhs); return lhs; } direction operator-(const point &lhs, const point &rhs) { - return direction(dynamic_cast(lhs)-dynamic_cast(rhs)); + return direction(dynamic_cast(lhs)-dynamic_cast(rhs)); } \ No newline at end of file diff --git a/lib/geometry/point.h b/lib/geometry/point.h index 2611095..edbb8fd 100644 --- a/lib/geometry/point.h +++ b/lib/geometry/point.h @@ -54,19 +54,6 @@ class point : public vec4 { * @param &in the original vector */ point(const point &in); - - /** - * @brief Output operator - * - * Puts the vector on an output stream in an Octave/Matlab-compatible format. - * - * @param &out the output stream - * - * @param &a the vector - * - * @return the output stream - */ - friend std::ostream &operator<<(std::ostream &out, const point &a); }; /** diff --git a/lib/geometry/ray.cpp b/lib/geometry/ray.cpp new file mode 100644 index 0000000..3f2bb86 --- /dev/null +++ b/lib/geometry/ray.cpp @@ -0,0 +1,7 @@ +// +// Created by chais on 09.09.15. +// + +#include "ray.h" + +ray::ray(const point &o, const direction &d) : o(o), d(normalise(d)) { } diff --git a/lib/geometry/ray.h b/lib/geometry/ray.h index e3f4973..dc03f43 100644 --- a/lib/geometry/ray.h +++ b/lib/geometry/ray.h @@ -7,9 +7,12 @@ #include "point.h" -struct ray { +class ray { +public: point o; direction d; + + ray(const point &o, const direction &d); }; #endif //RAY_TRACER_RAY_H diff --git a/lib/geometry/shape.cpp b/lib/geometry/shape.cpp index 6d02841..c06d827 100644 --- a/lib/geometry/shape.cpp +++ b/lib/geometry/shape.cpp @@ -4,8 +4,29 @@ #include "shape.h" -shape::shape(material *matrl) : transforms(transform()), matrl(matrl) { } +shape::shape(material *matrl) : object_to_world(transform()), world_to_object(object_to_world.inv_trans, object_to_world.trans), matrl(matrl) { } -color shape::shade(const direction &l, const normal &n, const direction &v, const vec2 &pos, const bool internal) { - return this->matrl->shade(l, n, v, pos, internal); +color shape::shade(const color &lcol, const direction &l, const normal &n, const direction &v, const vec2 &pos, + const bool internal) { + return this->matrl->shade(lcol, l, n, v, pos, internal); +} + +void shape::translate(const direction &t) { + this->object_to_world.translate(t); +} + +void shape::scale(const std::array sf) { + this->object_to_world.scale(sf); +} + +void shape::rotateX(const float &angle) { + this->object_to_world.rotateX(angle); +} + +void shape::rotateY(const float &angle) { + this->object_to_world.rotateY(angle); +} + +void shape::rotateZ(const float &angle) { + this->object_to_world.rotateZ(angle); } diff --git a/lib/geometry/shape.h b/lib/geometry/shape.h index a057ef4..990c047 100644 --- a/lib/geometry/shape.h +++ b/lib/geometry/shape.h @@ -2,8 +2,8 @@ // Created by chais on 02.08.15. // -#ifndef RAY_TRACER_GEOMETRY_H -#define RAY_TRACER_GEOMETRY_H +#ifndef RAY_TRACER_SHAPE_H +#define RAY_TRACER_SHAPE_H #include "ray.h" #include "material/material.h" @@ -12,18 +12,31 @@ #include "color.h" class shape { +private: + shape() {}; protected: - transform transforms; + transform object_to_world; + transform world_to_object; material *matrl; -public: shape(material *matrl); - virtual intersection intersect_full(ray r) = 0; +public: + virtual intersection intersect_full(const ray &r) = 0; + + virtual bool intersect_shadow(const ray &r) = 0; - virtual bool intersect_shadow(vec3 origin, vec3 direction) = 0; + /** + * @copydoc material::shade(const color &lcol,const direction &l,const normal &n,const direction &v,const vec2 &pos,const bool internal) + */ + virtual color shade(const color &lcol, const direction &l, const normal &n, const direction &v, const vec2 &pos, + const bool internal); - virtual color shade(const direction &l, const normal &n, const direction &v, const vec2 &pos, const bool internal); + void translate(const direction &t); + void scale(const std::array sf); + void rotateX(const float &angle); + void rotateY(const float &angle); + void rotateZ(const float &angle); }; -#endif //RAY_TRACER_GEOMETRY_H +#endif //RAY_TRACER_SHAPE_H diff --git a/lib/geometry/sphere.cpp b/lib/geometry/sphere.cpp index 36ddfdc..1d287fb 100644 --- a/lib/geometry/sphere.cpp +++ b/lib/geometry/sphere.cpp @@ -4,50 +4,45 @@ #include "sphere.h" -sphere::sphere(double radius, material *matrl) : radius(radius), shape(matrl) { - if (radius <= 0) - throw new geometry_exception("The radius has to be greater than zero."); +sphere::sphere(float radius, material *matrl) : radius(radius), shape(matrl) { + assert(radius > 0); } std::ostream &operator<<(std::ostream &out, const sphere &a) { - out << "Radius: " << a.radius << ", Transformations: " << a.transforms << ", inverse transformations: " << - a.inv_trans;; + out << "Radius: " << a.radius << ", Transformations: " << a.object_to_world; return out; } -ray sphere::intersect(ray r) { - mat4 m = this->getTransforms(); - mat4 im = this->getInvTransforms(); - ray tr = ray(im*r.getOrigin(), transform(im, r.getDirection())); - vec3 c = -tr.getOrigin(); - double a = std::max(0.0, dot(tr.getDirection(), c)); - double b = std::sqrt(std::pow(length(c), 2)-std::pow(a, 2)); - if (b < this->radius-1E-12) { - double d = std::sqrt(std::pow(this->radius, 2)-std::pow(b, 2)); - vec3 x; - if (d < a-1E-12) - x = tr.getOrigin()+tr.getDirection()*(a-d); +intersection sphere::intersect_full(const ray &r) { + ray tr = this->world_to_object(r); + direction c = -tr.o; + float a = std::max(float(0.0), dot(tr.d, c)); + float b = std::sqrt(std::pow(length(c), 2)-std::pow(a, 2)); + intersection out = intersection(); + if (b < this->radius-1E-7) { + float d = std::sqrt(std::pow(this->radius, 2)-std::pow(b, 2)); + point *x; + if (d < a-1E-7) + x = new point(tr.o+direction(tr.d*(a-d))); else - x = tr.getOrigin()+tr.getDirection()*(a+d); - vec3 dir = x; - double local_len = length(x); - vec3 col = this->getColor(x[0]/local_len, x[1]/local_len); - x = m*x; - dir = transform(transpose(im), dir); - return ray(x, dir, col); + x = new point(tr.o+direction(tr.d*(a+d))); + normal *norm = new normal(*x); + float local_len = length(direction(*x)); + vec2 *local_pos = new vec2((*x)[0]/local_len, (*x)[1]/local_len); + *x = this->object_to_world(*x); + *norm = normalise(this->object_to_world(*norm)); + out.object = this; + out.norm = norm; + out.pos = x; + out.local_pos = local_pos; } - throw geometry_exception("No intersection"); + return out; } -bool sphere::intersect_shadow(vec3 origin, vec3 direction) { - mat4 im = this->getInvTransforms(); - ray tr = ray(im*origin, transform(im, direction)); - vec3 c = -tr.getOrigin(); - double a = dot(tr.getDirection(), c); - double b = std::sqrt(std::pow(length(c), 2)-std::pow(a, 2)); +bool sphere::intersect_shadow(const ray &r) { + ray tr = this->world_to_object(r); + direction c = -tr.o; + float a = std::max(float(0.0), dot(tr.d, c)); + float b = std::sqrt(std::pow(length(c), 2)-std::pow(a, 2)); return (a > 0 && b < this->radius); } - -vec3 sphere::getColor(double u, double v) { - return this->getMaterial()->getColor(u, v); -} diff --git a/lib/geometry/sphere.h b/lib/geometry/sphere.h index 0fb1e05..f0e8510 100644 --- a/lib/geometry/sphere.h +++ b/lib/geometry/sphere.h @@ -6,21 +6,19 @@ #define RAY_TRACER_SPHERE_H #include "shape.h" -#include "geometry_exception.h" +#include class sphere : public shape { private: - double radius; + float radius; public: - sphere(double radius, material *matrl); + sphere(float radius, material *matrl); friend std::ostream &operator<<(std::ostream &out, const sphere &a); - virtual ray intersect(ray r) override; + virtual intersection intersect_full(const ray &r); - virtual bool intersect_shadow(vec3 origin, vec3 direction) override; - - virtual vec3 getColor(double u, double v); + virtual bool intersect_shadow(const ray &r); }; #endif //RAY_TRACER_SPHERE_H diff --git a/lib/geometry/transform.cpp b/lib/geometry/transform.cpp index 2753f55..a396362 100644 --- a/lib/geometry/transform.cpp +++ b/lib/geometry/transform.cpp @@ -4,26 +4,37 @@ #include "transform.h" -transform::transform() : trans(mat4()), inv_trans(mat4()) { } +transform::transform() : trans(new mat4()), inv_trans(new mat4()) { } -transform::transform(const mat4 &trans, const mat4 &inv_trans) : trans(trans), inv_trans(inv_trans) { } +transform::transform(mat4 *trans) : trans(trans), inv_trans(new mat4(invert(*trans))) { } + +transform::transform(mat4 *trans, mat4 *inv_trans) : trans(trans), inv_trans(inv_trans) { } transform::transform(const transform &in) : trans(in.trans), inv_trans(in.inv_trans) { } transform transform::operator()(const transform &t) const { - return transform(this->trans*t.trans, t.inv_trans*this->inv_trans); + return transform(new mat4(*this->trans*(*t.trans)), new mat4(*t.inv_trans*(*this->inv_trans))); } point transform::operator()(const point &p) const { - return point(this->trans*p); + return point(*this->trans*p); } direction transform::operator()(const direction &v) const { - return direction(this->trans*v); + return direction(*this->trans*v); } normal transform::operator()(const normal &n) const { - return normal(transpose(this->inv_trans)*n); + return normal(transpose(*this->inv_trans)*n); +} + +ray transform::operator()(const ray &r) const { + return ray(*this->trans*r.o, *this->trans*r.d); +} + +std::ostream &operator<<(std::ostream &out, const transform &a) { + out << "Transform: " << a.trans << ", Inverse: " << a.inv_trans; + return out; } void transform::translate(const direction t) { @@ -39,8 +50,8 @@ void transform::translate(const direction t) { {0, 0, 1, -t[2]}, {0, 0, 0, 1} }}; - this->trans = this->trans*mat4(tmp); - this->inv_trans = mat4(itmp)*this->inv_trans; + *this->trans = mat4(tmp)*(*this->trans); + *this->inv_trans = *this->inv_trans*mat4(itmp); } void transform::scale(const std::array sf) { @@ -49,15 +60,15 @@ void transform::scale(const std::array sf) { {0, sf[1], 0, 0}, {0, 0, sf[2], 0}, {0, 0, 0, 1} - }}; + }}; std::array, 4> itmp = {{ {1/sf[0], 0, 0, 0}, {0, 1/sf[1], 0, 0}, {0, 0, 1/sf[2], 0}, {0, 0, 0, 1} - }}; - this->trans = this->trans*mat4(tmp); - this->inv_trans = mat4(itmp)*this->inv_trans; + }}; + *this->trans = mat4(tmp)*(*this->trans); + *this->inv_trans = *this->inv_trans*mat4(itmp); } void transform::rotateX(const float &angle) { @@ -88,8 +99,8 @@ void transform::rotateX(const float &angle) { {0, -s, c, 0}, {0, 0, 0, 1} }}; - this->trans = this->trans*mat4(tmp); - this->inv_trans = mat4(itmp)*this->inv_trans; + *this->trans = mat4(tmp)*(*this->trans); + *this->inv_trans = *this->inv_trans*mat4(itmp); } void transform::rotateY(const float &angle) { @@ -120,24 +131,24 @@ void transform::rotateY(const float &angle) { {s, 0, c, 0}, {0, 0, 0, 1} }}; - this->trans = this->trans*mat4(tmp); - this->inv_trans = mat4(itmp)*this->inv_trans; + *this->trans = mat4(tmp)*(*this->trans); + *this->inv_trans = *this->inv_trans*mat4(itmp); } void transform::rotateZ(const float &angle) { float a = helper::to_radians(angle); /*std::array, 4> tmp = {{ - {cos(a), -sin(a), 0, 0}, - {sin(a), cos(a), 0, 0}, + {std::cos(a), -std::sin(a), 0, 0}, + {std::sin(a), std::cos(a), 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} }}; std::array, 4> itmp = {{ - {cos(-a), -sin(-a), 0, 0}, - {sin(-a), cos(-a), 0, 0}, + {std::cos(-a), -std::sin(-a), 0, 0}, + {std::sin(-a), std::cos(-a), 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} - }};*/ + }};*/ float c = std::cos(a); float s = std::sin(a); std::array, 4> tmp = {{ @@ -152,6 +163,6 @@ void transform::rotateZ(const float &angle) { {0, 0, 1, 0}, {0, 0, 0, 1} }}; - this->trans = this->trans*mat4(tmp); - this->inv_trans = mat4(itmp)*this->inv_trans; + *this->trans = mat4(tmp)*(*this->trans); + *this->inv_trans = *this->inv_trans*mat4(itmp); } diff --git a/lib/geometry/transform.h b/lib/geometry/transform.h index 6ae4cca..4662cd5 100644 --- a/lib/geometry/transform.h +++ b/lib/geometry/transform.h @@ -10,6 +10,7 @@ #include "normal.h" #include #include "../math/helper.h" +#include "ray.h" /** * @name transform @@ -21,10 +22,10 @@ * inverse transformation is applied to the inverse matrix from the opposite direction. */ class transform { -private: - mat4 trans; - mat4 inv_trans; public: + mat4 *trans; + mat4 *inv_trans; + /** * @brief Default constructor * @@ -32,13 +33,20 @@ class transform { */ transform(); + /** + * @brief Explicit constructor + * + * Copies the values of the input matrix into its own matrices. For world_to_object the input matrix is inverted. + */ + transform(mat4 *trans); + /** * @brief Explicit constructor * * Copies the values of the input matrices into its own matrices. If the input matrices aren't each other's inverse * the results will be incorrect. */ - transform(const mat4 &trans, const mat4 &inv_trans); + transform(mat4 *trans, mat4 *inv_trans); /** * @brief Copy constructor @@ -92,6 +100,19 @@ class transform { */ normal operator()(const normal &n) const; + /** + * @brief Transform application to ray + * + * Applies its inverse transformations to the given ray. + * + * @param &r the ray to be transformed + * + * @return the new, transformed ray + */ + ray operator()(const ray &r) const; + + friend std::ostream &operator<<(std::ostream &out, const transform &a); + /** * @brief Translate transform * diff --git a/lib/light/ambient_light.cpp b/lib/light/ambient_light.cpp index ab9f55b..49fcfe6 100644 --- a/lib/light/ambient_light.cpp +++ b/lib/light/ambient_light.cpp @@ -4,12 +4,17 @@ #include "ambient_light.h" -ambient_light::ambient_light(color col) : light(col) {} +ambient_light::ambient_light(color col) : light(col) { } std::ostream &operator<<(std::ostream &out, const ambient_light &a) { - out << "Ambient light: color [r, g, b]: " << rgb(a.col) << ", direction: " << a.dir; + out << "Ambient light: color [r, g, b]: " << a.col; return out; } -color &ambient_light::emit(const direction &dir) const { + +direction &ambient_light::get_direction(const point &pos) { + return this->dir; +} + +color &ambient_light::emit(const direction &dir) { return this->col; } diff --git a/lib/light/ambient_light.h b/lib/light/ambient_light.h index f1876aa..cdf3c8d 100644 --- a/lib/light/ambient_light.h +++ b/lib/light/ambient_light.h @@ -13,7 +13,10 @@ class ambient_light : public light { public: ambient_light(color col); friend std::ostream &operator<<(std::ostream &out, const ambient_light &a); - virtual color &emit(const direction &dir) const; + + virtual direction &get_direction(const point &pos); + + virtual color &emit(const direction &dir); }; #endif //RAY_TRACER_AMBIENT_LIGHT_H diff --git a/lib/light/light.cpp b/lib/light/light.cpp index 9d6ee04..b719b5b 100644 --- a/lib/light/light.cpp +++ b/lib/light/light.cpp @@ -5,9 +5,6 @@ #include "light.h" #include "../geometry/direction.h" -light::light(const color &col) : col(col) { } +light::light(const color &col) : col(col), dir(direction()) { } -std::ostream &operator<<(std::ostream &out, const light &a) { - out << "Ambient light: color [r, g, b]: " << rgb(a.col); - return out; -} \ No newline at end of file +light::light(const color &col, const direction &dir) : col(col), dir(normalise(dir)) { } diff --git a/lib/light/light.h b/lib/light/light.h index 3d4dfd6..eb2c8cc 100644 --- a/lib/light/light.h +++ b/lib/light/light.h @@ -2,23 +2,26 @@ // Created by chais on 06.08.15. // -#ifndef RAY_TRACER_AMBIENT_LIGHT_H -#define RAY_TRACER_AMBIENT_LIGHT_H +#ifndef RAY_TRACER_LIGHT_H +#define RAY_TRACER_LIGHT_H #include -#include "../geometry/direction.h" #include "../geometry/color.h" +#include "../geometry/point.h" class light { protected: color col; + direction dir; light(const color &col); + light(const color &col, const direction &dir); + public: - friend std::ostream &operator<<(std::ostream &out, const light &a); + virtual direction &get_direction(const point &pos) = 0; - virtual color &emit(const direction &dir) const = 0; + virtual color &emit(const direction &dir) = 0; }; -#endif //RAY_TRACER_AMBIENT_LIGHT_H +#endif //RAY_TRACER_LIGHT_H diff --git a/lib/light/parallel_light.cpp b/lib/light/parallel_light.cpp index f76ee5e..754ccf9 100644 --- a/lib/light/parallel_light.cpp +++ b/lib/light/parallel_light.cpp @@ -4,17 +4,17 @@ #include "parallel_light.h" -parallel_light::parallel_light(const color &col, const direction &dir) : light(col), dir(dir) { } +parallel_light::parallel_light(const color &col, const direction &dir) : light(col, dir) { } std::ostream &operator<<(std::ostream &out, const parallel_light &a) { - out << "Parallel light: color [r, g, b]: " << rgb(a.col) << ", direction: " << a.dir; + out << "Parallel light: color [r, g, b]: " << a.col << ", direction: " << a.dir; return out; } -const direction ¶llel_light::get_direction() const { +direction ¶llel_light::get_direction(const point &pos) { return this->dir; } -color ¶llel_light::emit(const direction &dir) const { +color ¶llel_light::emit(const direction &dir) { return this->col; } diff --git a/lib/light/parallel_light.h b/lib/light/parallel_light.h index 45ef191..3151255 100644 --- a/lib/light/parallel_light.h +++ b/lib/light/parallel_light.h @@ -8,16 +8,14 @@ #include "light.h" class parallel_light : public light { -protected: - direction dir; public: parallel_light(const color &col, const direction &dir); friend std::ostream &operator<<(std::ostream &out, const parallel_light &a); - const direction &get_direction() const; + virtual direction &get_direction(const point &pos); - virtual color &emit(const direction &dir) const; + virtual color &emit(const direction &dir); }; #endif //RAY_TRACER_PARALLEL_LIGHT_H diff --git a/lib/math/mat4.cpp b/lib/math/mat4.cpp index 847248a..120328e 100644 --- a/lib/math/mat4.cpp +++ b/lib/math/mat4.cpp @@ -4,7 +4,7 @@ mat4::mat4() { m = {{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}}; } -mat4::mat4(const std::array, 4> &in) { +mat4::mat4(const std::array, 4> &in) { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) m[i][j] = in[i][j]; @@ -28,7 +28,7 @@ std::array mat4::operator[](const unsigned long i) { return this->m[i]; } -const std::array mat4::operator[](const unsigned long i) const { +const std::array mat4::operator[](const unsigned long i) const { assert(0 <= i <= 3); return this->m[i]; } diff --git a/lib/math/mat4.h b/lib/math/mat4.h index 5841671..9449dd6 100644 --- a/lib/math/mat4.h +++ b/lib/math/mat4.h @@ -70,7 +70,7 @@ class mat4 { * * Allows access to the matrix' values */ - const std::array operator[](const unsigned long i) const; + const std::array operator[](const unsigned long i) const; /** * @brief Stream output diff --git a/lib/math/vec2.cpp b/lib/math/vec2.cpp index fafe425..a60287a 100644 --- a/lib/math/vec2.cpp +++ b/lib/math/vec2.cpp @@ -8,7 +8,7 @@ vec2::vec2(const float &u, const float &v) { a = {u, v}; } -vec2::vec2(const std::array &in) { +vec2::vec2(const std::array &in) { a = {in[0], in[1]}; } @@ -47,7 +47,7 @@ vec2 &operator+=(vec2 &lhs, const vec2 &rhs) { } vec2 operator-(const vec2 &lhs, const vec2 &rhs) { - std::array tmp = { + std::array tmp = { lhs[0]-rhs[0], lhs[1]-rhs[1] }; @@ -61,7 +61,7 @@ vec2 &operator-=(vec2 &lhs, const vec2 &rhs) { } vec2 operator-(const vec2 &rhs) { - std::array tmp = { + std::array tmp = { -rhs[0], -rhs[1] }; @@ -74,7 +74,7 @@ std::ostream &operator<<(std::ostream &out, const vec2 &a) { } vec2 operator*(const vec2 &lhs, const float &rhs) { - std::array tmp = { + std::array tmp = { lhs[0]*rhs, lhs[1]*rhs }; @@ -82,7 +82,7 @@ vec2 operator*(const vec2 &lhs, const float &rhs) { } vec2 operator*(const float &lhs, const vec2 &rhs) { - std::array tmp = { + std::array tmp = { lhs*rhs[0], lhs*rhs[1] }; @@ -94,7 +94,7 @@ float dot(const vec2 &lhs, const vec2 &rhs) { } vec2 scale(const vec2 &a, const float f[2]) { - std::array tmp = { + std::array tmp = { a[0]*f[0], a[1]*f[1] }; @@ -107,7 +107,7 @@ float length(const vec2 &a) { vec2 normalise(const vec2 &a) { float il = 1/length(a); - std::array tmp = { + std::array tmp = { a[0]*il, a[1]*il }; diff --git a/lib/math/vec2.h b/lib/math/vec2.h index 3954c3a..f61b1eb 100644 --- a/lib/math/vec2.h +++ b/lib/math/vec2.h @@ -50,7 +50,7 @@ class vec2 { * * @param &in the std::array of values */ - vec2(const std::array &in); + vec2(const std::array &in); /** * @brief Copy constructor diff --git a/lib/math/vec4.cpp b/lib/math/vec4.cpp index 54cc064..98aecee 100644 --- a/lib/math/vec4.cpp +++ b/lib/math/vec4.cpp @@ -1,5 +1,4 @@ #include "vec4.h" -#include "helper.h" vec4::vec4() { a = {0, 0, 0, 0}; @@ -9,7 +8,7 @@ vec4::vec4(const float &x, const float &y, const float &z, const float &w) { a = {x, y, z, w}; } -vec4::vec4(const std::array &in) { +vec4::vec4(const std::array &in) { a = {in[0], in[1], in[2], in[3]}; } @@ -17,9 +16,6 @@ vec4::vec4(const vec4 &in) { a = {in.a[0], in.a[1], in.a[2], in.a[3]}; } -vec4::~vec4() { -} - vec4 &vec4::operator=(const vec4 &in) { this->a[0] = in.a[0]; this->a[1] = in.a[1]; @@ -115,8 +111,8 @@ bool operator==(const vec4 &lhs, const vec4 &rhs) { } bool operator!=(const vec4 &lhs, const vec4 &rhs) { - return !(helper::almost_equal(lhs[0], rhs[0], 1) || helper::almost_equal(lhs[1], rhs[1], 1) || - helper::almost_equal(lhs[2], rhs[2], 1) || helper::almost_equal(lhs[3], rhs[3], 1)); + return !(helper::almost_equal(lhs[0], rhs[0], 1) && helper::almost_equal(lhs[1], rhs[1], 1) && + helper::almost_equal(lhs[2], rhs[2], 1) && helper::almost_equal(lhs[3], rhs[3], 1)); } float dot(const vec4 &lhs, const vec4 &rhs) { @@ -134,7 +130,7 @@ vec4 scale(const vec4 &a, const float f[4]) { } float length(const vec4 &a) { - return sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3])); + return std::sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+a[3]*a[3]); } vec4 normalise(const vec4 &a) { diff --git a/lib/math/vec4.h b/lib/math/vec4.h index c59164c..7f0c360 100644 --- a/lib/math/vec4.h +++ b/lib/math/vec4.h @@ -12,6 +12,7 @@ #include #include #include +#include "helper.h" /** * @name vec4 @@ -54,7 +55,7 @@ class vec4 { * * @param &in the values */ - vec4(const std::array &in); + vec4(const std::array &in); /** * @brief Copy constructor @@ -63,16 +64,14 @@ class vec4 { */ vec4(const vec4 &in); - virtual ~vec4(); - -/** + /** * @brief Assignment operator * * Assigns the values from the given vector. * * @param &in the rvalue vector */ - vec4 &operator=(const vec4 &in); + virtual vec4 &operator=(const vec4 &in); /** * @brief Array subscript diff --git a/lib/whitted_rt.cpp b/lib/whitted_rt.cpp index 6050b7d..7d42c12 100644 --- a/lib/whitted_rt.cpp +++ b/lib/whitted_rt.cpp @@ -3,18 +3,24 @@ // #include "whitted_rt.h" -#include "geometry/geometry_exception.h" -#include "light/parallel_light.h" -whitted_rt::whitted_rt(const vec3 &backgroundColor, perspective_camera &cam, const std::vector &lights, - const std::vector &scene) : backgroundColor(backgroundColor), cam(cam), lights(lights), - scene(scene) { } +whitted_rt::whitted_rt(const color &background_color, camera *cam, const std::vector &lights, + const std::vector &scene, const unsigned long &max_bounces) : background_color( + background_color), cam(cam), lights(lights), scene(scene), max_bounces(max_bounces) { } -vec3 whitted_rt::cast_ray(ray r, int step, bool internal) { - try { - whitted_rt::intersect intersection = this->find_nearest(r); - shape *object = intersection.object; - ray normal = intersection.normal; +color whitted_rt::cast_ray(ray r, int step, bool internal) { + intersection is = this->find_nearest(r); + if (is.object == nullptr) // No intersection + return this->background_color; + color out = color(); + for (light *l : lights) { + direction light_dir = l->get_direction(*is.pos); + if (!this->cast_shadow(ray (*is.pos, -light_dir))) + out += is.object->shade(l->emit(light_dir), -light_dir, *is.norm, -r.d, *is.local_pos, internal); + } + return out; + /*try { + intersection is = this->find_nearest(r); vec3 *base_color = normal.getColor(); vec3 *reflect_color = new vec3(); vec3 *refract_color = new vec3(); @@ -28,10 +34,10 @@ vec3 whitted_rt::cast_ray(ray r, int step, bool internal) { vec3 *dc = new vec3(); vec3 *sc = new vec3(); for (light *light : lights) { - if (parallel_light *l = dynamic_cast(light)) { + if (parallel_light*l = dynamic_cast(light)) { if (!internal) { vec3 light_dir = -l->getDirection(); - if (this->cast_shadow(normal.getOrigin(), light_dir)) + if (this->cast_shadow(normal.getOrigin())) continue; double phi = std::max(0.0, dot(normal.getDirection(), light_dir)); if (phi > 0) { @@ -49,7 +55,7 @@ vec3 whitted_rt::cast_ray(ray r, int step, bool internal) { double lw[] = {(*light_weight)[0], (*light_weight)[1], (*light_weight)[2]}; delete light_weight; *base_color = (scale(*base_color, lw)+*sc)*(1-ref-t); - // Reflect + /* Reflect if (ref > 0) { double phi = std::max(0.0, dot(normal.getDirection(), view_dir)); vec3 reflect_dir = normal.getDirection()*(2*phi)-view_dir; @@ -70,36 +76,41 @@ vec3 whitted_rt::cast_ray(ray r, int step, bool internal) { } } return *base_color+*reflect_color+*refract_color; - } catch (geometry_exception &e) { } - return this->backgroundColor; + }*/ } void whitted_rt::render() { - for (ray &r : cam) - r.setColor(cast_ray(r, 0, false)); + const std::array resolution = this->cam->get_resolution(); + for (unsigned long y = 0; y < resolution[1]; y++) + for (unsigned long x = 0; x < resolution[0]; x++) { + std::vector *rays = this->cam->get_rays(x, y); + std::vector data; + data.reserve(rays->size()); + for (auto &r : *rays) + data.push_back(cast_ray(r, 0, false)); + this->cam->set_data(x, y, data); + } } -bool whitted_rt::cast_shadow(vec3 origin, vec3 direction) { +bool whitted_rt::cast_shadow(const ray &r) { for (shape *obstacle : this->scene) - if (obstacle->intersect_shadow(origin, direction)) + if (obstacle->intersect_shadow(r)) return true; return false; } intersection whitted_rt::find_nearest(ray r) { - struct whitted_rt::intersect out; - double dist = std::numeric_limits::max(); - for (shape *object : scene) - try { - ray normal = object->intersect_full(r); - double new_dist = length(r.getOrigin()-normal.getOrigin()); - if (new_dist < dist) { - dist = new_dist; - out.object = object; - out.normal = normal; - } - } catch (geometry_exception &e) { } - if (dist == std::numeric_limits::max()) - throw geometry_exception("No intersection"); + intersection out = intersection(); + float dist = std::numeric_limits::max(); + for (shape *object : scene) { + intersection cur = object->intersect_full(r); + if (cur.object == nullptr) + continue; + float new_dist = length(r.o-*cur.pos); + if (new_dist < dist) { + dist = new_dist; + out = cur; + } + } return out; } diff --git a/lib/whitted_rt.h b/lib/whitted_rt.h index 5e6027c..5331e70 100644 --- a/lib/whitted_rt.h +++ b/lib/whitted_rt.h @@ -7,26 +7,28 @@ #ifndef RAY_TRACER_WHITTEDRT_H #define RAY_TRACER_WHITTEDRT_H -#include "perspective_camera.h" +#include "camera/camera.h" #include "light/light.h" #include "geometry/shape.h" #include class whitted_rt { private: - const vec3 backgroundColor; - perspective_camera &cam; + const color background_color; + camera *cam; std::vector lights; std::vector scene; + const unsigned long max_bounces; - vec3 cast_ray(ray r, int step, bool internal); + color cast_ray(ray r, int step, bool internal); + + bool cast_shadow(const ray &r); - bool cast_shadow(vec3 origin, vec3 direction); intersection find_nearest(ray r); public: - whitted_rt(const vec3 &backgroundColor, perspective_camera &cam, const std::vector &lights, - const std::vector &scene); + whitted_rt(const color &background_color, camera *cam, const std::vector &lights, + const std::vector &scene, const unsigned long &max_bounces); void render(); }; diff --git a/main.cpp b/main.cpp index bdf8e05..14ac7ab 100644 --- a/main.cpp +++ b/main.cpp @@ -3,44 +3,44 @@ #include "lib/geometry/sphere.h" #include "lib/geometry/material/solid_material.h" #include "lib/light/parallel_light.h" +#include "lib/camera/perspective_camera.h" +#include "lib/geometry/material/phong_material.h" +#include "lib/light/ambient_light.h" #include using namespace std; int main() { - perspective_camera cam = perspective_camera(); - vec3 bgcolor = vec3(); + camera *cam = new perspective_camera(); + color bgcolor = color(); std::vector lights; - lights.push_back(new light(vec3{1, 1, 1})); - lights.push_back(new parallel_light(vec3{1, 1, 1}, vec3{0, -1, 0})); - phong_material lack = phong_material(0.1, 0.6, 0.7, 200); - solid_material *red_lack = new solid_material(vec3{1, 0, 0}, lack, 0, 0, 0); + lights.push_back(new ambient_light(color{1, 1, 1})); + lights.push_back(new parallel_light(color{1, 1, 1}, direction{0, -1, 0})); + phong_material *red_lack = new phong_material(color{1, 0, 0}, 0.1, 0.6, 0.7, 200); std::vector scene; scene.push_back(new sphere(1.0, red_lack)); - scene[0]->translate(vec3{0, -1, -7}); - scene[0]->rotateZ(30); - double sf[] = {2, 1, 1}; + std::array sf = {2, 1, 1}; scene[0]->scale(sf); + scene[0]->rotateZ(30); + scene[0]->translate(direction{0, -1, -7}); scene.push_back(new sphere(1.0, red_lack)); - scene[1]->translate(vec3{0, -4, -1}); sf[0] = 100; sf[1] = 0.1; sf[2] = 100; scene[1]->scale(sf); - whitted_rt rt = whitted_rt(bgcolor, cam, lights, scene); + scene[1]->translate(direction{0, -4, -1}); + whitted_rt rt = whitted_rt(bgcolor, cam, lights, scene, 10); rt.render(); png::image img(1024, 768); png::rgb_pixel *pPtr; - vector::iterator rIt = cam.begin(); - for (int y = 0; y < 768; y++) { + for (unsigned long y = 0; y < 768; y++) { pPtr = &img[y][0]; - for (int x = 0; x < 1024; x++) { - vec3 tmp = to_color(*rIt->getColor()); - (*pPtr).red = int(tmp[0]); - (*pPtr).green = int(tmp[1]); - (*pPtr).blue = int(tmp[2]); + for (unsigned long x = 0; x < 1024; x++) { + std::array tmp = rgb(*cam->get_pixel(x, y)); + (*pPtr).red = tmp[0]; + (*pPtr).green = tmp[1]; + (*pPtr).blue = tmp[2]; pPtr++; - rIt++; } } img.write("test.png");