[FEAT] Chapter 07 is done.
This commit is contained in:
@@ -23,3 +23,6 @@ Ray Tracing: The Next Week book: http://raytracerchallenge.com/
|
|||||||
|
|
||||||
### Chapter 06
|
### Chapter 06
|
||||||

|

|
||||||
|
|
||||||
|
### Chapter 07
|
||||||
|

|
||||||
|
|||||||
@@ -10,3 +10,6 @@ target_link_libraries(chapter_05 PRIVATE raytracing gcov)
|
|||||||
|
|
||||||
add_executable(chapter_06 chapter_06.cpp)
|
add_executable(chapter_06 chapter_06.cpp)
|
||||||
target_link_libraries(chapter_06 PRIVATE raytracing gcov)
|
target_link_libraries(chapter_06 PRIVATE raytracing gcov)
|
||||||
|
|
||||||
|
add_executable(chapter_07 chapter_07.cpp)
|
||||||
|
target_link_libraries(chapter_07 PRIVATE raytracing gcov)
|
||||||
|
|||||||
108
apps/chapter_07.cpp
Normal file
108
apps/chapter_07.cpp
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*!
|
||||||
|
* chapter_07.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 <cstdio>
|
||||||
|
|
||||||
|
#include <raytracing.h>
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
using namespace Raytracer;
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
World the_world;
|
||||||
|
Camera the_camera;
|
||||||
|
Canvas the_canvas;
|
||||||
|
Sphere *the_floor, *the_left_wall, *the_right_wall;
|
||||||
|
Sphere *the_middle, *the_right, *the_left;
|
||||||
|
printf("Chapter 07 example.\n");
|
||||||
|
|
||||||
|
// Floor is an extremely flattened sphere with a matte texture.
|
||||||
|
the_floor = new Sphere();
|
||||||
|
the_floor->set_transform(Matrix::scaling(10, 0.01, 10));
|
||||||
|
the_floor->material().set_color(Color(1, 0.9, 0.9));
|
||||||
|
the_floor->material().set_specular(0);
|
||||||
|
the_world.add_object(the_floor);
|
||||||
|
|
||||||
|
// The Wall on the left has the same scale and color as the floor,
|
||||||
|
// But is also rotated and translated into place.
|
||||||
|
the_left_wall = new Sphere();
|
||||||
|
the_left_wall->set_transform(Matrix::translation(0, 0, 5) * Matrix::rotation_y(-std::numbers::pi / 4) *
|
||||||
|
Matrix::rotation_x(std::numbers::pi / 2) * Matrix::scaling(10, 0.01, 10));
|
||||||
|
the_left_wall->set_material(the_floor->material());
|
||||||
|
the_world.add_object(the_left_wall);
|
||||||
|
|
||||||
|
// The Wall on the right is identical to the left wall, but is rotated the opposite direction in y.
|
||||||
|
the_right_wall = new Sphere();
|
||||||
|
the_right_wall->set_transform(Matrix::translation(0, 0, 5) * Matrix::rotation_y(std::numbers::pi / 4) *
|
||||||
|
Matrix::rotation_x(std::numbers::pi / 2) * Matrix::scaling(10, 0.01, 10));
|
||||||
|
the_right_wall->set_material(the_floor->material());
|
||||||
|
the_world.add_object(the_right_wall);
|
||||||
|
|
||||||
|
// 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, -5), Tuple::Point(0, 1, 0), Tuple::Vector(0, 1, 0)));
|
||||||
|
|
||||||
|
the_canvas = the_camera.render(the_world);
|
||||||
|
|
||||||
|
the_canvas.save_to_file("chapter07.ppm");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
data/chapter_07.png
Normal file
BIN
data/chapter_07.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -36,6 +36,12 @@ using namespace Raytracer;
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
Camera::Camera(void) : m_h_size(0), m_v_size(0), m_field_of_view(0), m_half_width(0), m_half_height(0), m_pixel_size(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
Camera::Camera(uint16_t a_h_size, uint16_t a_v_size, double a_field_of_view) :
|
Camera::Camera(uint16_t a_h_size, uint16_t a_v_size, double a_field_of_view) :
|
||||||
m_h_size(a_h_size),
|
m_h_size(a_h_size),
|
||||||
m_v_size(a_v_size),
|
m_v_size(a_v_size),
|
||||||
@@ -65,6 +71,39 @@ Camera::Camera(uint16_t a_h_size, uint16_t a_v_size, double a_field_of_view) :
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
Camera::Camera(const Camera &an_other)
|
||||||
|
{
|
||||||
|
m_h_size = an_other.m_h_size;
|
||||||
|
m_v_size = an_other.m_v_size;
|
||||||
|
m_field_of_view = an_other.m_field_of_view;
|
||||||
|
m_transform = an_other.m_transform;
|
||||||
|
m_half_width = an_other.m_half_width;
|
||||||
|
m_half_height = an_other.m_half_height;
|
||||||
|
m_pixel_size = an_other.m_pixel_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
const Camera &Camera::operator=(const Camera &an_other)
|
||||||
|
{
|
||||||
|
if (this == &an_other)
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_h_size = an_other.m_h_size;
|
||||||
|
m_v_size = an_other.m_v_size;
|
||||||
|
m_field_of_view = an_other.m_field_of_view;
|
||||||
|
m_transform = an_other.m_transform;
|
||||||
|
m_half_width = an_other.m_half_width;
|
||||||
|
m_half_height = an_other.m_half_height;
|
||||||
|
m_pixel_size = an_other.m_pixel_size;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
uint16_t Camera::hsize(void) const
|
uint16_t Camera::hsize(void) const
|
||||||
{
|
{
|
||||||
return m_h_size;
|
return m_h_size;
|
||||||
@@ -132,3 +171,22 @@ Ray Camera::ray_for_pixel(double an_x, double an_y) const
|
|||||||
|
|
||||||
return Ray(the_origin, the_direction);
|
return Ray(the_origin, the_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
Canvas Camera::render(const World &a_world)
|
||||||
|
{
|
||||||
|
Canvas the_image(m_h_size, m_v_size);
|
||||||
|
|
||||||
|
for (int y = 0; y < m_v_size - 1; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < m_h_size - 1; x++)
|
||||||
|
{
|
||||||
|
Ray the_ray = ray_for_pixel(x, y);
|
||||||
|
Color the_color = a_world.color_at(the_ray);
|
||||||
|
the_image.write_pixel(x, y, the_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return the_image;
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,8 +30,10 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "canvas.h"
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
#include "ray.h"
|
#include "ray.h"
|
||||||
|
#include "world.h"
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@@ -40,7 +42,11 @@ namespace Raytracer
|
|||||||
class Camera
|
class Camera
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Camera(void);
|
||||||
Camera(uint16_t a_h_size, uint16_t a_v_size, double a_field_of_view);
|
Camera(uint16_t a_h_size, uint16_t a_v_size, double a_field_of_view);
|
||||||
|
Camera(const Camera &a_nother);
|
||||||
|
|
||||||
|
const Camera &operator=(const Camera &an_other);
|
||||||
|
|
||||||
uint16_t hsize(void) const;
|
uint16_t hsize(void) const;
|
||||||
uint16_t vsize(void) const;
|
uint16_t vsize(void) const;
|
||||||
@@ -53,6 +59,8 @@ namespace Raytracer
|
|||||||
|
|
||||||
Ray ray_for_pixel(double an_x, double an_y) const;
|
Ray ray_for_pixel(double an_x, double an_y) const;
|
||||||
|
|
||||||
|
Canvas render(const World &a_world);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t m_h_size;
|
uint16_t m_h_size;
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ using namespace Raytracer;
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
Canvas::Canvas(void) : m_width(0), m_height(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
Canvas::Canvas(uint16_t a_width, uint16_t a_height) : m_width(a_width), m_height(a_height)
|
Canvas::Canvas(uint16_t a_width, uint16_t a_height) : m_width(a_width), m_height(a_height)
|
||||||
{
|
{
|
||||||
m_pixels = std::vector<std::vector<Color>>(m_width, std::vector<Color>(m_height));
|
m_pixels = std::vector<std::vector<Color>>(m_width, std::vector<Color>(m_height));
|
||||||
@@ -53,6 +59,26 @@ Canvas::Canvas(uint16_t a_width, uint16_t a_height) : m_width(a_width), m_height
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
Canvas::Canvas(const Canvas &a_canvas) :
|
||||||
|
m_width(a_canvas.m_width),
|
||||||
|
m_height(a_canvas.m_height),
|
||||||
|
m_pixels(a_canvas.m_pixels)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
Canvas &Canvas::operator=(const Canvas &a_canvas)
|
||||||
|
{
|
||||||
|
m_width = a_canvas.m_width;
|
||||||
|
m_height = a_canvas.m_height;
|
||||||
|
m_pixels = a_canvas.m_pixels;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
uint16_t Canvas::width(void) const
|
uint16_t Canvas::width(void) const
|
||||||
{
|
{
|
||||||
return m_width;
|
return m_width;
|
||||||
|
|||||||
@@ -42,7 +42,11 @@ namespace Raytracer
|
|||||||
class Canvas
|
class Canvas
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Canvas(void);
|
||||||
Canvas(uint16_t a_width, uint16_t a_height);
|
Canvas(uint16_t a_width, uint16_t a_height);
|
||||||
|
Canvas(const Canvas &a_canvas);
|
||||||
|
|
||||||
|
Canvas &operator=(const Canvas &a_canvas);
|
||||||
|
|
||||||
uint16_t width(void) const;
|
uint16_t width(void) const;
|
||||||
uint16_t height(void) const;
|
uint16_t height(void) const;
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ bool World::contains(const Shape &a_shape)
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
Intersections World::intersect_world(const Ray &a_ray)
|
Intersections World::intersect_world(const Ray &a_ray) const
|
||||||
{
|
{
|
||||||
Intersections the_all_intersec;
|
Intersections the_all_intersec;
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ Intersections World::intersect_world(const Ray &a_ray)
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
Color World::shade_hit(const IntersectionData &an_intersection_data)
|
Color World::shade_hit(const IntersectionData &an_intersection_data) const
|
||||||
{
|
{
|
||||||
return an_intersection_data.object().material().lighting(
|
return an_intersection_data.object().material().lighting(
|
||||||
m_light, an_intersection_data.point(), an_intersection_data.eyev(), an_intersection_data.normalv());
|
m_light, an_intersection_data.point(), an_intersection_data.eyev(), an_intersection_data.normalv());
|
||||||
@@ -163,7 +163,7 @@ Color World::shade_hit(const IntersectionData &an_intersection_data)
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
Color World::color_at(const Ray &a_ray)
|
Color World::color_at(const Ray &a_ray) const
|
||||||
{
|
{
|
||||||
Color the_color = Color::Black();
|
Color the_color = Color::Black();
|
||||||
|
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ namespace Raytracer
|
|||||||
|
|
||||||
bool contains(const Shape &a_shape);
|
bool contains(const Shape &a_shape);
|
||||||
|
|
||||||
Intersections intersect_world(const Ray &a_ray);
|
Intersections intersect_world(const Ray &a_ray) const;
|
||||||
Color shade_hit(const IntersectionData &an_intersection_data);
|
Color shade_hit(const IntersectionData &an_intersection_data) const;
|
||||||
Color color_at(const Ray &a_ray);
|
Color color_at(const Ray &a_ray) const;
|
||||||
|
|
||||||
static World default_world(void);
|
static World default_world(void);
|
||||||
|
|
||||||
|
|||||||
@@ -635,3 +635,41 @@ SCENARIO("Constructing a ray when the camera is transformed", "[features/camera.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
SCENARIO("Rendering a world with the camera", "[features/camera.feature]")
|
||||||
|
{
|
||||||
|
GIVEN("w <- default_world()")
|
||||||
|
{
|
||||||
|
World w = World::default_world();
|
||||||
|
AND_GIVEN("c <- camera(11, 11, pi/2)")
|
||||||
|
{
|
||||||
|
Camera c(11, 11, std::numbers::pi / 2);
|
||||||
|
AND_GIVEN("from <- point(0, 0, -5)")
|
||||||
|
{
|
||||||
|
Tuple from = Tuple::Point(0, 0, -5);
|
||||||
|
AND_GIVEN("to <- point(0, 0, 0)")
|
||||||
|
{
|
||||||
|
Tuple to = Tuple::Point(0, 0, 0);
|
||||||
|
AND_GIVEN("up <- vector(0, 1, 0)")
|
||||||
|
{
|
||||||
|
Tuple up = Tuple::Vector(0, 1, 0);
|
||||||
|
AND_GIVEN("c.transform <- view_transform(from, to, up)")
|
||||||
|
{
|
||||||
|
c.set_transform(Matrix::view_transform(from, to, up));
|
||||||
|
WHEN("image <- c.render(w)")
|
||||||
|
{
|
||||||
|
Canvas image = c.render(w);
|
||||||
|
THEN("pixel_at(image, 5, 5) = color(0.38066, 0.47583, 0.2855)")
|
||||||
|
{
|
||||||
|
REQUIRE(image.pixel_at(5, 5) == Color(0.38066, 0.47583, 0.2855));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user