From 45ff10ecc8b5bd3b826081be1d0361c062e66ba7 Mon Sep 17 00:00:00 2001 From: NADAL Jean-Baptiste Date: Sun, 25 Feb 2024 23:47:40 +0100 Subject: [PATCH] [ADD] ray_for_pixel to camera --- raytracing/src/camera.cpp | 42 +++++++++++++++++++++++-- raytracing/src/camera.h | 5 +++ raytracing/src/common.cpp | 11 +++---- raytracing/src/tuple.cpp | 7 +++++ tests/07_making_scene.cpp | 66 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 8 deletions(-) diff --git a/raytracing/src/camera.cpp b/raytracing/src/camera.cpp index d893b2c..118f1e9 100644 --- a/raytracing/src/camera.cpp +++ b/raytracing/src/camera.cpp @@ -40,9 +40,11 @@ Camera::Camera(uint16_t a_h_size, uint16_t a_v_size, double a_field_of_view) : m_h_size(a_h_size), m_v_size(a_v_size), m_field_of_view(a_field_of_view), + m_transform(Matrix::identity()), m_half_width(0), m_half_height(0), m_pixel_size(0) + { double the_half_view = tan(m_field_of_view / 2); double the_aspect_ratio = (double)m_h_size / m_v_size; @@ -57,7 +59,8 @@ Camera::Camera(uint16_t a_h_size, uint16_t a_v_size, double a_field_of_view) : m_half_width = the_half_view * the_aspect_ratio; m_half_height = the_half_view; } - m_pixel_size = ceil(((m_half_width * 2) / m_h_size) * 100) / 100; + // m_pixel_size = ceil(((m_half_width * 2) / m_h_size) * 100) / 100; + m_pixel_size = (m_half_width * 2) / m_h_size; } /* ------------------------------------------------------------------------- */ @@ -83,6 +86,13 @@ double Camera::field_of_view(void) const /* ------------------------------------------------------------------------- */ +void Camera::set_transform(const Matrix &a_matrix) +{ + m_transform = a_matrix; +} + +/* ------------------------------------------------------------------------- */ + Matrix &Camera::transform(void) { return m_transform; @@ -92,5 +102,33 @@ Matrix &Camera::transform(void) double Camera::pixel_size(void) { - return m_pixel_size; + return ceil(((m_half_width * 2) / m_h_size) * 100) / 100; +} + +/* ------------------------------------------------------------------------- */ + +Ray Camera::ray_for_pixel(double an_x, double an_y) const +{ + double the_xoffset, the_yoffset; + double the_world_x, the_world_y; + Tuple the_pixel, the_origin, the_direction; + + // the offset from the edge of the canvas to the pixel center + the_xoffset = (an_x + 0.5) * m_pixel_size; + the_yoffset = (an_y + 0.5) * m_pixel_size; + + // the untransformed coordinates of the pixel in the world space + // (remember that the camera looks toward -z, so +x is to the *left*) + the_world_x = m_half_width - the_xoffset; + the_world_y = m_half_height - the_yoffset; + + // using the camera matrix, transform the canvas point and the origin, + // and then compute the ray direction vector. + // (remember that the canvas is at z=-1) + Matrix the_invert = m_transform.inverse(); + the_pixel = the_invert * Tuple::Point(the_world_x, the_world_y, -1); + the_origin = the_invert * Tuple::Point(0, 0, 0); + the_direction = (the_pixel - the_origin).normalize(); + + return Ray(the_origin, the_direction); } diff --git a/raytracing/src/camera.h b/raytracing/src/camera.h index 5303056..e696c6e 100644 --- a/raytracing/src/camera.h +++ b/raytracing/src/camera.h @@ -31,6 +31,7 @@ #include #include "matrix.h" +#include "ray.h" /* ------------------------------------------------------------------------- */ @@ -44,10 +45,14 @@ namespace Raytracer uint16_t hsize(void) const; uint16_t vsize(void) const; double field_of_view(void) const; + + void set_transform(const Matrix &a_matrix); Matrix &transform(void); double pixel_size(void); + Ray ray_for_pixel(double an_x, double an_y) const; + private: uint16_t m_h_size; diff --git a/raytracing/src/common.cpp b/raytracing/src/common.cpp index bb7ebf3..166033f 100644 --- a/raytracing/src/common.cpp +++ b/raytracing/src/common.cpp @@ -38,10 +38,9 @@ bool Raytracer::double_equal(double a, double b) { - if ((std::abs((a) - (b)) < kEpsilon)) - { - return true; - } - - return false; +#if 0 + double the_fabs = std::fabs(a - b); + bool the_test = the_fabs < kEpsilon; +#endif + return std::fabs(a - b) < kEpsilon; } diff --git a/raytracing/src/tuple.cpp b/raytracing/src/tuple.cpp index b893bfd..5115e71 100644 --- a/raytracing/src/tuple.cpp +++ b/raytracing/src/tuple.cpp @@ -72,6 +72,13 @@ Tuple::Tuple(std::vector a_data) : m_x(0.0), m_y(0.0), m_z(0.0), m_w(0.0 bool Tuple::operator==(const Tuple &an_other) const { +#if 0 + bool the_eqx = double_equal(m_x, an_other.m_x); + bool the_eqy = double_equal(m_y, an_other.m_y); + bool the_eqz = double_equal(m_z, an_other.m_z); + bool the_eqw = double_equal(m_w, an_other.m_w); +#endif + if (double_equal(m_x, an_other.m_x) && double_equal(m_y, an_other.m_y) && double_equal(m_z, an_other.m_z) && double_equal(m_w, an_other.m_w)) { diff --git a/tests/07_making_scene.cpp b/tests/07_making_scene.cpp index 8eb4e1d..c31ca86 100644 --- a/tests/07_making_scene.cpp +++ b/tests/07_making_scene.cpp @@ -569,3 +569,69 @@ SCENARIO("The pixel size for a vertical canvas", "[features/camera.feature]") } } } + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Constructing a ray through the center of the canvas", "[features/camera.feature]") +{ + GIVEN("c <- camera(201, 101, pi/2)") + { + Camera c(201, 101, std::numbers::pi / 2); + WHEN("r <- ray_for_pixel(c, 100, 50)") + { + Ray r = c.ray_for_pixel(100, 50); + THEN("r.origin = point(0, 0, 0)") + { + REQUIRE(r.origin() == Tuple::Point(0, 0, 0)); + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Constructing a ray through a corner of the canvas", "[features/camera.feature]") +{ + GIVEN("c <- camera(201, 101, pi/2)") + { + Camera c(201, 101, std::numbers::pi / 2); + WHEN("r <- ray_for_pixel(c, 0, 0)") + { + Ray r = c.ray_for_pixel(0, 0); + THEN("r.origin = point(0, 0, 0)") + { + REQUIRE(r.origin() == Tuple::Point(0, 0, 0)); + } + AND_THEN("r.direction = vector(0.66519, 0.33259, -0.66851)") + { + REQUIRE(r.direction() == Tuple::Vector(0.66519, 0.33259, -0.66851)); + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Constructing a ray when the camera is transformed", "[features/camera.feature]") +{ + GIVEN("c <- camera(201, 101, pi/2)") + { + Camera c(201, 101, std::numbers::pi / 2); + WHEN("c.transform <- rotation_y(pi/4) * translation(0, -2, 5)") + { + c.set_transform(Matrix::rotation_y(std::numbers::pi / 4) * Matrix::translation(0, -2, 5)); + AND_WHEN("r <- ray_for_pixel(c, 100, 50)") + { + Ray r = c.ray_for_pixel(100, 50); + THEN("r.origin = point(0, 2, -5)") + { + REQUIRE(r.origin() == Tuple::Point(0, 2, -5)); + } + AND_THEN("r.direction = vector(sqrt(2) / 2, 0, -sqrt(2) / 2)") + { + REQUIRE(r.direction() == Tuple::Vector(sqrt(2) / 2, 0, -sqrt(2) / 2)); + } + } + } + } +}