[FEAT] Add Plane Chapter 09 is done

This commit is contained in:
2024-02-27 23:29:44 +01:00
parent 86e31e76eb
commit 32689ab4cc
20 changed files with 399 additions and 68 deletions

View File

@@ -23,6 +23,6 @@ The Web Site of the book: http://raytracerchallenge.com/
| :------------------------: | :------------------------: | | :------------------------: | :------------------------: |
| ![05](data/chapter_05.png) | ![06](data/chapter_06.png) | | ![05](data/chapter_05.png) | ![06](data/chapter_06.png) |
| Chapiter 07 | Chapiter 08 | | Chapiter 07 | Chapiter 08 | Chapiter 09 |
| :------------------------: | :----------------------------: | |:------------------------: | :------------------------: | :----------------------------: |
| ![07](data/chapter_07.png) | ![08](data/chapter_08.png) | |![07](data/chapter_07.png) | ![08](data/chapter_08.png) | ![09](data/chapter_09.png) |

View File

@@ -13,3 +13,6 @@ target_link_libraries(chapter_06 PRIVATE raytracing gcov)
add_executable(chapter_07 chapter_07.cpp) add_executable(chapter_07 chapter_07.cpp)
target_link_libraries(chapter_07 PRIVATE raytracing gcov) target_link_libraries(chapter_07 PRIVATE raytracing gcov)
add_executable(chapter_09 chapter_09.cpp)
target_link_libraries(chapter_09 PRIVATE raytracing gcov)

101
apps/chapter_09.cpp Normal file
View File

@@ -0,0 +1,101 @@
/*!
* chapter_09.cpp
*
* Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* @Author: NADAL Jean-Baptiste
* @Date: 26/02/2024
*
*/
// This is an independent project of an individual developer. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
#include <chrono>
#include <cstdio>
#include <raytracing.h>
/* ------------------------------------------------------------------------- */
using namespace Raytracer;
using namespace std;
/* ------------------------------------------------------------------------- */
int main(void)
{
World the_world;
Camera the_camera;
Canvas the_canvas;
Plane *the_floor;
Sphere *the_middle, *the_right, *the_left;
chrono::time_point<chrono::high_resolution_clock> the_start, the_end;
printf("Chapter 09 example.\n");
// Floor is an extremely flattened sphere with a matte texture.
the_floor = new Plane();
the_floor->material().set_color(Color(1, 0.9, 0.9));
the_floor->material().set_specular(0);
the_world.add_object(the_floor);
// The large sphere in the middle is a unit sphere, translated upward slightly and colored green.
the_middle = new Sphere();
the_middle->set_transform(Matrix::translation(-0.5, 1, 0.5));
the_middle->material().set_color(Color(0.1, 1, 0.5));
the_middle->material().set_diffuse(0.7);
the_middle->material().set_specular(0.3);
the_world.add_object(the_middle);
// The smaller green sphere on the right is scaled in half
the_right = new Sphere();
the_right->set_transform(Matrix::translation(1.5, 0.5, -0.5) * Matrix::scaling(0.5, 0.5, 0.5));
the_right->material().set_color(Color(0.5, 1, 0.1));
the_right->material().set_diffuse(0.7);
the_right->material().set_specular(0.3);
the_world.add_object(the_right);
// The smallest sphere is scaled by a third, before being translated
the_left = new Sphere();
the_left->set_transform(Matrix::translation(-1.5, 0.33, -0.75) * Matrix::scaling(0.33, 0.33, 0.33));
the_left->material().set_color(Color(1, 0.8, 0.1));
the_left->material().set_diffuse(0.7);
the_left->material().set_specular(0.3);
the_world.add_object(the_left);
// The Light source is white, shining from above and to the left
the_world.set_light(PointLight(Tuple::Point(-10, 10, -10), Color(1, 1, 1)));
// Configure the camera.
// the_camera = Camera(100, 50, std::numbers::pi / 2);
the_camera = Camera(320, 200, std::numbers::pi / 2);
the_camera.set_transform(
Matrix::view_transform(Tuple::Point(0, 1.5, -3.5), Tuple::Point(0, 1, 0), Tuple::Vector(0, 1, 0)));
the_start = chrono::high_resolution_clock::now();
the_canvas = the_camera.render(the_world);
the_end = chrono::high_resolution_clock::now();
the_canvas.save_to_file("chapter09.ppm");
chrono::duration<double> the_elapsed_time = the_end - the_start;
printf("Execution Time: %f secondes\n", the_elapsed_time.count());
return 0;
}

