[FEAT] Add Plane Chapter 09 is done
This commit is contained in:
@@ -23,6 +23,6 @@ The Web Site of the book: http://raytracerchallenge.com/
|
|||||||
| :------------------------: | :------------------------: |
|
| :------------------------: | :------------------------: |
|
||||||
|  |  |
|
|  |  |
|
||||||
|
|
||||||
| Chapiter 07 | Chapiter 08 |
|
| Chapiter 07 | Chapiter 08 | Chapiter 09 |
|
||||||
| :------------------------: | :----------------------------: |
|
|:------------------------: | :------------------------: | :----------------------------: |
|
||||||
|  |  |
|
| |  |  |
|
||||||
|
|||||||
@@ -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
101
apps/chapter_09.cpp
Normal 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
BIN
data/chapter_09.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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/sphere.h"
|
#include "shapes/plane.h"
|
||||||
|
#include "shapes/sphere.h"
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
63
raytracing/src/shapes/plane.cpp
Normal file
63
raytracing/src/shapes/plane.cpp
Normal 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);
|
||||||
|
}
|
||||||
46
raytracing/src/shapes/plane.h
Normal file
46
raytracing/src/shapes/plane.h
Normal 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
|
||||||
@@ -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++;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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});
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user