diff --git a/README.md b/README.md index 26b7594..a681424 100644 --- a/README.md +++ b/README.md @@ -20,3 +20,6 @@ Ray Tracing: The Next Week book: http://raytracerchallenge.com/ # Output ### Chapter 05 ![chapter_05](data/chapter_05.png) + +### Chapter 06 +![chapter_06](data/chapter_06.png) diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index a98e572..d9394c5 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -6,5 +6,7 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(chapter_05 chapter_05.cpp) - target_link_libraries(chapter_05 PRIVATE raytracing gcov) + +add_executable(chapter_06 chapter_06.cpp) +target_link_libraries(chapter_06 PRIVATE raytracing gcov) diff --git a/apps/chapter_06.cpp b/apps/chapter_06.cpp new file mode 100644 index 0000000..89017e2 --- /dev/null +++ b/apps/chapter_06.cpp @@ -0,0 +1,97 @@ +/*! + * chapter_06.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: 20/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 + +#include + +/* ------------------------------------------------------------------------- */ + +#define kImageSize 100 +#define kWallSize 7.0 +#define kWallZ 10 + +using namespace Raytracer; + +/* ------------------------------------------------------------------------- */ + +int shadow_sphere(uint8_t a_canvas_pixels, double a_wall_size, uint8_t a_wall_z) +{ + Canvas the_canvas(a_canvas_pixels, a_canvas_pixels); + Sphere the_shape; + Tuple the_ray_origin = Tuple::Point(0, 0, -5); + PointLight the_light = PointLight(Tuple::Point(-10, 10, -10), Color(1, 1, 1)); + + the_shape.material().set_color(Color(1, 0.2, 1)); + + double the_pixel_size = a_wall_size / a_canvas_pixels; + double the_half = a_wall_size / 2; + double the_world_x, the_world_y; + + // For each row of pixels in the canvas + for (int y = 0; y < a_canvas_pixels - 1; y++) + { + // Compute the world y coordinate (top = +half, bottom = -half) + the_world_y = the_half - the_pixel_size * y; + + // For each pixel in the row + for (int x = 0; x < a_canvas_pixels; x++) + { + // Compute the world x coordinate (left = -half, right = half) + the_world_x = -the_half + the_pixel_size * x; + + // Describe the point on the wall that the ray will target + Tuple the_position = Tuple::Point(the_world_x, the_world_y, a_wall_z); + the_position -= the_ray_origin; + Ray the_ray(the_ray_origin, the_position.normalize()); + + auto the_xs = the_shape.intersect(the_ray); + auto the_intersec = the_xs.hit(); + if (the_intersec.is_defined()) + { + Tuple the_point = the_ray.position(the_intersec.distance_t()); + Tuple the_normal = the_intersec.object().normal_at(the_point); + Tuple the_eye = -the_ray.direction(); + Color the_color = the_intersec.object().material().lighting(the_light, the_point, the_eye, the_normal); + the_canvas.write_pixel(x, y, the_color); + } + } + } + + the_canvas.save_to_file("chapter06.ppm"); + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +int main(void) +{ + printf("Chapter 06 example.\n"); + return shadow_sphere(kImageSize, kWallSize, kWallZ); +} diff --git a/data/chapter_06.png b/data/chapter_06.png new file mode 100644 index 0000000..f8b342e Binary files /dev/null and b/data/chapter_06.png differ diff --git a/raytracing/src/material.cpp b/raytracing/src/material.cpp index b26b216..928b626 100644 --- a/raytracing/src/material.cpp +++ b/raytracing/src/material.cpp @@ -60,6 +60,13 @@ const Color &Material::color(void) const /* ------------------------------------------------------------------------- */ +void Material::set_color(const Color &a_color) +{ + m_color = a_color; +} + +/* ------------------------------------------------------------------------- */ + const double &Material::ambient(void) const { return m_ambient; @@ -116,7 +123,8 @@ void Material::set_shininess(double a_value) /* ------------------------------------------------------------------------- */ -Color Material::lighting(const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev, const Tuple &a_normalv) +Color Material::lighting(const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev, + const Tuple &a_normalv) const { Color the_effective_color; Tuple the_light_v, the_reflect_v; @@ -137,8 +145,7 @@ Color Material::lighting(const PointLight &a_light, const Tuple &a_point, const if (the_light_dot_normal < 0) { - the_diffuse = Color::Black(); - the_specular = Color::Black(); + the_diffuse = the_specular = Color::Black(); } else { diff --git a/raytracing/src/material.h b/raytracing/src/material.h index ce70c71..a9a0615 100644 --- a/raytracing/src/material.h +++ b/raytracing/src/material.h @@ -44,6 +44,7 @@ namespace Raytracer bool operator==(const Material &a_material) const; const Color &color(void) const; + void set_color(const Color &a_color); const double &ambient(void) const; void set_ambient(double a_value); @@ -57,7 +58,8 @@ namespace Raytracer const double &shininess(void) const; void set_shininess(double a_value); - Color lighting(const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev, const Tuple &a_normalv); + Color lighting(const PointLight &a_light, const Tuple &a_point, const Tuple &an_eyev, + const Tuple &a_normalv) const; private: Color m_color; diff --git a/raytracing/src/ray.cpp b/raytracing/src/ray.cpp index 3f3e8b8..f2e8872 100644 --- a/raytracing/src/ray.cpp +++ b/raytracing/src/ray.cpp @@ -55,6 +55,13 @@ const Tuple &Ray::direction(void) const /* ------------------------------------------------------------------------- */ +Tuple &Ray::direction(void) +{ + return m_direction; +} + +/* ------------------------------------------------------------------------- */ + Tuple Ray::position(double a_distance) { return m_origin + m_direction * a_distance; diff --git a/raytracing/src/ray.h b/raytracing/src/ray.h index 6074b34..d3ee1b6 100644 --- a/raytracing/src/ray.h +++ b/raytracing/src/ray.h @@ -43,6 +43,7 @@ namespace Raytracer const Tuple &origin(void) const; const Tuple &direction(void) const; + Tuple &direction(void); Tuple position(double a_distance); diff --git a/raytracing/src/shape.cpp b/raytracing/src/shape.cpp index 9af2d2e..756bc0e 100644 --- a/raytracing/src/shape.cpp +++ b/raytracing/src/shape.cpp @@ -48,13 +48,13 @@ Shape::Shape(void) : m_id(kNothing), m_transform(Matrix::identity()) /* ------------------------------------------------------------------------- */ -Shape::Shape(Shape &a_copy) : m_id(a_copy.m_id), m_transform(Matrix::identity()) +Shape::Shape(Shape &a_copy) : m_id(a_copy.m_id), m_transform(Matrix::identity()), m_material(a_copy.m_material) { } /* ------------------------------------------------------------------------- */ -Shape::Shape(const Shape &a_copy) : m_id(a_copy.m_id), m_transform(Matrix::identity()) +Shape::Shape(const Shape &a_copy) : m_id(a_copy.m_id), m_transform(Matrix::identity()), m_material(a_copy.m_material) { } @@ -69,6 +69,7 @@ const Shape &Shape::operator=(const Shape &a_shape) m_id = a_shape.m_id; m_transform = a_shape.m_transform; + m_material = a_shape.m_material; return *this; } @@ -77,7 +78,7 @@ const Shape &Shape::operator=(const Shape &a_shape) bool Shape::operator==(const Shape &a_shape) const { - return (m_id == a_shape.m_id) && (m_transform == a_shape.m_transform); + return (m_id == a_shape.m_id) && (m_transform == a_shape.m_transform) && (m_material == a_shape.m_material); } /* ------------------------------------------------------------------------- */ @@ -96,6 +97,13 @@ void Shape::set_transform(const Matrix &a_transform_matrix) /* ------------------------------------------------------------------------- */ +Material &Shape::material(void) +{ + return m_material; +} + +/* ------------------------------------------------------------------------- */ + const Material &Shape::material(void) const { return m_material; @@ -110,7 +118,7 @@ void Shape::set_material(const Material &a_material) /* ------------------------------------------------------------------------- */ -Tuple Shape::normal_at(const Tuple &a_world_point) +Tuple Shape::normal_at(const Tuple &a_world_point) const { Tuple the_object_point = m_transform.inverse() * a_world_point; Tuple the_object_normal = the_object_point - Tuple::Point(0, 0, 0); diff --git a/raytracing/src/shape.h b/raytracing/src/shape.h index 8bd21fe..c8da14d 100644 --- a/raytracing/src/shape.h +++ b/raytracing/src/shape.h @@ -55,10 +55,11 @@ namespace Raytracer Matrix &transform(void); void set_transform(const Matrix &a_transform_matrix); + Material &material(void); const Material &material(void) const; void set_material(const Material &a_material); - Tuple normal_at(const Tuple &a_point); + Tuple normal_at(const Tuple &a_point) const; virtual Intersections intersect(Ray &a_ray);