BIN
data/chapter_09.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -24,6 +24,7 @@ add_library(raytracing
src/renderer/material.cpp src/renderer/material.cpp
src/renderer/ray.cpp src/renderer/ray.cpp
src/renderer/world.cpp src/renderer/world.cpp
src/shapes/plane.cpp
src/shapes/shape.cpp src/shapes/shape.cpp
src/shapes/sphere.cpp src/shapes/sphere.cpp
) )

View File

@@ -38,4 +38,5 @@
#include "renderer/material.h" #include "renderer/material.h"
#include "renderer/ray.h" #include "renderer/ray.h"
#include "renderer/world.h" #include "renderer/world.h"
#include "shapes/plane.h"
#include "shapes/sphere.h" #include "shapes/sphere.h"

View File

@@ -34,7 +34,7 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
IntersectionData::IntersectionData(void) : m_is_inside(false), m_distance(0) IntersectionData::IntersectionData(void) : m_is_inside(false), m_distance(0), m_shape(nullptr)
{ {
} }
@@ -56,12 +56,12 @@ void IntersectionData::set_distance_t(double a_value)
const Shape &IntersectionData::object(void) const const Shape &IntersectionData::object(void) const
{ {
return m_shape; return *m_shape;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
void IntersectionData::set_object(const Shape &a_shape) void IntersectionData::set_object(Shape *a_shape)
{ {
m_shape = a_shape; m_shape = a_shape;
} }

View File

@@ -45,7 +45,7 @@ namespace Raytracer
void set_distance_t(double a_value); void set_distance_t(double a_value);
const Shape &object(void) const; const Shape &object(void) const;
void set_object(const Shape &a_shape); void set_object(Shape *a_shape);
const Tuple &point(void) const; const Tuple &point(void) const;
void set_point(const Tuple &a_point); void set_point(const Tuple &a_point);
@@ -65,7 +65,7 @@ namespace Raytracer
private: private:
bool m_is_inside; bool m_is_inside;
double m_distance; double m_distance;
Shape m_shape; // TODO ?? Shape *m_shape;
Tuple m_point; Tuple m_point;
Tuple m_over_point; Tuple m_over_point;
Tuple m_eyev; Tuple m_eyev;

View File

@@ -36,13 +36,13 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Intersection::Intersection(void) : m_is_nothing(true), m_distance_t(0.0), m_shape() Intersection::Intersection(void) : m_is_nothing(true), m_distance_t(0.0), m_shape(nullptr)
{ {
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Intersection::Intersection(double a_distance_t, const Shape &a_shape) : Intersection::Intersection(double a_distance_t, Shape *a_shape) :
m_is_nothing(false), m_is_nothing(false),
m_distance_t(a_distance_t), m_distance_t(a_distance_t),
m_shape(a_shape) m_shape(a_shape)
@@ -143,7 +143,7 @@ double Intersection::distance_t(void) const
const Shape &Intersection::object(void) const const Shape &Intersection::object(void) const
{ {
return m_shape; return *m_shape;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -173,7 +173,7 @@ IntersectionData Intersection::prepare_computations(Ray a_ray) const
// Precompute some useful values // Precompute some useful values
the_data.set_point(a_ray.position(m_distance_t)); the_data.set_point(a_ray.position(m_distance_t));
the_data.set_eyev(-a_ray.direction()); the_data.set_eyev(-a_ray.direction());
the_data.set_normalv(m_shape.normal_at(the_data.point())); the_data.set_normalv(m_shape->normal_at(the_data.point()));
the_data.set_over_point(the_data.point() + the_data.normalv() * kEpsilon); the_data.set_over_point(the_data.point() + the_data.normalv() * kEpsilon);
the_data.set_inside(); the_data.set_inside();

View File

@@ -41,7 +41,7 @@ namespace Raytracer
{ {
public: public:
Intersection(void); Intersection(void);
Intersection(double a_distance_t, const Shape &a_shape); Intersection(double a_distance_t, Shape *a_shape);
Intersection(Intersection &an_intersection); Intersection(Intersection &an_intersection);
Intersection(const Intersection &an_intersection); Intersection(const Intersection &an_intersection);
@@ -65,7 +65,7 @@ namespace Raytracer
private: private:
bool m_is_nothing; bool m_is_nothing;
double m_distance_t; double m_distance_t;
Shape m_shape; Shape *m_shape;
}; };
}; // namespace Raytracer }; // namespace Raytracer

View File

@@ -0,0 +1,63 @@
/*!
* sphere.cpp
*
* Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* @Author: NADAL Jean-Baptiste
* @Date: 05/02/2024
*
*/
// This is an independent project of an individual developer. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
/* ------------------------------------------------------------------------- */
#include <cmath>
#include "core/common.h"
#include "core/intersections.h"
#include "plane.h"
using namespace Raytracer;
/* ------------------------------------------------------------------------- */
Intersections Plane::local_intersect(const Ray &a_ray)
{
Intersections the_intersections;
if (std::abs(a_ray.direction().y()) < kEpsilon)
{
return the_intersections;
}
double the_t = -a_ray.origin().y() / a_ray.direction().y();
the_intersections.add(Intersection(the_t, this));
return the_intersections;
}
/* ------------------------------------------------------------------------- */
Tuple Plane::local_normal_at(const Tuple &a_local_point) const
{
return Tuple::Vector(0, 1, 0);
}

View File

@@ -0,0 +1,46 @@
/*!
* plane.h
*
* Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* @Author: NADAL Jean-Baptiste
* @Date: 27/02/2024
*
*/
#ifndef _RAYTRACER_PLANE_H
#define _RAYTRACER_PLANE_H
/* ------------------------------------------------------------------------- */
#include "shapes/shape.h"
/* ------------------------------------------------------------------------- */
namespace Raytracer
{
class Plane : public Shape
{
public:
Plane(void) = default;
Intersections local_intersect(const Ray &a_ray) override;
Tuple local_normal_at(const Tuple &a_local_point) const override;
};
}; // namespace Raytracer
#endif // _RAYTRACER_PLANE_H

View File

@@ -38,23 +38,21 @@ using namespace Raytracer;
#define kNothing 0 #define kNothing 0
uint32_t Shape::s_current_index = 0;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Shape::Shape(void) : m_id(kNothing), m_transform(Matrix::identity()) Shape::Shape(void) : m_transform(Matrix::identity())
{ {
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Shape::Shape(Shape &a_copy) : m_id(a_copy.m_id), m_transform(a_copy.m_transform), m_material(a_copy.m_material) Shape::Shape(Shape &a_copy) : m_transform(a_copy.m_transform), m_material(a_copy.m_material)
{ {
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Shape::Shape(const Shape &a_copy) : m_id(a_copy.m_id), m_transform(a_copy.m_transform), m_material(a_copy.m_material) Shape::Shape(const Shape &a_copy) : m_transform(a_copy.m_transform), m_material(a_copy.m_material)
{ {
} }
@@ -67,7 +65,6 @@ const Shape &Shape::operator=(const Shape &a_shape)
return *this; return *this;
} }
m_id = a_shape.m_id;
m_transform = a_shape.m_transform; m_transform = a_shape.m_transform;
m_material = a_shape.m_material; m_material = a_shape.m_material;
@@ -78,7 +75,6 @@ const Shape &Shape::operator=(const Shape &a_shape)
bool Shape::operator==(const Shape &a_shape) const bool Shape::operator==(const Shape &a_shape) const
{ {
// (m_id == a_shape.m_id) && (
return (m_transform == a_shape.m_transform) && (m_material == a_shape.m_material); return (m_transform == a_shape.m_transform) && (m_material == a_shape.m_material);
} }
@@ -159,10 +155,3 @@ Intersections Shape::local_intersect(const Ray &a_ray)
return the_ret; return the_ret;
} }
/* ------------------------------------------------------------------------- */
void Shape::inc_id(void)
{
m_id = s_current_index++;
}

View File

@@ -66,14 +66,9 @@ namespace Raytracer
Intersections intersect(const Ray &a_ray); Intersections intersect(const Ray &a_ray);
virtual Intersections local_intersect(const Ray &a_ray); virtual Intersections local_intersect(const Ray &a_ray);
protected:
void inc_id(void);
private: private:
uint32_t m_id;
Matrix m_transform; Matrix m_transform;
Material m_material; Material m_material;
static uint32_t s_current_index;
}; };
}; // namespace Raytracer }; // namespace Raytracer

View File

@@ -39,13 +39,6 @@ using namespace Raytracer;
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
Sphere::Sphere(void)
{
inc_id();
}
/* ------------------------------------------------------------------------- */
Intersections Sphere::local_intersect(const Ray &a_ray) Intersections Sphere::local_intersect(const Ray &a_ray)
{ {
Intersections the_intersections; Intersections the_intersections;
@@ -61,8 +54,8 @@ Intersections Sphere::local_intersect(const Ray &a_ray)
if (discriminant >= 0) if (discriminant >= 0)
{ {
double the_sqrt = std::sqrt(discriminant); double the_sqrt = std::sqrt(discriminant);
the_intersections.add(Intersection((-the_b - the_sqrt) / (2 * the_a), *this)); the_intersections.add(Intersection((-the_b - the_sqrt) / (2 * the_a), this));
the_intersections.add(Intersection((-the_b + the_sqrt) / (2 * the_a), *this)); the_intersections.add(Intersection((-the_b + the_sqrt) / (2 * the_a), this));
} }
return the_intersections; return the_intersections;

View File

@@ -37,7 +37,7 @@ namespace Raytracer
class Sphere : public Shape class Sphere : public Shape
{ {
public: public:
Sphere(void); Sphere(void) = default;
Intersections local_intersect(const Ray &a_ray) override; Intersections local_intersect(const Ray &a_ray) override;
Tuple local_normal_at(const Tuple &a_local_point) const override; Tuple local_normal_at(const Tuple &a_local_point) const override;
}; };

View File

@@ -234,7 +234,7 @@ SCENARIO("An intersection encapsulates t and object", "[features/intersections.f
Sphere s; Sphere s;
WHEN("intersection(3.5,s)") WHEN("intersection(3.5,s)")
{ {
Intersection i(3.5, s); Intersection i(3.5, &s);
THEN("i.t = 3.5") THEN("i.t = 3.5")
{ {
@@ -257,7 +257,7 @@ SCENARIO("An intersection could be affected", "[features/intersections.feature]"
Sphere s; Sphere s;
AND_GIVEN("i1 <- intersection(3.5,s) and i2 <- intersection()") AND_GIVEN("i1 <- intersection(3.5,s) and i2 <- intersection()")
{ {
Intersection i1(3.5, s); Intersection i1(3.5, &s);
Intersection i2; Intersection i2;
WHEN("i2 <- i1") WHEN("i2 <- i1")
@@ -286,8 +286,8 @@ SCENARIO("Intersection could be compared", "[features/intersections.feature]")
Sphere s; Sphere s;
AND_GIVEN("i1 <- intersection(3,s) and i2 <- intersection(4,s)") AND_GIVEN("i1 <- intersection(3,s) and i2 <- intersection(4,s)")
{ {
Intersection i1(3.0, s); Intersection i1(3.0, &s);
Intersection i2(4.0, s); Intersection i2(4.0, &s);
THEN("i2 > i1") THEN("i2 > i1")
{ {
@@ -326,10 +326,10 @@ SCENARIO("Aggregating intersections", "[features/intersections.feature]")
Sphere s; Sphere s;
AND_GIVEN("i1 <- intersection(1,s)") AND_GIVEN("i1 <- intersection(1,s)")
{ {
Intersection i1(1, s); Intersection i1(1, &s);
AND_GIVEN("i2 <- intersection(2,s)") AND_GIVEN("i2 <- intersection(2,s)")
{ {
Intersection i2(2, s); Intersection i2(2, &s);
WHEN("xs <- intersections(i1,i2)") WHEN("xs <- intersections(i1,i2)")
{ {
Intersections xs = Intersections({i1, i2}); Intersections xs = Intersections({i1, i2});
@@ -361,7 +361,7 @@ SCENARIO("Operations with intersections", "[features/intersections.feature]")
AND_GIVEN("s <- sphere()") AND_GIVEN("s <- sphere()")
{ {
Sphere s; Sphere s;
Intersection i1(1, s); Intersection i1(1, &s);
AND_GIVEN("xs2 <- intersections({i1})") AND_GIVEN("xs2 <- intersections({i1})")
{ {
Intersections xs2({i1}); Intersections xs2({i1});
@@ -423,10 +423,10 @@ SCENARIO("The hit, when all intersections have positive t", "[features/intersect
Sphere s; Sphere s;
AND_GIVEN("i1 <- intersection(1,s)") AND_GIVEN("i1 <- intersection(1,s)")
{ {
Intersection i1(1, s); Intersection i1(1, &s);
AND_GIVEN("i2 <- intersection(2,s)") AND_GIVEN("i2 <- intersection(2,s)")
{ {
Intersection i2(2, s); Intersection i2(2, &s);
AND_GIVEN("xs <- intersections(i1,i2)") AND_GIVEN("xs <- intersections(i1,i2)")
{ {
Intersections xs = Intersections({i2, i1}); Intersections xs = Intersections({i2, i1});
@@ -453,10 +453,10 @@ SCENARIO("The hit, when some intersections have negative t", "[features/intersec
Sphere s; Sphere s;
AND_GIVEN("i1 <- intersection(-1,s)") AND_GIVEN("i1 <- intersection(-1,s)")
{ {
Intersection i1(-1, s); Intersection i1(-1, &s);
AND_GIVEN("i2 <- intersection(2,s)") AND_GIVEN("i2 <- intersection(2,s)")
{ {
Intersection i2(1, s); Intersection i2(1, &s);
AND_GIVEN("xs <- intersections(i1,i2)") AND_GIVEN("xs <- intersections(i1,i2)")
{ {
Intersections xs = Intersections({i2, i1}); Intersections xs = Intersections({i2, i1});
@@ -483,10 +483,10 @@ SCENARIO("The hit, when all intersections have negative t", "[features/intersect
Sphere s; Sphere s;
AND_GIVEN("i1 <- intersection(-2,s)") AND_GIVEN("i1 <- intersection(-2,s)")
{ {
Intersection i1(-2, s); Intersection i1(-2, &s);
AND_GIVEN("i2 <- intersection(-1,s)") AND_GIVEN("i2 <- intersection(-1,s)")
{ {
Intersection i2(-1, s); Intersection i2(-1, &s);
AND_GIVEN("xs <- intersections(i1,i2)") AND_GIVEN("xs <- intersections(i1,i2)")
{ {
Intersections xs = Intersections({i1, i2}); Intersections xs = Intersections({i1, i2});
@@ -514,16 +514,16 @@ SCENARIO("The hit is always the lowest nonnegative intersection", "[features/int
Sphere s; Sphere s;
AND_GIVEN("i1 <- intersection(5,s)") AND_GIVEN("i1 <- intersection(5,s)")
{ {
Intersection i1(5, s); Intersection i1(5, &s);
AND_GIVEN("i2 <- intersection(7,s)") AND_GIVEN("i2 <- intersection(7,s)")
{ {
Intersection i2(7, s); Intersection i2(7, &s);
AND_GIVEN("i3 <- intersection(-3,s)") AND_GIVEN("i3 <- intersection(-3,s)")
{ {
Intersection i3(-3, s); Intersection i3(-3, &s);
AND_GIVEN("i4 <- intersection(2,s)") AND_GIVEN("i4 <- intersection(2,s)")
{ {
Intersection i4(2, s); Intersection i4(2, &s);
AND_GIVEN("xs <- intersections(i1, i2, i3, i4)") AND_GIVEN("xs <- intersections(i1, i2, i3, i4)")
{ {
Intersections xs = Intersections({i1, i2, i3, i4}); Intersections xs = Intersections({i1, i2, i3, i4});

View File

@@ -143,7 +143,7 @@ SCENARIO("Precompute the state of an intersection", "[features/intersections.fea
Sphere shape; Sphere shape;
AND_GIVEN("i <- intersection(4, shape)") AND_GIVEN("i <- intersection(4, shape)")
{ {
Intersection i(4, shape); Intersection i(4, &shape);
WHEN("comps <- prepare_computations(i,r)") WHEN("comps <- prepare_computations(i,r)")
{ {
IntersectionData comps = i.prepare_computations(r); IntersectionData comps = i.prepare_computations(r);
@@ -185,7 +185,7 @@ SCENARIO("The hit, when an intersection occurs on the outside", "[features/inter
Sphere shape; Sphere shape;
AND_GIVEN("i <- intersection(4, shape)") AND_GIVEN("i <- intersection(4, shape)")
{ {
Intersection i(4, shape); Intersection i(4, &shape);
WHEN("comps <- prepare_computations(i,r)") WHEN("comps <- prepare_computations(i,r)")
{ {
IntersectionData comps = i.prepare_computations(r); IntersectionData comps = i.prepare_computations(r);
@@ -211,7 +211,7 @@ SCENARIO("The hit, when an intersection occurs on the inside", "[features/inters
Sphere shape; Sphere shape;
AND_GIVEN("i <- intersection(1, shape)") AND_GIVEN("i <- intersection(1, shape)")
{ {
Intersection i(1, shape); Intersection i(1, &shape);
WHEN("comps <- prepare_computations(i,r)") WHEN("comps <- prepare_computations(i,r)")
{ {
IntersectionData comps = i.prepare_computations(r); IntersectionData comps = i.prepare_computations(r);
@@ -252,7 +252,7 @@ SCENARIO("Shading an intersection", "[features/world.feature]")
Shape *shape = w.objects(0); Shape *shape = w.objects(0);
AND_GIVEN("i <- intersection(4, shape)") AND_GIVEN("i <- intersection(4, shape)")
{ {
Intersection i(4, *shape); Intersection i(4, shape);
WHEN("comps <- prepare_computations(i,r)") WHEN("comps <- prepare_computations(i,r)")
{ {
IntersectionData comps = i.prepare_computations(r); IntersectionData comps = i.prepare_computations(r);
@@ -289,7 +289,7 @@ SCENARIO("Shading an intersection from the inside", "[features/world.feature]")
Shape *shape = w.objects(1); Shape *shape = w.objects(1);
AND_GIVEN("i <- intersection(0.5, shape)") AND_GIVEN("i <- intersection(0.5, shape)")
{ {
Intersection i(0.5, *shape); Intersection i(0.5, shape);
WHEN("comps <- prepare_computations(i,r)") WHEN("comps <- prepare_computations(i,r)")
{ {
IntersectionData comps = i.prepare_computations(r); IntersectionData comps = i.prepare_computations(r);

View File

@@ -164,7 +164,7 @@ SCENARIO("shade_hit() is given an intersection in the shadow", "[features/world.
Ray r(Tuple::Point(0, 0, 5), Tuple::Vector(0, 0, 1)); Ray r(Tuple::Point(0, 0, 5), Tuple::Vector(0, 0, 1));
AND_GIVEN("i <- intersection(4, s2)") AND_GIVEN("i <- intersection(4, s2)")
{ {
Intersection i(4, *s2); Intersection i(4, s2);
WHEN("comps <- prepare_computatons(i,r)") WHEN("comps <- prepare_computatons(i,r)")
{ {
IntersectionData comps = i.prepare_computations(r); IntersectionData comps = i.prepare_computations(r);
@@ -200,7 +200,7 @@ SCENARIO("The hit should offset the point", "[features/intersections.feature]")
shape.set_transform(Matrix::translation(0, 0, 1)); shape.set_transform(Matrix::translation(0, 0, 1));
AND_GIVEN("i <- intersection(5, shape)") AND_GIVEN("i <- intersection(5, shape)")
{ {
Intersection i(5, shape); Intersection i(5, &shape);
WHEN("comps <- prepare_computatons(i,r)") WHEN("comps <- prepare_computatons(i,r)")
{ {
IntersectionData comps = i.prepare_computations(r); IntersectionData comps = i.prepare_computations(r);

View File

@@ -244,3 +244,142 @@ SCENARIO("Computing the normal on a transformed shape", "[features/shapes.featur
} }
} }
} }
/* ------------------------------------------------------------------------- */
SCENARIO("The normal of a plane is constant everywhere", "[features/planes.feature]")
{
GIVEN("p <- plane()")
{
Plane p;
WHEN("n1 <- local_normal_at(p, point(0, 0, 0)))")
{
Tuple n1 = p.local_normal_at(Tuple::Point(0, 0, 0));
AND_WHEN("n2 <- local_normal_at(p, point(10, 0, 0)))")
{
Tuple n2 = p.local_normal_at(Tuple::Point(10, 0, 0));
AND_WHEN("n3 <- local_normal_at(p, point(-5, 0, 150)))")
{
Tuple n3 = p.local_normal_at(Tuple::Point(-5, 0, 150));
THEN("n1 = vector(0, 1, 0)")
{
REQUIRE(n1 == Tuple::Vector(0, 1, 0));
}
AND_THEN("n2 = vector(0, 1, 0)")
{
REQUIRE(n1 == Tuple::Vector(0, 1, 0));
}
AND_THEN("n3 = vector(0, 1, 0)")
{
REQUIRE(n1 == Tuple::Vector(0, 1, 0));
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Intersect with a ray parallel to the plane", "[features/planes.feature]")
{
GIVEN("p <- plane()")
{
Plane p;
AND_GIVEN("r <- ray(point(0, 10, 0), vector(0, 0, 1))")
{
Ray r(Tuple::Point(0, 10, 0), Tuple::Vector(0, 0, 1));
WHEN("xs <-local_intersect(p, r)")
{
Intersections xs = p.local_intersect(r);
THEN("xs is empty")
{
REQUIRE(xs.count() == 0);
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Intersect with a coplanar ray", "[features/planes.feature]")
{
GIVEN("p <- plane()")
{
Plane p;
AND_GIVEN("r <- ray(point(0, 0, 0), vector(0, 0, 1))")
{
Ray r(Tuple::Point(0, 0, 0), Tuple::Vector(0, 0, 1));
WHEN("xs <-local_intersect(p, r)")
{
Intersections xs = p.local_intersect(r);
THEN("xs is empty")
{
REQUIRE(xs.count() == 0);
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("A ray Intersecting a plane from above", "[features/planes.feature]")
{
GIVEN("p <- plane()")
{
Plane p;
AND_GIVEN("r <- ray(point(0, 1, 0), vector(0, -1, 0))")
{
Ray r(Tuple::Point(0, 1, 0), Tuple::Vector(0, -1, 0));
WHEN("xs <-local_intersect(p, r)")
{
Intersections xs = p.local_intersect(r);
THEN("xs.count = 1")
{
REQUIRE(xs.count() == 1);
}
AND_THEN("xs[0].t = 1")
{
REQUIRE(xs[0].distance_t() == 1);
}
AND_THEN("xs[0].object = p")
{
REQUIRE(xs[0].object() == p);
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("A ray Intersecting a plane from below", "[features/planes.feature]")
{
GIVEN("p <- plane()")
{
Plane p;
AND_GIVEN("r <- ray(point(0, -1, 0), vector(0, 1, 0))")
{
Ray r(Tuple::Point(0, -1, 0), Tuple::Vector(0, 1, 0));
WHEN("xs <-local_intersect(p, r)")
{
Intersections xs = p.local_intersect(r);
THEN("xs.count = 1")
{
REQUIRE(xs.count() == 1);
}
AND_THEN("xs[0].t = 1")
{
REQUIRE(xs[0].distance_t() == 1);
}
AND_THEN("xs[0].object = p")
{
REQUIRE(xs[0].object() == p);
}
}
}
}
}