[WIP] stripe-pattern is now ok.

This commit is contained in:
NADAL Jean-Baptiste
2024-02-29 18:39:45 +01:00
parent 5e540a995b
commit 0576ccaccb
19 changed files with 192 additions and 56 deletions

View File

@@ -77,10 +77,10 @@ int shadow_sphere(uint8_t a_canvas_pixels, double a_wall_size, uint8_t a_wall_z)
if (the_intersec.is_defined()) if (the_intersec.is_defined())
{ {
Tuple the_point = the_ray.position(the_intersec.distance_t()); Tuple the_point = the_ray.position(the_intersec.distance_t());
Tuple the_normal = the_intersec.object().normal_at(the_point); Tuple the_normal = the_intersec.object()->normal_at(the_point);
Tuple the_eye = -the_ray.direction(); Tuple the_eye = -the_ray.direction();
Color the_color = Color the_color = the_intersec.object()->material().lighting(nullptr, the_light, the_point, the_eye,
the_intersec.object().material().lighting(the_light, the_point, the_eye, the_normal, false); the_normal, false);
the_canvas.write_pixel(x, y, the_color); the_canvas.write_pixel(x, y, the_color);
} }
} }

View File

@@ -54,7 +54,7 @@ int main(void)
Material &the_floor_material = the_floor->material(); Material &the_floor_material = the_floor->material();
the_floor_material.set_color(Color(1, 0.9, 0.9)); the_floor_material.set_color(Color(1, 0.9, 0.9));
the_floor_material.set_specular(0); the_floor_material.set_specular(0);
the_floor_material.set_pattern(new StripePattern(Color(1, 1, 1), Color(0, 0, 0))); the_floor_material.set_pattern(new StripePattern(Color(1, 1, 1), Color(1, 0.9, 0.9)));
the_world.add_object(the_floor); the_world.add_object(the_floor);
// The large sphere in the middle is a unit sphere, translated upward slightly and colored green. // The large sphere in the middle is a unit sphere, translated upward slightly and colored green.
@@ -62,6 +62,7 @@ int main(void)
the_middle->set_transform(Matrix::translation(-0.5, 1, 0.5)); the_middle->set_transform(Matrix::translation(-0.5, 1, 0.5));
Material &the_middle_material = the_middle->material(); Material &the_middle_material = the_middle->material();
the_middle_material.set_color(Color(0.1, 1, 0.5)); the_middle_material.set_color(Color(0.1, 1, 0.5));
the_middle_material.set_pattern(new StripePattern(Color(1, 1, 1), Color(0.1, 1, 0.5)));
the_middle_material.set_diffuse(0.7); the_middle_material.set_diffuse(0.7);
the_middle_material.set_specular(0.3); the_middle_material.set_specular(0.3);
the_world.add_object(the_middle); the_world.add_object(the_middle);

View File

