From d519399c6195abd26f8cce2133d067f726dd0d4f Mon Sep 17 00:00:00 2001 From: NADAL Jean-Baptiste Date: Fri, 8 Mar 2024 17:35:10 +0100 Subject: [PATCH] [WIP] Refraction Wip --- raytracing/src/core/intersection-data.cpp | 32 +++++++- raytracing/src/core/intersection-data.h | 8 ++ raytracing/src/core/intersection.cpp | 26 ++++++- raytracing/src/core/intersection.h | 4 +- raytracing/src/core/intersections.cpp | 7 ++ raytracing/src/core/intersections.h | 2 + raytracing/src/renderer/world.cpp | 3 +- tests/11_reflection_refraction.cpp | 92 ++++++++++++++++++++++- 8 files changed, 169 insertions(+), 5 deletions(-) diff --git a/raytracing/src/core/intersection-data.cpp b/raytracing/src/core/intersection-data.cpp index dcc4be3..000ff7e 100644 --- a/raytracing/src/core/intersection-data.cpp +++ b/raytracing/src/core/intersection-data.cpp @@ -37,7 +37,9 @@ using namespace Raytracer; IntersectionData::IntersectionData(void) : m_is_inside(false), m_distance(0), - m_shape(nullptr) + m_shape(nullptr), + m_n1(0), + m_n2(0) { } @@ -160,3 +162,31 @@ void IntersectionData::set_inside(void) m_is_inside = false; } } + +/* ------------------------------------------------------------------------- */ + +void IntersectionData::set_n1(double an_n1) +{ + m_n1 = an_n1; +} + +/* ------------------------------------------------------------------------- */ + +const double IntersectionData::n1(void) const +{ + return m_n1; +} + +/* ------------------------------------------------------------------------- */ + +void IntersectionData::set_n2(double an_n2) +{ + m_n2 = an_n2; +} + +/* ------------------------------------------------------------------------- */ + +const double IntersectionData::n2(void) const +{ + return m_n2; +} diff --git a/raytracing/src/core/intersection-data.h b/raytracing/src/core/intersection-data.h index 4e62eb8..e702da7 100644 --- a/raytracing/src/core/intersection-data.h +++ b/raytracing/src/core/intersection-data.h @@ -65,6 +65,12 @@ namespace Raytracer const bool is_inside(void) const; void set_inside(void); + void set_n1(double an_n1); + const double n1(void) const; + + void set_n2(double an_n2); + const double n2(void) const; + private: bool m_is_inside; double m_distance; @@ -74,6 +80,8 @@ namespace Raytracer Tuple m_eyev; Tuple m_normalv; Tuple m_reflectv; + double m_n1; + double m_n2; }; }; // namespace Raytracer diff --git a/raytracing/src/core/intersection.cpp b/raytracing/src/core/intersection.cpp index 11ce348..1f3abcc 100644 --- a/raytracing/src/core/intersection.cpp +++ b/raytracing/src/core/intersection.cpp @@ -32,6 +32,8 @@ #include "intersection.h" +#include "intersections.h" + using namespace Raytracer; /* ------------------------------------------------------------------------- */ @@ -165,9 +167,10 @@ bool Intersection::is_defined(void) /* ------------------------------------------------------------------------- */ -IntersectionData Intersection::prepare_computations(const Ray &a_ray) const +IntersectionData Intersection::prepare_computations(const Ray &a_ray, Intersections *a_collection) const { IntersectionData the_data; + std::vector the_container; // Copy intersections properties for convenance the_data.set_distance_t(m_distance_t); @@ -181,5 +184,26 @@ IntersectionData Intersection::prepare_computations(const Ray &a_ray) const the_data.set_inside(); the_data.set_reflectv(a_ray.direction().reflect(the_data.normalv())); + if (a_collection == nullptr) + { + return the_data; + } + + // Manage the container + for (const Intersection &the_it : a_collection->data()) + { + if (the_it == a_collection->hit()) + { + if (the_container.empty()) + { + the_data.set_n1(1.0); + } + else + { + // TODO + } + } + } + return the_data; } diff --git a/raytracing/src/core/intersection.h b/raytracing/src/core/intersection.h index 986c52a..ca99dd3 100644 --- a/raytracing/src/core/intersection.h +++ b/raytracing/src/core/intersection.h @@ -35,6 +35,8 @@ namespace Raytracer { + class Intersections; + /* ------------------------------------------------------------------------- */ class Intersection @@ -60,7 +62,7 @@ namespace Raytracer bool is_nothing(void); bool is_defined(void); - IntersectionData prepare_computations(const Ray &a_ray) const; + IntersectionData prepare_computations(const Ray &a_ray, Intersections *a_collection = nullptr) const; private: bool m_is_nothing; diff --git a/raytracing/src/core/intersections.cpp b/raytracing/src/core/intersections.cpp index f02e423..28efd33 100644 --- a/raytracing/src/core/intersections.cpp +++ b/raytracing/src/core/intersections.cpp @@ -95,6 +95,13 @@ const Intersections &Intersections::operator+=(const Intersections &an_other) /* ------------------------------------------------------------------------- */ +const std::vector &Intersections::data(void) const +{ + return m_data; +} + +/* ------------------------------------------------------------------------- */ + bool Intersections::add(const Intersection &an_intersection) { m_data.push_back(an_intersection); diff --git a/raytracing/src/core/intersections.h b/raytracing/src/core/intersections.h index d281189..a9cd9f4 100644 --- a/raytracing/src/core/intersections.h +++ b/raytracing/src/core/intersections.h @@ -50,6 +50,8 @@ namespace Raytracer const Intersections &operator=(const Intersections &an_other); const Intersections &operator+=(const Intersections &an_other); + const std::vector &data(void) const; + bool add(const Intersection &an_intersection); uint8_t count(void) const; diff --git a/raytracing/src/renderer/world.cpp b/raytracing/src/renderer/world.cpp index 5f85198..7735cd3 100644 --- a/raytracing/src/renderer/world.cpp +++ b/raytracing/src/renderer/world.cpp @@ -28,6 +28,7 @@ /* ------------------------------------------------------------------------- */ +#include "core/common.h" #include "core/matrix.h" #include "shapes/shape.h" @@ -177,7 +178,7 @@ Color World::reflected_color(const IntersectionData &a_data, uint32_t a_remaingi return Color(0, 0, 0); } - if (a_data.object()->material().reflective() == 0.0) + if (double_equal(a_data.object()->material().reflective(), 0.0)) { return Color(0, 0, 0); } diff --git a/tests/11_reflection_refraction.cpp b/tests/11_reflection_refraction.cpp index 1c5062e..0079a40 100644 --- a/tests/11_reflection_refraction.cpp +++ b/tests/11_reflection_refraction.cpp @@ -256,7 +256,7 @@ SCENARIO("The reflected color at the maximum recursive depth", "[features/world. AND_GIVEN("shape is added to w") { w.add_object(&shape); - AND_GIVEN("ray(point(0, 0, -3), vector(0, -sqrt(2) / 2, sqrt(2) / 2)") + AND_GIVEN("r <- ray(point(0, 0, -3), vector(0, -sqrt(2) / 2, sqrt(2) / 2)") { Ray r(Tuple::Point(0, 0, -3), Tuple::Vector(0, -sqrt(2) / 2, sqrt(2) / 2)); AND_GIVEN("i <- intersection(sqrt(2), shape)") @@ -320,3 +320,93 @@ SCENARIO("A helper for producing a sphere with a glassy material", "[features/sp } } } + +/* ------------------------------------------------------------------------- */ + +struct TestData +{ + Intersection i; + double n1; + double n2; +}; + +void fill_test_various(TestData *a_test, const Intersection &an_in, double a_n1, double a_n2) +{ + a_test->i = an_in; + a_test->n1 = a_n1; + a_test->n2 = a_n2; +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Finding n1 and n2 at various intersections", "[features/intersections.feature]") +{ + + TestData the_tests[6]; + + GIVEN("A <- glass_sphere() with:") + // | transform | scaling(2, 2, 2) | + // | material.refractive_index | 1.5 | + { + Sphere A = Sphere::Glass(); + A.set_transform(Matrix::scaling(2, 2, 2)); + A.material().set_refractive_index(1.5); + GIVEN("B <- glass_sphere() with:") + // | transform | translation(0, 0, -0.25) | + // | material.refractive_index | 2.0 | + { + Sphere B = Sphere::Glass(); + B.set_transform(Matrix::translation(0, 0, -0.25)); + B.material().set_refractive_index(2.0); + GIVEN("C <- glass_sphere() with:") + // | transform | translation(0, 0, 0.25) | + // | material.refractive_index | 2.5 | + { + Sphere C = Sphere::Glass(); + C.set_transform(Matrix::translation(0, 0, 0.25)); + C.material().set_refractive_index(2.5); + AND_GIVEN("r <- ray(point(0, 0, -4), vector(0, 0, 1)") + { + Ray r(Tuple::Point(0, 0, -4), Tuple::Vector(0, 0, 1)); + + AND_GIVEN("xs <- intersections(2:A, 2.75:B, 3.25:C, 4.75:B, 5.25:C, 6:A)") + { + // Examples: + // | index | n1 | n2 | + // | 0 |1.0 |1.5 | + // | 1 |1.5 |2.0 | + // | 2 |2.0 |2.5 | + // | 3 |2.5 |2.5 | + // | 4 |2.5 |1.5 | + // | 5 |1.5 |1.0 | + fill_test_various(&the_tests[0], Intersection(2.0, &A), 1.0, 1.5); + fill_test_various(&the_tests[1], Intersection(2.75, &B), 1.5, 2.0); + fill_test_various(&the_tests[2], Intersection(3.25, &C), 2.0, 2.5); + fill_test_various(&the_tests[3], Intersection(4.75, &B), 2.5, 2.5); + fill_test_various(&the_tests[4], Intersection(5.25, &C), 2.5, 1.5); + fill_test_various(&the_tests[5], Intersection(6.0, &A), 1.5, 1.0); + + Intersections xs = Intersections({the_tests[0].i, the_tests[1].i, the_tests[2].i, the_tests[3].i, + the_tests[4].i, the_tests[5].i}); + + for (int i = 0; i < 6; i++) + { + WHEN("comps <- prepare_computations(xs[index], r, xs)") + { + IntersectionData comps = the_tests[i].i.prepare_computations(r, &xs); + THEN("comps.n1 = ") + { + REQUIRE(comps.n1() == the_tests[i].n1); + } + AND_THEN("comps.n2 = ") + { + REQUIRE(comps.n2() == the_tests[i].n2); + } + } + } + } + } + } + } + } +}