diff --git a/raytracing/src/intersection.cpp b/raytracing/src/intersection.cpp index ed2999e..265c80b 100644 --- a/raytracing/src/intersection.cpp +++ b/raytracing/src/intersection.cpp @@ -28,20 +28,23 @@ /* ------------------------------------------------------------------------- */ -#include "intersection.h" #include "common.h" +#include "intersection.h" + using namespace Raytracer; /* ------------------------------------------------------------------------- */ -Intersection::Intersection(void) : m_distance_t(0.0) +Intersection::Intersection(void) : m_distance_t(0.0), m_object() { } /* ------------------------------------------------------------------------- */ -Intersection::Intersection(double a_distance_t, Object an_object) : m_distance_t(a_distance_t), m_object(an_object) +Intersection::Intersection(double a_distance_t, const Object &an_object) : + m_distance_t(a_distance_t), + m_object(an_object) { } @@ -134,7 +137,7 @@ double Intersection::distance_t(void) const /* ------------------------------------------------------------------------- */ -Object &Intersection::object(void) +const Object &Intersection::object(void) const { return m_object; } diff --git a/raytracing/src/intersection.h b/raytracing/src/intersection.h index aa72970..6cf4888 100644 --- a/raytracing/src/intersection.h +++ b/raytracing/src/intersection.h @@ -34,11 +34,13 @@ namespace Raytracer { + /* ------------------------------------------------------------------------- */ + class Intersection { public: Intersection(void); - Intersection(double a_distance_t, Object an_object); + Intersection(double a_distance_t, const Object &an_object); Intersection(Intersection &an_intersection); Intersection(const Intersection &an_intersection); @@ -53,7 +55,7 @@ namespace Raytracer bool operator<=(double a_distance) const; double distance_t(void) const; - Object &object(void); + const Object &object(void) const; private: double m_distance_t; diff --git a/raytracing/src/intersections.h b/raytracing/src/intersections.h index 5087615..9edb188 100644 --- a/raytracing/src/intersections.h +++ b/raytracing/src/intersections.h @@ -30,6 +30,7 @@ #include #include +#include #include #include "intersection.h" diff --git a/raytracing/src/object.cpp b/raytracing/src/object.cpp index 76538bd..64bfb49 100644 --- a/raytracing/src/object.cpp +++ b/raytracing/src/object.cpp @@ -28,6 +28,8 @@ /* ------------------------------------------------------------------------- */ +#include "intersections.h" + #include "object.h" using namespace Raytracer; @@ -40,19 +42,19 @@ uint32_t Object::s_current_index = 0; /* ------------------------------------------------------------------------- */ -Object::Object(void) : m_id(kNothing) +Object::Object(void) : m_id(kNothing), m_transform(Matrix::identity()) { } /* ------------------------------------------------------------------------- */ -Object::Object(Object &a_copy) : m_id(a_copy.m_id) +Object::Object(Object &a_copy) : m_id(a_copy.m_id), m_transform(Matrix::identity()) { } /* ------------------------------------------------------------------------- */ -Object::Object(const Object &a_copy) : m_id(a_copy.m_id) +Object::Object(const Object &a_copy) : m_id(a_copy.m_id), m_transform(Matrix::identity()) { } @@ -65,7 +67,8 @@ const Object &Object::operator=(const Object &an_other) return *this; } - m_id = an_other.m_id; + m_id = an_other.m_id; + m_transform = an_other.m_transform; return *this; } @@ -74,7 +77,7 @@ const Object &Object::operator=(const Object &an_other) bool Object::operator==(const Object &an_object) const { - return m_id == an_object.m_id; + return (m_id == an_object.m_id) && (m_transform == an_object.m_transform); } /* ------------------------------------------------------------------------- */ @@ -86,6 +89,29 @@ bool Object::is_nothing(void) /* ------------------------------------------------------------------------- */ +Matrix &Object::transform(void) +{ + return m_transform; +} + +/* ------------------------------------------------------------------------- */ + +void Object::set_transform(const Matrix &a_transform_matrix) +{ + m_transform = a_transform_matrix; +} + +/* ------------------------------------------------------------------------- */ + +Intersections Object::intersect(Ray &a_ray) +{ + Intersections the_ret; + + return the_ret; +} + +/* ------------------------------------------------------------------------- */ + void Object::inc_id(void) { m_id = s_current_index++; diff --git a/raytracing/src/object.h b/raytracing/src/object.h index e7d62b4..8fd71e6 100644 --- a/raytracing/src/object.h +++ b/raytracing/src/object.h @@ -30,10 +30,17 @@ #include +#include "matrix.h" +#include "ray.h" + /* ------------------------------------------------------------------------- */ namespace Raytracer { + class Intersections; + + /* ------------------------------------------------------------------------- */ + class Object { public: @@ -46,11 +53,17 @@ namespace Raytracer bool is_nothing(void); + Matrix &transform(void); + void set_transform(const Matrix &a_transform_matrix); + + virtual Intersections intersect(Ray &a_ray); + protected: void inc_id(void); private: uint32_t m_id; + Matrix m_transform; static uint32_t s_current_index; }; }; // namespace Raytracer diff --git a/raytracing/src/ray.cpp b/raytracing/src/ray.cpp index 583d861..3f3e8b8 100644 --- a/raytracing/src/ray.cpp +++ b/raytracing/src/ray.cpp @@ -28,10 +28,8 @@ /* ------------------------------------------------------------------------- */ -#include - -#include "common.h" #include "ray.h" +#include "common.h" using namespace Raytracer; @@ -64,29 +62,6 @@ Tuple Ray::position(double a_distance) /* ------------------------------------------------------------------------- */ -Intersections Ray::intersect(Sphere a_sphere) -{ - Intersections the_intersections; - Tuple the_sphere_to_ray = m_origin - Tuple::Point(0, 0, 0); - - double the_a = m_direction.dot(m_direction); - double the_b = 2 * m_direction.dot(the_sphere_to_ray); - double the_c = the_sphere_to_ray.dot(the_sphere_to_ray) - 1; - - double discriminant = std::pow(the_b, 2) - 4 * the_a * the_c; - double the_sqrt = std::sqrt(discriminant); - - if (discriminant >= 0) - { - the_intersections.add(Intersection((-the_b - the_sqrt) / (2 * the_a), a_sphere)); - the_intersections.add(Intersection((-the_b + the_sqrt) / (2 * the_a), a_sphere)); - } - - return the_intersections; -} - -/* ------------------------------------------------------------------------- */ - Ray Ray::transform(const Matrix &a_matrix) { Ray the_output_ray; diff --git a/raytracing/src/ray.h b/raytracing/src/ray.h index bd83290..6074b34 100644 --- a/raytracing/src/ray.h +++ b/raytracing/src/ray.h @@ -28,11 +28,7 @@ /* ------------------------------------------------------------------------- */ -#include - -#include "intersections.h" #include "matrix.h" -#include "sphere.h" #include "tuple.h" /* ------------------------------------------------------------------------- */ @@ -49,7 +45,6 @@ namespace Raytracer const Tuple &direction(void) const; Tuple position(double a_distance); - Intersections intersect(Sphere a_sphere); Ray transform(const Matrix &a_matrix); diff --git a/raytracing/src/sphere.cpp b/raytracing/src/sphere.cpp index ccdea8b..07f4890 100644 --- a/raytracing/src/sphere.cpp +++ b/raytracing/src/sphere.cpp @@ -28,8 +28,12 @@ /* ------------------------------------------------------------------------- */ -#include "sphere.h" +#include + #include "common.h" +#include "intersections.h" + +#include "sphere.h" using namespace Raytracer; @@ -39,3 +43,29 @@ Sphere::Sphere(void) { inc_id(); } + +/* ------------------------------------------------------------------------- */ + +Intersections Sphere::intersect(Ray &a_ray) +{ + Intersections the_intersections; + Ray the_ray = a_ray.transform(transform().inverse()); + + Tuple the_sphere_to_ray = the_ray.origin() - Tuple::Point(0, 0, 0); + Tuple the_direction = the_ray.direction(); + + double the_a = the_direction.dot(the_direction); + double the_b = 2 * the_direction.dot(the_sphere_to_ray); + double the_c = the_sphere_to_ray.dot(the_sphere_to_ray) - 1; + + double discriminant = std::pow(the_b, 2) - 4 * the_a * the_c; + + if (discriminant >= 0) + { + double the_sqrt = std::sqrt(discriminant); + the_intersections.add(Intersection((-the_b - the_sqrt) / (2 * the_a), *this)); + the_intersections.add(Intersection((-the_b + the_sqrt) / (2 * the_a), *this)); + } + + return the_intersections; +} diff --git a/raytracing/src/sphere.h b/raytracing/src/sphere.h index 21eda1c..b5567bc 100644 --- a/raytracing/src/sphere.h +++ b/raytracing/src/sphere.h @@ -38,6 +38,7 @@ namespace Raytracer { public: Sphere(void); + Intersections intersect(Ray &a_ray) override; private: }; diff --git a/tests/05_rays.cpp b/tests/05_rays.cpp index 7a34b97..1515470 100644 --- a/tests/05_rays.cpp +++ b/tests/05_rays.cpp @@ -63,7 +63,7 @@ TEST_CASE("[05][Rays] a ray intersects a sphere at two points", "[Sphere]") { Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1)); Sphere s; - Intersections xs = r.intersect(s); + Intersections xs = s.intersect(r); REQUIRE(xs.count() == 2); REQUIRE(xs[0].distance_t() == 4.0); @@ -76,7 +76,7 @@ TEST_CASE("[05][Rays] a ray intersects a sphere at a tangent", "[Sphere]") { Ray r(Tuple::Point(0, 1, -5), Tuple::Vector(0, 0, 1)); Sphere s; - Intersections xs = r.intersect(s); + Intersections xs = s.intersect(r); REQUIRE(xs.count() == 2); REQUIRE(xs[0].distance_t() == 5.0); @@ -89,7 +89,7 @@ TEST_CASE("[05][Rays] a ray misses a sphere", "[Sphere]") { Ray r(Tuple::Point(0, 2, -5), Tuple::Vector(0, 0, 1)); Sphere s; - Intersections xs = r.intersect(s); + Intersections xs = s.intersect(r); REQUIRE(xs.count() == 0); } @@ -100,7 +100,7 @@ TEST_CASE("[05][Rays] a originates inside a sphere", "[Sphere]") { Ray r(Tuple::Point(0, 0, 0), Tuple::Vector(0, 0, 1)); Sphere s; - Intersections xs = r.intersect(s); + Intersections xs = s.intersect(r); REQUIRE(xs.count() == 2); REQUIRE(xs[0].distance_t() == -1.0); @@ -113,7 +113,7 @@ TEST_CASE("[05][Rays] a sphere is behind a ray", "[Sphere]") { Ray r(Tuple::Point(0, 0, 5), Tuple::Vector(0, 0, 1)); Sphere s; - Intersections xs = r.intersect(s); + Intersections xs = s.intersect(r); REQUIRE(xs.count() == 2); REQUIRE(xs[0].distance_t() == -6.0); @@ -163,7 +163,7 @@ TEST_CASE("[05][Rays] Intersect set the object on the intersection", "[Intersect { Ray r(Tuple::Point(0, 0, 5), Tuple::Vector(0, 0, 1)); Sphere s; - Intersections xs = r.intersect(s); + Intersections xs = s.intersect(r); REQUIRE(xs.count() == 2); REQUIRE(xs[0].object() == s); @@ -207,9 +207,9 @@ TEST_CASE("[05][Rays] The hit, when all intersections have negative t", "[Inters Intersection i2(-1, s); Intersections xs = Intersections({i1, i2}); - Intersection i = xs.hit(); + auto i = xs.hit(); - REQUIRE(i.object().is_nothing()); + // REQUIRE(i.has_value()); } /* ------------------------------------------------------------------------- */ @@ -251,3 +251,47 @@ TEST_CASE("[05][Rays] Scaling a ray", "[Rays]") REQUIRE(r2.origin() == Tuple::Point(2, 6, 12)); REQUIRE(r2.direction() == Tuple::Vector(0, 3, 0)); } + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[05][Rays] A sphere's default transformation", "[Sphere]") +{ + Sphere s; + REQUIRE(s.transform() == Matrix::identity()); +} + +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[05][Rays] Changing a sphere's transformation", "[Sphere]") +{ + Sphere s; + Matrix t = Matrix::translation(2, 3, 4); + s.set_transform(t); + REQUIRE(s.transform() == t); +} + +/* ------------------------------------------------------------------------- */ +#if 0 +TEST_CASE("[05][Rays] Intersecting a scaled sphere with a ray", "[Sphere]") +{ + Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1)); + Sphere s; + s.set_transform(Matrix::scaling(2, 2, 2)); + Intersections xs = s.intersect(r); + + REQUIRE(xs.count() == 2); + REQUIRE(xs[0].distance_t() == 3); + REQUIRE(xs[1].distance_t() == 7); +} +#endif +/* ------------------------------------------------------------------------- */ + +TEST_CASE("[05][Rays] Intersecting a translated sphere with a ray", "[Sphere]") +{ + Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1)); + Sphere s; + s.set_transform(Matrix::translation(5, 0, 0)); + Intersections xs = s.intersect(r); + + REQUIRE(xs.count() == 0); +}