From 6901cefbbc03fc494365ab94df9bdd9e699727d1 Mon Sep 17 00:00:00 2001 From: NADAL Jean-Baptiste Date: Tue, 20 Feb 2024 09:57:47 +0100 Subject: [PATCH] [FEAT] Finish the Chapter 06 --- README.md | 3 ++ apps/CMakeLists.txt | 4 +- apps/chapter_06.cpp | 97 ++++++++++++++++++++++++++++++++++++ data/chapter_06.png | Bin 0 -> 4303 bytes raytracing/src/material.cpp | 13 +++-- raytracing/src/material.h | 4 +- raytracing/src/ray.cpp | 7 +++ raytracing/src/ray.h | 1 + raytracing/src/shape.cpp | 16 ++++-- raytracing/src/shape.h | 3 +- 10 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 apps/chapter_06.cpp create mode 100644 data/chapter_06.png 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 0000000000000000000000000000000000000000..f8b342e468526d20685bb2d32a0214deffd55c10 GIT binary patch literal 4303 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 literal 0 HcmV?d00001 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);