@@ -54,9 +54,9 @@ void IntersectionData::set_distance_t(double a_value)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
const Shape &IntersectionData::object(void) const Shape *IntersectionData::object(void) const
{ {
return *m_shape; return m_shape;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */

View File

@@ -44,7 +44,7 @@ namespace Raytracer
double distance_t(void) const; double distance_t(void) const;
void set_distance_t(double a_value); void set_distance_t(double a_value);
const Shape &object(void) const; Shape *object(void) const;
void set_object(Shape *a_shape); void set_object(Shape *a_shape);
const Tuple &point(void) const; const Tuple &point(void) const;

View File

@@ -141,9 +141,9 @@ double Intersection::distance_t(void) const
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
const Shape &Intersection::object(void) const const Shape *Intersection::object(void) const
{ {
return *m_shape; return m_shape;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */

View File

@@ -56,7 +56,7 @@ namespace Raytracer
bool operator<=(double a_distance) const; bool operator<=(double a_distance) const;
double distance_t(void) const; double distance_t(void) const;
const Shape &object(void) const; const Shape *object(void) const;
bool is_nothing(void); bool is_nothing(void);
bool is_defined(void); bool is_defined(void);

View File

@@ -31,6 +31,9 @@
#include <cmath> #include <cmath>
#include "core/common.h" #include "core/common.h"
#include "shapes/shape.h"
#include "renderer/stripe-pattern.h"
#include "material.h" #include "material.h"
@@ -144,8 +147,8 @@ void Material::set_pattern(StripePattern *a_pattern)
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Color Material::lighting(const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev, const Tuple &a_normalv, Color Material::lighting(Shape *an_object, const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev,
bool is_shadowed) const const Tuple &a_normalv, bool is_shadowed) const
{ {
Color the_effective_color; Color the_effective_color;
Tuple the_light_v, the_reflect_v; Tuple the_light_v, the_reflect_v;
@@ -153,7 +156,7 @@ Color Material::lighting(const PointLight &a_light, const Tuple &a_point, const
if (m_pattern != nullptr) if (m_pattern != nullptr)
{ {
the_color = m_pattern->stripe_at(a_point); the_color = m_pattern->stripe_at_object(an_object, a_point);
} }
else else
{ {

View File

@@ -30,13 +30,16 @@
#include "core/color.h" #include "core/color.h"
#include "core/tuple.h" #include "core/tuple.h"
#include "lights/point-light.h" #include "lights/point-light.h"
#include "stripe-pattern.h"
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
namespace Raytracer namespace Raytracer
{ {
class Shape;
class StripePattern;
class Material class Material
{ {
public: public:
@@ -62,8 +65,8 @@ namespace Raytracer
const StripePattern *pattern(void) const; const StripePattern *pattern(void) const;
void set_pattern(StripePattern *a_pattern); void set_pattern(StripePattern *a_pattern);
Color lighting(const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev, const Tuple &a_normalv, Color lighting(Shape *an_object, const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev,
bool is_shadowed) const; const Tuple &a_normalv, bool is_shadowed) const;
private: private:
Color m_color; Color m_color;

View File

@@ -40,6 +40,7 @@ using namespace Raytracer;
StripePattern::StripePattern(const Color &a_color_a, const Color &a_color_b) : m_a(a_color_a), m_b(a_color_b) StripePattern::StripePattern(const Color &a_color_a, const Color &a_color_b) : m_a(a_color_a), m_b(a_color_b)
{ {
m_transform = Matrix::identity();
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -72,3 +73,20 @@ const Color &StripePattern::stripe_at(const Tuple &a_point) const
return m_b; return m_b;
} }
/* ------------------------------------------------------------------------- */
void StripePattern::set_pattern_transform(const Matrix &a_transform_matrix)
{
m_transform = a_transform_matrix;
}
/* ------------------------------------------------------------------------- */
const Color &StripePattern::stripe_at_object(Shape *an_object, const Tuple &a_world_point) const
{
Tuple the_objet_point = an_object->transform().inverse() * a_world_point;
Tuple the_pattern_point = m_transform.inverse() * the_objet_point;
return stripe_at(the_pattern_point);
}

View File

@@ -29,8 +29,11 @@
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#include "core/color.h" #include "core/color.h"
#include "core/matrix.h"
#include "core/tuple.h" #include "core/tuple.h"
#include "shapes/shape.h"
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
namespace Raytracer namespace Raytracer
@@ -47,7 +50,12 @@ namespace Raytracer
const Color &stripe_at(const Tuple &a_point) const; const Color &stripe_at(const Tuple &a_point) const;
void set_pattern_transform(const Matrix &a_transform_matrix);
const Color &stripe_at_object(Shape *an_object, const Tuple &a_world_point) const;
private: private:
Matrix m_transform;
Color m_a; Color m_a;
Color m_b; Color m_b;
}; };

View File

@@ -29,6 +29,8 @@
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#include "core/matrix.h" #include "core/matrix.h"
#include "shapes/shape.h"
#include "shapes/sphere.h" #include "shapes/sphere.h"
#include "world.h" #include "world.h"
@@ -158,9 +160,9 @@ Intersections World::intersect_world(const Ray &a_ray) const
Color World::shade_hit(const IntersectionData &an_intersection_data) const Color World::shade_hit(const IntersectionData &an_intersection_data) const
{ {
bool the_shadowed = is_shadowed(an_intersection_data.over_point()); bool the_shadowed = is_shadowed(an_intersection_data.over_point());
return an_intersection_data.object().material().lighting(m_light, an_intersection_data.over_point(), Shape *the_object = an_intersection_data.object();
an_intersection_data.eyev(), return the_object->material().lighting(the_object, m_light, an_intersection_data.over_point(),
an_intersection_data.normalv(), the_shadowed); an_intersection_data.eyev(), an_intersection_data.normalv(), the_shadowed);
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */

View File

@@ -41,6 +41,8 @@
namespace Raytracer namespace Raytracer
{ {
class Shape;
class World class World
{ {
public: public:

View File

@@ -80,6 +80,13 @@ bool Shape::operator==(const Shape &a_shape) const
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
bool Shape::operator==(const Shape *a_shape) const
{
return (m_transform == a_shape->m_transform) && (m_material == a_shape->m_material);
}
/* ------------------------------------------------------------------------- */
Matrix &Shape::transform(void) Matrix &Shape::transform(void)
{ {
return m_transform; return m_transform;

View File

@@ -51,6 +51,7 @@ namespace Raytracer
const Shape &operator=(const Shape &a_shape); const Shape &operator=(const Shape &a_shape);
bool operator==(const Shape &a_shape) const; bool operator==(const Shape &a_shape) const;
bool operator==(const Shape *a_shape) const;
Matrix &transform(void); Matrix &transform(void);
const Matrix &transform(void) const; const Matrix &transform(void) const;

View File

@@ -242,7 +242,7 @@ SCENARIO("An intersection encapsulates t and object", "[features/intersections.f
} }
AND_THEN("i.object = s") AND_THEN("i.object = s")
{ {
REQUIRE(i.object() == s); REQUIRE(*i.object() == s);
} }
} }
} }
@@ -270,7 +270,7 @@ SCENARIO("An intersection could be affected", "[features/intersections.feature]"
} }
AND_THEN("i2.object = s") AND_THEN("i2.object = s")
{ {
REQUIRE(i2.object() == s); REQUIRE(*i2.object() == s);
} }
} }
} }
@@ -403,11 +403,11 @@ SCENARIO("Intersect sets the object on the intersection", "[features/spheres.fea
} }
AND_THEN("xs[0].object = s") AND_THEN("xs[0].object = s")
{ {
REQUIRE(xs[0].object() == s); REQUIRE(*xs[0].object() == s);
} }
AND_THEN("xs[1].object = s") AND_THEN("xs[1].object = s")
{ {
REQUIRE(xs[1].object() == s); REQUIRE(*xs[1].object() == s);
} }
} }
} }

View File

@@ -331,7 +331,7 @@ SCENARIO("Lighting with the eye between the light and the surface", "[features/m
PointLight light = PointLight(Tuple::Point(0, 0, -10), Color(1, 1, 1)); PointLight light = PointLight(Tuple::Point(0, 0, -10), Color(1, 1, 1));
WHEN("result <- lighting(m, light, position, eyev, normalv)") WHEN("result <- lighting(m, light, position, eyev, normalv)")
{ {
Color result = m.lighting(light, position, eyev, normalv, false); Color result = m.lighting(nullptr, light, position, eyev, normalv, false);
THEN("result = color(1.9, 1.9, 1.9)") THEN("result = color(1.9, 1.9, 1.9)")
{ {
REQUIRE(result == Color(1.9, 1.9, 1.9)); REQUIRE(result == Color(1.9, 1.9, 1.9));
@@ -360,7 +360,7 @@ SCENARIO("Lighting with eye between the light & surface, eye offset 45°", "[fea
PointLight light = PointLight(Tuple::Point(0, 0, -10), Color(1, 1, 1)); PointLight light = PointLight(Tuple::Point(0, 0, -10), Color(1, 1, 1));
WHEN("result <- lighting(m, light, position, eyev, normalv)") WHEN("result <- lighting(m, light, position, eyev, normalv)")
{ {
Color result = m.lighting(light, position, eyev, normalv, false); Color result = m.lighting(nullptr, light, position, eyev, normalv, false);
THEN("result = color(1.0, 1.0, 1.0)") THEN("result = color(1.0, 1.0, 1.0)")
{ {
REQUIRE(result == Color(1.0, 1.0, 1.0)); REQUIRE(result == Color(1.0, 1.0, 1.0));
@@ -389,7 +389,7 @@ SCENARIO("Lighting with the eye opposite surface, light offset 45°", "[features
PointLight light = PointLight(Tuple::Point(0, 10, -10), Color(1, 1, 1)); PointLight light = PointLight(Tuple::Point(0, 10, -10), Color(1, 1, 1));
WHEN("result <- lighting(m, light, position, eyev, normalv)") WHEN("result <- lighting(m, light, position, eyev, normalv)")
{ {
Color result = m.lighting(light, position, eyev, normalv, false); Color result = m.lighting(nullptr, light, position, eyev, normalv, false);
THEN("result = color(0.7364, 0.7364, 0.7364)") THEN("result = color(0.7364, 0.7364, 0.7364)")
{ {
REQUIRE(result == Color(0.7364, 0.7364, 0.7364)); REQUIRE(result == Color(0.7364, 0.7364, 0.7364));
@@ -418,7 +418,7 @@ SCENARIO("Lighting with the eye in the path of the reflection vector", "[feature
PointLight light = PointLight(Tuple::Point(0, 10, -10), Color(1, 1, 1)); PointLight light = PointLight(Tuple::Point(0, 10, -10), Color(1, 1, 1));
WHEN("result <- lighting(m, light, position, eyev, normalv)") WHEN("result <- lighting(m, light, position, eyev, normalv)")
{ {
Color result = m.lighting(light, position, eyev, normalv, false); Color result = m.lighting(nullptr, light, position, eyev, normalv, false);
THEN("result = color(1.6364, 1.6364, 1.6364)") THEN("result = color(1.6364, 1.6364, 1.6364)")
{ {
REQUIRE(result == Color(1.6364, 1.6364, 1.6364)); REQUIRE(result == Color(1.6364, 1.6364, 1.6364));
@@ -447,7 +447,7 @@ SCENARIO("Lighting with the light behind the surface", "[features/materials.feat
PointLight light = PointLight(Tuple::Point(0, 0, 10), Color(1, 1, 1)); PointLight light = PointLight(Tuple::Point(0, 0, 10), Color(1, 1, 1));
WHEN("result <- lighting(m, light, position, eyev, normalv)") WHEN("result <- lighting(m, light, position, eyev, normalv)")
{ {
Color result = m.lighting(light, position, eyev, normalv, false); Color result = m.lighting(nullptr, light, position, eyev, normalv, false);
THEN("result = color(0.1, 0.1, 0.1)") THEN("result = color(0.1, 0.1, 0.1)")
{ {
REQUIRE(result == Color(0.1, 0.1, 0.1)); REQUIRE(result == Color(0.1, 0.1, 0.1));

View File

@@ -52,7 +52,7 @@ SCENARIO("Lightning with the surface in shadow", "[features/materials.feature]")
bool in_shadow = true; bool in_shadow = true;
WHEN("result <- lighting(m, light, position, eyev, normalv, in_shadow)") WHEN("result <- lighting(m, light, position, eyev, normalv, in_shadow)")
{ {
Color result = m.lighting(light, position, eyev, normalv, in_shadow); Color result = m.lighting(nullptr, light, position, eyev, normalv, in_shadow);
THEN("result = color(0.1, 0.1, 0.1)") THEN("result = color(0.1, 0.1, 0.1)")
{ {
REQUIRE(result == Color(0.1, 0.1, 0.1)); REQUIRE(result == Color(0.1, 0.1, 0.1));

View File

@@ -347,7 +347,7 @@ SCENARIO("A ray Intersecting a plane from above", "[features/planes.feature]")
} }
AND_THEN("xs[0].object = p") AND_THEN("xs[0].object = p")
{ {
REQUIRE(xs[0].object() == p); REQUIRE(*xs[0].object() == p);
} }
} }
} }

View File

@@ -58,12 +58,15 @@ SCENARIO("A stripe pattern is constant in y", "[features/patterns.feature]")
StripePattern pattern(Color::White(), Color::Black()); StripePattern pattern(Color::White(), Color::Black());
THEN("stripe_at(pattern, point(0, 0, 0) = white") THEN("stripe_at(pattern, point(0, 0, 0) = white")
{ {
REQUIRE(pattern.stripe_at(Tuple::Point(0, 0, 0)) == Color::White());
} }
AND_THEN("stripe_at(pattern, point(0, 1, 0) = white") AND_THEN("stripe_at(pattern, point(0, 1, 0) = white")
{ {
REQUIRE(pattern.stripe_at(Tuple::Point(0, 1, 0)) == Color::White());
} }
AND_THEN("stripe_at(pattern, point(0, 2, 0) = white") AND_THEN("stripe_at(pattern, point(0, 2, 0) = white")
{ {
REQUIRE(pattern.stripe_at(Tuple::Point(0, 2, 0)) == Color::White());
} }
} }
} }
@@ -128,6 +131,9 @@ SCENARIO("A stripe pattern alternates in x", "[features/patterns.feature]")
SCENARIO("Lightning with a pattern applied", "[features/materials.feature]") SCENARIO("Lightning with a pattern applied", "[features/materials.feature]")
{ {
GIVEN("object <- sphere()")
{
Sphere object;
Material m; Material m;
GIVEN("m.pattern <- strip_pattern(color(1, 1, 1), color(0, 0, 0))") GIVEN("m.pattern <- strip_pattern(color(1, 1, 1), color(0, 0, 0))")
{ {
@@ -153,10 +159,12 @@ SCENARIO("Lightning with a pattern applied", "[features/materials.feature]")
WHEN("c1 <- lighting(m, light, point(0.9, 0, 0), eyev, normalv, false)") WHEN("c1 <- lighting(m, light, point(0.9, 0, 0), eyev, normalv, false)")
{ {
Color c1 = m.lighting(light, Tuple::Point(0.9, 0, 0), eyev, normalv, false); Color c1 =
m.lighting(&object, light, Tuple::Point(0.9, 0, 0), eyev, normalv, false);
AND_WHEN("c2 <- lighting(m, light, point(1.1, 0, 0), eyev, normalv, false)") AND_WHEN("c2 <- lighting(m, light, point(1.1, 0, 0), eyev, normalv, false)")
{ {
Color c2 = m.lighting(light, Tuple::Point(1.1, 0, 0), eyev, normalv, false); Color c2 = m.lighting(&object, light, Tuple::Point(1.1, 0, 0), eyev,
normalv, false);
THEN("c1 = color(1, 1, 1)") THEN("c1 = color(1, 1, 1)")
{ {
REQUIRE(c1 == Color(1, 1, 1)); REQUIRE(c1 == Color(1, 1, 1));
@@ -174,4 +182,87 @@ SCENARIO("Lightning with a pattern applied", "[features/materials.feature]")
} }
} }
} }
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Stripes with an object transformation", "[features/patterns.feature]")
{
GIVEN("object <- sphere()")
{
Sphere object;
AND_GIVEN("set_transform(object, scaling(2, 2, 2))")
{
object.set_transform(Matrix::scaling(2, 2, 2));
AND_GIVEN("pattern <- stripe_pattern(white, black)")
{
StripePattern pattern(Color::White(), Color::Black());
WHEN("c <- stripe_at_object(pattern, object, point(1.5, 0, 0))")
{
Color c = pattern.stripe_at_object(&object, Tuple::Point(1.5, 0, 0));
THEN("c = white")
{
REQUIRE(c == Color::White());
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Stripes with an pattern transformation", "[features/patterns.feature]")
{
GIVEN("object <- sphere()")
{
Sphere object;
AND_GIVEN("pattern <- stripe_pattern(white, black)")
{
StripePattern pattern(Color::White(), Color::Black());
AND_GIVEN("set_transform(pattern, scaling(2, 2, 2))")
{
pattern.set_pattern_transform(Matrix::scaling(2, 2, 2));
WHEN("c <- stripe_at_object(pattern, object, point(1.5, 0, 0))")
{
Color c = pattern.stripe_at_object(&object, Tuple::Point(1.5, 0, 0));
THEN("c = white")
{
REQUIRE(c == Color::White());
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Stripes with both an object and pattern transformation", "[features/patterns.feature]")
{
GIVEN("object <- sphere()")
{
Sphere object;
AND_GIVEN("set_transform(object, scaling(2, 2, 2))")
{
object.set_transform(Matrix::scaling(2, 2, 2));
AND_GIVEN("pattern <- stripe_pattern(white, black)")
{
StripePattern pattern(Color::White(), Color::Black());
AND_GIVEN("set_pattern_transform(pattern, translation(0.5, 0, 0)))")
{
pattern.set_pattern_transform(Matrix::translation(0.5, 0, 0));
WHEN("c <- stripe_at_object(pattern, object, point(2.5, 0, 0))")
{
Color c = pattern.stripe_at_object(&object, Tuple::Point(1.5, 0, 0));
THEN("c = white")
{
REQUIRE(c == Color::White());
}
}
}
}
}
}
} }