[FEAT] add world.color_at

This commit is contained in:
2024-02-22 23:00:54 +01:00
parent 6acf43540f
commit ea33f1b985
4 changed files with 120 additions and 8 deletions

View File

@@ -112,21 +112,25 @@ uint8_t Intersections::count(void) const
Intersection Intersections::hit(void)
{
Intersection the_current_int;
if (m_data.size() == 0)
{
return {};
}
auto the_it = std::min_element(m_data.begin(), m_data.end(),
[](const Intersection &a, const Intersection &b)
{
// Use < comparison for strict positivity check
return a.distance_t() < b.distance_t() && a.distance_t() > 0;
});
if (the_it == m_data.end() || the_it->distance_t() <= 0)
for (const Intersection &the_it : m_data)
{
if (the_it.distance_t() > 0 &&
(the_current_int.is_nothing() || the_it.distance_t() < the_current_int.distance_t()))
{
the_current_int = the_it;
}
}
if (the_current_int.is_nothing())
{
return {};
}
return *the_it;
return the_current_int;
}

View File

@@ -163,6 +163,31 @@ Color World::shade_hit(const IntersectionData &an_intersection_data)
/* ------------------------------------------------------------------------- */
Color World::color_at(const Ray &a_ray)
{
Color the_color = Color::Black();
Intersections the_intersections = intersect_world(a_ray);
if (the_intersections.count() == 0)
{
return the_color;
}
Intersection the_intersec = the_intersections.hit();
if (the_intersec.is_nothing())
{
return the_color;
}
IntersectionData the_comps = the_intersec.prepare_computations(a_ray);
the_color = shade_hit(the_comps);
return the_color;
}
/* ------------------------------------------------------------------------- */
World World::default_world(void)
{
World the_world;

View File

@@ -62,6 +62,7 @@ namespace Raytracer
Intersections intersect_world(const Ray &a_ray);
Color shade_hit(const IntersectionData &an_intersection_data);
Color color_at(const Ray &a_ray);
static World default_world(void);

View File

@@ -308,3 +308,85 @@ SCENARIO("Shading an intersection from the inside", "[features/world.feature]")
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The color when a ray misses", "[features/world.feature]")
{
GIVEN("w <- default_world()")
{
World w = World::default_world();
AND_GIVEN("r <- ray(point(0, 0, -5), vector(0, 1, 0))")
{
Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 1, 0));
WHEN("c <- color_at(w, r)")
{
Color c = w.color_at(r);
THEN("c = color(0, 0, 0)")
{
REQUIRE(c == Color(0, 0, 0));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The color when a ray hits", "[features/world.feature]")
{
GIVEN("w <- default_world()")
{
World w = World::default_world();
AND_GIVEN("r <- ray(point(0, 0, -5), vector(0, 0, 1))")
{
Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1));
WHEN("c <- color_at(w, r)")
{
Color c = w.color_at(r);
THEN("c = color(0.38066, 0.47583, 0.2855)")
{
REQUIRE(c == Color(0.38066, 0.47583, 0.2855));
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The color with an intersection behind the ray", "[features/world.feature]")
{
GIVEN("w <- default_world()")
{
World w = World::default_world();
AND_GIVEN("outer <- the first object in w")
{
Shape *outer = w.objects(0);
AND_GIVEN("outer.material.ambient <- 1")
{
outer->material().set_ambient(1);
AND_GIVEN("inner <- the second object in w")
{
Shape *inner = w.objects(1);
AND_GIVEN("inner.material.ambient <- 1")
{
inner->material().set_ambient(1);
AND_GIVEN("r <- ray(point(0, 0, 0.75), vector(0, 0, -1))")
{
Ray r(Tuple::Point(0, 0, 0.75), Tuple::Vector(0, 0, -1));
WHEN("c <- color_at(w, r)")
{
Color c = w.color_at(r);
THEN("c = inner.material.color")
{
REQUIRE(c == inner->material().color());
}
}
}
}
}
}
}
}
}