From 999419dfe1b57067fea8fc974cda970bcdd20887 Mon Sep 17 00:00:00 2001 From: Godzil Date: Thu, 20 Feb 2020 01:41:53 +0000 Subject: [PATCH] World is on the verge of working! --- source/include/intersection.h | 16 +++++++++++ source/include/world.h | 5 ++++ source/intersection.cpp | 32 +++++++++++++++++++++ source/world.cpp | 19 ++++++++++++ tests/intersect_test.cpp | 44 ++++++++++++++++++++++++++++ tests/world_test.cpp | 54 +++++++++++++++++++++++++++++++++++ 6 files changed, 170 insertions(+) create mode 100644 source/intersection.cpp diff --git a/source/include/intersection.h b/source/include/intersection.h index e388c06..ae7de5e 100644 --- a/source/include/intersection.h +++ b/source/include/intersection.h @@ -10,9 +10,23 @@ #define DORAYME_INTERSECTION_H #include +#include class Shape; +struct Computation +{ + Computation(Shape *object, double t, Tuple point, Tuple eyev, Tuple normalv, bool inside) : + object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside) { }; + Shape *object; + double t; + Tuple hitPoint; + Tuple eyeVector; + Tuple normalVector; + + bool inside; +}; + class Intersection { public: @@ -23,6 +37,8 @@ public: Intersection(double t, Shape *object) : t(t), object(object) { }; bool nothing() { return (this->object == nullptr); }; + Computation prepareComputation(Ray r); + bool operator==(const Intersection &b) const { return ((this->t == b.t) && (this->object == b.object)); }; }; diff --git a/source/include/world.h b/source/include/world.h index a4116b3..02e92a6 100644 --- a/source/include/world.h +++ b/source/include/world.h @@ -39,6 +39,11 @@ public: bool lightIsIn(Light &l); bool objectIsIn(Shape &s); + Shape *getObject(int i) { return this->objectList[i]; }; + + Tuple shadeHit(Computation comps);; + Tuple colourAt(Ray r); + Intersect intersect(Ray r); }; diff --git a/source/intersection.cpp b/source/intersection.cpp new file mode 100644 index 0000000..f1d6c16 --- /dev/null +++ b/source/intersection.cpp @@ -0,0 +1,32 @@ +/* + * DoRayMe - a quick and dirty Raytracer + * Intersection implementation + * + * Created by Manoƫl Trapier + * Copyright (c) 2020 986-Studio. + * + */ +#include +#include + +Computation Intersection::prepareComputation(Ray r) +{ + Tuple hitP = r.position(this->t); + Tuple normalV = this->object->normalAt(hitP); + Tuple eyeV = -r.direction; + bool inside; + + if (normalV.dot(eyeV) < 0) + { + inside = true; + normalV = -normalV; + } + + + return Computation(this->object, + this->t, + hitP, + eyeV, + normalV, + inside); +} \ No newline at end of file diff --git a/source/world.cpp b/source/world.cpp index fa45c6b..cdfdcb2 100644 --- a/source/world.cpp +++ b/source/world.cpp @@ -90,4 +90,23 @@ Intersect World::intersect(Ray r) } return ret; +} + +Tuple World::shadeHit(Computation comps) +{ + return comps.object->material.lighting(*this->lightList[0], comps.hitPoint, comps.eyeVector, comps.normalVector); +} + +Tuple World::colourAt(Ray r) +{ + Intersection hit = this->intersect(r).hit(); + + if (hit.nothing()) + { + return Colour(0, 0, 0); + } + else + { + return this->shadeHit(hit.prepareComputation(r)); + } } \ No newline at end of file diff --git a/tests/intersect_test.cpp b/tests/intersect_test.cpp index adaef43..223558a 100644 --- a/tests/intersect_test.cpp +++ b/tests/intersect_test.cpp @@ -7,6 +7,7 @@ * */ #include +#include #include #include @@ -129,4 +130,47 @@ TEST(IntersectTest, The_hit_is_always_the_lowest_nonnegative_intersection) Intersection i = xs.hit(); ASSERT_EQ(i, i4); +} + +TEST(IntersectTest, Precomputing_the_state_of_an_intersection) +{ + Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1)); + Sphere shape = Sphere(); + Intersection i = Intersection(4, &shape); + + Computation comps = i.prepareComputation(r); + + ASSERT_EQ(comps.t, i.t); + ASSERT_EQ(comps.object, i.object); + ASSERT_EQ(comps.hitPoint, Point(0, 0, -1)); + ASSERT_EQ(comps.eyeVector, Vector(0, 0, -1)); + ASSERT_EQ(comps.normalVector, Vector(0, 0, -1)); + +} + +TEST(IntersectTest, The_hit_when_an_intersection_occurs_on_the_outside) +{ + Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1)); + Sphere shape = Sphere(); + Intersection i = Intersection(4, &shape); + + Computation comps = i.prepareComputation(r); + + ASSERT_EQ(comps.inside, false); +} + +TEST(IntersectTest, The_hit_when_an_intersection_occurs_on_the_inside) +{ + Ray r = Ray(Point(0, 0, 0), Vector(0, 0, 1)); + Sphere shape = Sphere(); + Intersection i = Intersection(1, &shape); + + Computation comps = i.prepareComputation(r); + ASSERT_EQ(comps.hitPoint, Point(0, 0, 1)); + ASSERT_EQ(comps.eyeVector, Vector(0, 0, -1)); + ASSERT_EQ(comps.inside, true); + + /* Normal vector would have been (0, 0, 1); but is inverted ! */ + + ASSERT_EQ(comps.normalVector, Vector(0, 0, -1)); } \ No newline at end of file diff --git a/tests/world_test.cpp b/tests/world_test.cpp index c971c01..2c7e744 100644 --- a/tests/world_test.cpp +++ b/tests/world_test.cpp @@ -58,3 +58,57 @@ TEST(WorldTest, Intersect_a_world_with_a_ray) ASSERT_EQ(xs[3].t, 6); } +TEST(WorldTest, Shading_an_intersection) +{ + World w = DefaultWorld(); + Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1)); + Shape *s = w.getObject(0); + Intersection i = Intersection(4, s); + Computation comps = i.prepareComputation(r); + Tuple c = w.shadeHit(comps); + + /* Temporary lower the precision */ + set_equal_precision(0.00001); + + ASSERT_EQ(c, Colour(0.38066, 0.47583, 0.2855)); + + set_equal_precision(FLT_EPSILON); +} + +TEST(WorldTest, The_when_ray_miss) +{ + World w = DefaultWorld(); + Ray r = Ray(Point(0, 0, -5), Vector(0, 1, 0)); + Tuple c = w.colourAt(r); + + ASSERT_EQ(c, Colour(0, 0, 0)); +} + +TEST(WorldTest, The_when_ray_hit) +{ + World w = DefaultWorld(); + Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1)); + Tuple c = w.colourAt(r); + + /* Temporary lower the precision */ + set_equal_precision(0.00001); + + ASSERT_EQ(c, Colour(0.38066, 0.47583, 0.2855)); + + set_equal_precision(FLT_EPSILON); +} + +TEST(WorldTest, The_colour_with_an_intersection_behind_the_ray) +{ + World w = DefaultWorld(); + Shape *outer = w.getObject(0); + outer->material.ambient = 1; + Shape *inner = w.getObject(1); + inner->material.ambient = 1; + + Ray r = Ray(Point(0, 0, 0.75), Vector(0, 0, -1)); + + Tuple c = w.colourAt(r); + + ASSERT_EQ(c, inner->material.colour); +} \ No newline at end of file