[FEAT] add world.color_at
This commit is contained in:
@@ -112,21 +112,25 @@ uint8_t Intersections::count(void) const
|
|||||||
|
|
||||||
Intersection Intersections::hit(void)
|
Intersection Intersections::hit(void)
|
||||||
{
|
{
|
||||||
|
Intersection the_current_int;
|
||||||
if (m_data.size() == 0)
|
if (m_data.size() == 0)
|
||||||
{
|
{
|
||||||
return {};
|
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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return *the_it;
|
return the_current_int;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 World::default_world(void)
|
||||||
{
|
{
|
||||||
World the_world;
|
World the_world;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ namespace Raytracer
|
|||||||
|
|
||||||
Intersections intersect_world(const Ray &a_ray);
|
Intersections intersect_world(const Ray &a_ray);
|
||||||
Color shade_hit(const IntersectionData &an_intersection_data);
|
Color shade_hit(const IntersectionData &an_intersection_data);
|
||||||
|
Color color_at(const Ray &a_ray);
|
||||||
|
|
||||||
static World default_world(void);
|
static World default_world(void);
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user