[WIP] world is wip
This commit is contained in:
@@ -10,8 +10,9 @@ add_definitions(--coverage)
|
||||
add_library(raytracing
|
||||
|
||||
src/canvas.cpp
|
||||
src/common.cpp
|
||||
src/color.cpp
|
||||
src/common.cpp
|
||||
src/intersection-data.cpp
|
||||
src/intersection.cpp
|
||||
src/intersections.cpp
|
||||
src/material.cpp
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "canvas.h"
|
||||
#include "color.h"
|
||||
#include "common.h"
|
||||
#include "intersection-data.h"
|
||||
#include "intersection.h"
|
||||
#include "intersections.h"
|
||||
#include "material.h"
|
||||
|
||||
131
raytracing/src/intersection-data.cpp
Normal file
131
raytracing/src/intersection-data.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/*!
|
||||
* intersection-data.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: 21/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 "intersection-data.h"
|
||||
|
||||
using namespace Raytracer;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
IntersectionData::IntersectionData(void) : m_is_inside(false), m_distance(0)
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
double IntersectionData::distance_t(void) const
|
||||
{
|
||||
return m_distance;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void IntersectionData::set_distance_t(double a_value)
|
||||
{
|
||||
m_distance = a_value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
const Shape &IntersectionData::object(void) const
|
||||
{
|
||||
return m_shape;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void IntersectionData::set_object(const Shape &a_shape)
|
||||
{
|
||||
m_shape = a_shape;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
const Tuple &IntersectionData::point(void) const
|
||||
{
|
||||
return m_point;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void IntersectionData::set_point(const Tuple &a_point)
|
||||
{
|
||||
m_point = a_point;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
const Tuple &IntersectionData::eyev(void) const
|
||||
{
|
||||
return m_eyev;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void IntersectionData::set_eyev(const Tuple &an_eyev)
|
||||
{
|
||||
m_eyev = an_eyev;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
const Tuple &IntersectionData::normalv(void) const
|
||||
{
|
||||
return m_normalv;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void IntersectionData::set_normalv(const Tuple &a_normalv)
|
||||
{
|
||||
m_normalv = a_normalv;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
const bool IntersectionData::is_inside(void) const
|
||||
{
|
||||
return m_is_inside;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void IntersectionData::set_inside(void)
|
||||
{
|
||||
if (m_normalv.dot(m_eyev) < 0)
|
||||
{
|
||||
m_is_inside = true;
|
||||
m_normalv = -m_normalv;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_is_inside = false;
|
||||
}
|
||||
}
|
||||
73
raytracing/src/intersection-data.h
Normal file
73
raytracing/src/intersection-data.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
* intersection-data.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: 21/02/2024
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RAYTRACER_INTERSECTION_DATA_H
|
||||
#define _RAYTRACER_INTERSECTION_DATA_H
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#include "shape.h"
|
||||
#include "tuple.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
namespace Raytracer
|
||||
{
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class IntersectionData
|
||||
{
|
||||
public:
|
||||
IntersectionData(void);
|
||||
|
||||
double distance_t(void) const;
|
||||
void set_distance_t(double a_value);
|
||||
|
||||
const Shape &object(void) const;
|
||||
void set_object(const Shape &a_shape);
|
||||
|
||||
const Tuple &point(void) const;
|
||||
void set_point(const Tuple &a_point);
|
||||
|
||||
const Tuple &eyev(void) const;
|
||||
void set_eyev(const Tuple &an_eyev);
|
||||
|
||||
const Tuple &normalv(void) const;
|
||||
void set_normalv(const Tuple &a_normalv);
|
||||
|
||||
const bool is_inside(void) const;
|
||||
void set_inside(void);
|
||||
|
||||
private:
|
||||
bool m_is_inside;
|
||||
double m_distance;
|
||||
Shape m_shape; // TODO ??
|
||||
Tuple m_point;
|
||||
Tuple m_eyev;
|
||||
Tuple m_normalv;
|
||||
};
|
||||
|
||||
}; // namespace Raytracer
|
||||
|
||||
#endif /* _RAYTRACER_INTERSECTION_DATA_H */
|
||||
@@ -159,3 +159,22 @@ bool Intersection::is_defined(void)
|
||||
{
|
||||
return !m_is_nothing;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
IntersectionData Intersection::prepare_computations(Ray a_ray) const
|
||||
{
|
||||
IntersectionData the_data;
|
||||
|
||||
// Copy intersections properties for conveniance
|
||||
the_data.set_distance_t(m_distance_t);
|
||||
the_data.set_object(m_shape);
|
||||
|
||||
// Precompute some useful values
|
||||
the_data.set_point(a_ray.position(m_distance_t));
|
||||
the_data.set_eyev(-a_ray.direction());
|
||||
the_data.set_normalv(m_shape.normal_at(the_data.point()));
|
||||
the_data.set_inside();
|
||||
|
||||
return the_data;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#include "intersection-data.h"
|
||||
#include "shape.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@@ -59,6 +60,8 @@ namespace Raytracer
|
||||
bool is_nothing(void);
|
||||
bool is_defined(void);
|
||||
|
||||
IntersectionData prepare_computations(Ray a_ray) const;
|
||||
|
||||
private:
|
||||
bool m_is_nothing;
|
||||
double m_distance_t;
|
||||
|
||||
@@ -117,6 +117,13 @@ void World::add_object(Shape *a_shape)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
Shape *World::objects(uint32_t an_index)
|
||||
{
|
||||
return m_objects[an_index];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
bool World::contains(const Shape &a_shape)
|
||||
{
|
||||
|
||||
@@ -148,14 +155,23 @@ Intersections World::intersect_world(const Ray &a_ray)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
Color World::shade_hit(const IntersectionData &an_intersection_data)
|
||||
{
|
||||
return an_intersection_data.object().material().lighting(
|
||||
m_light, an_intersection_data.point(), an_intersection_data.eyev(), an_intersection_data.normalv());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
World World::default_world(void)
|
||||
{
|
||||
World the_world;
|
||||
Sphere *s1, *s2;
|
||||
|
||||
the_world.set_light(PointLight(Tuple::Point(-10, 10, 10), Color::White()));
|
||||
the_world.set_light(PointLight(Tuple::Point(-10, 10, -10), Color::White()));
|
||||
|
||||
s1 = new Sphere;
|
||||
|
||||
Material &the_s1_mat = s1->material();
|
||||
the_s1_mat.set_color(Color(0.8, 1.0, 0.6));
|
||||
the_s1_mat.set_diffuse(0.7);
|
||||
|
||||
@@ -56,9 +56,12 @@ namespace Raytracer
|
||||
void set_light(const PointLight &a_light);
|
||||
|
||||
void add_object(Shape *a_shape);
|
||||
Shape *objects(uint32_t an_index);
|
||||
|
||||
bool contains(const Shape &a_shape);
|
||||
|
||||
Intersections intersect_world(const Ray &a_ray);
|
||||
Color shade_hit(const IntersectionData &an_intersection_data);
|
||||
|
||||
static World default_world(void);
|
||||
|
||||
|
||||
@@ -53,9 +53,9 @@ SCENARIO("Creating a world", "[features/world.feature]")
|
||||
|
||||
SCENARIO("The default world", "[features/world.feature]")
|
||||
{
|
||||
GIVEN("light <- point_light(point(-10, 10, 10), color(1, 1, 1))")
|
||||
GIVEN("light <- point_light(point(-10, 10, -10), color(1, 1, 1))")
|
||||
{
|
||||
PointLight light = PointLight(Tuple::Point(-10, 10, 10), Color(1, 1, 1));
|
||||
PointLight light = PointLight(Tuple::Point(-10, 10, -10), Color(1, 1, 1));
|
||||
AND_GIVEN("s1 <- sphere")
|
||||
// with:
|
||||
// | material.color | (0.8, 1.0, 0.6) |
|
||||
@@ -130,3 +130,181 @@ SCENARIO("Intersect a world with a ray", "[features/world.feature]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("Precompute the state of an intersection", "[features/intersections.feature]")
|
||||
{
|
||||
GIVEN("r <- ray(point(0, 0, -5), vector(0, 0, 1))")
|
||||
{
|
||||
Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1));
|
||||
AND_GIVEN("shape <- sphere()")
|
||||
{
|
||||
Sphere shape;
|
||||
AND_GIVEN("i <- intersection(4, shape)")
|
||||
{
|
||||
Intersection i(4, shape);
|
||||
WHEN("comps <- prepare_computations(i,r)")
|
||||
{
|
||||
IntersectionData comps = i.prepare_computations(r);
|
||||
THEN("comps.t = i.t")
|
||||
{
|
||||
REQUIRE(comps.distance_t() == i.distance_t());
|
||||
}
|
||||
AND_THEN("comps.object = i.object")
|
||||
{
|
||||
REQUIRE(comps.object() == i.object());
|
||||
}
|
||||
AND_THEN("comps.point = point(0, 0, -1)")
|
||||
{
|
||||
REQUIRE(comps.point() == Tuple::Point(0, 0, -1));
|
||||
}
|
||||
AND_THEN("comps.eyev = vector(0, 0, -1)")
|
||||
{
|
||||
REQUIRE(comps.eyev() == Tuple::Vector(0, 0, -1));
|
||||
}
|
||||
AND_THEN("comps.normalv = vector(0, 0, -1)")
|
||||
{
|
||||
REQUIRE(comps.normalv() == Tuple::Vector(0, 0, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("The hit, when an intersection occurs on the outside", "[features/intersections.feature]")
|
||||
{
|
||||
GIVEN("r <- ray(point(0, 0, -5), vector(0, 0, 1))")
|
||||
{
|
||||
Ray r(Tuple::Point(0, 0, -5), Tuple::Vector(0, 0, 1));
|
||||
AND_GIVEN("shape <- sphere()")
|
||||
{
|
||||
Sphere shape;
|
||||
AND_GIVEN("i <- intersection(4, shape)")
|
||||
{
|
||||
Intersection i(4, shape);
|
||||
WHEN("comps <- prepare_computations(i,r)")
|
||||
{
|
||||
IntersectionData comps = i.prepare_computations(r);
|
||||
THEN("comps.inside = false")
|
||||
{
|
||||
REQUIRE(comps.is_inside() == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("The hit, when an intersection occurs on the inside", "[features/intersections.feature]")
|
||||
{
|
||||
GIVEN("r <- ray(point(0, 0, 0), vector(0, 0, 1))")
|
||||
{
|
||||
Ray r(Tuple::Point(0, 0, 0), Tuple::Vector(0, 0, 1));
|
||||
AND_GIVEN("shape <- sphere()")
|
||||
{
|
||||
Sphere shape;
|
||||
AND_GIVEN("i <- intersection(1, shape)")
|
||||
{
|
||||
Intersection i(1, shape);
|
||||
WHEN("comps <- prepare_computations(i,r)")
|
||||
{
|
||||
IntersectionData comps = i.prepare_computations(r);
|
||||
THEN("comps.point = point(0, 0, 1)")
|
||||
{
|
||||
REQUIRE(comps.point() == Tuple::Point(0, 0, 1));
|
||||
}
|
||||
AND_THEN("comps.eyev = vector(0, 0, -1)")
|
||||
{
|
||||
REQUIRE(comps.eyev() == Tuple::Vector(0, 0, -1));
|
||||
}
|
||||
AND_THEN("comps.inside = false")
|
||||
{
|
||||
REQUIRE(comps.is_inside() == true);
|
||||
}
|
||||
AND_THEN("comps.normalv = vector(0, 0, -1)")
|
||||
{
|
||||
REQUIRE(comps.normalv() == Tuple::Vector(0, 0, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("Shading an intersection", "[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));
|
||||
AND_GIVEN("shape <- first object of w")
|
||||
{
|
||||
Shape *shape = w.objects(0);
|
||||
AND_GIVEN("i <- intersection(4, shape)")
|
||||
{
|
||||
Intersection i(4, *shape);
|
||||
WHEN("comps <- prepare_computations(i,r)")
|
||||
{
|
||||
IntersectionData comps = i.prepare_computations(r);
|
||||
AND_WHEN("c <- shade_hit(w, comps)")
|
||||
{
|
||||
Color c = w.shade_hit(comps);
|
||||
THEN("c = color(0.38066, 0.47583, 0.2855)")
|
||||
{
|
||||
REQUIRE(c == Color(0.38066, 0.47583, 0.2855));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("Shading an intersection from the inside", "[features/world.feature]")
|
||||
{
|
||||
GIVEN("w <- default_world()")
|
||||
{
|
||||
World w = World::default_world();
|
||||
AND_GIVEN("w.light <- point_light(point(0, 0.25, 0))")
|
||||
{
|
||||
w.set_light(PointLight(Tuple::Point(0, 0.25, 0), Color(1, 1, 1)));
|
||||
AND_GIVEN("r <- ray(point(0, 0, 0), vector(0, 0, 1))")
|
||||
{
|
||||
Ray r(Tuple::Point(0, 0, 0), Tuple::Vector(0, 0, 1));
|
||||
AND_GIVEN("shape <- second object of w")
|
||||
{
|
||||
Shape *shape = w.objects(1);
|
||||
AND_GIVEN("i <- intersection(0.5, shape)")
|
||||
{
|
||||
Intersection i(0.5, *shape);
|
||||
WHEN("comps <- prepare_computations(i,r)")
|
||||
{
|
||||
IntersectionData comps = i.prepare_computations(r);
|
||||
AND_WHEN("c <- shade_hit(w, comps)")
|
||||
{
|
||||
Color c = w.shade_hit(comps);
|
||||
THEN("c = color(0.90498, 0.90498, 0.90498)")
|
||||
{
|
||||
REQUIRE(c == Color(0.90498, 0.90498, 0.90498));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user