[ADD] ray_for_pixel to camera
This commit is contained in:
@@ -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_h_size(a_h_size),
|
||||||
m_v_size(a_v_size),
|
m_v_size(a_v_size),
|
||||||
m_field_of_view(a_field_of_view),
|
m_field_of_view(a_field_of_view),
|
||||||
|
m_transform(Matrix::identity()),
|
||||||
m_half_width(0),
|
m_half_width(0),
|
||||||
m_half_height(0),
|
m_half_height(0),
|
||||||
m_pixel_size(0)
|
m_pixel_size(0)
|
||||||
|
|
||||||
{
|
{
|
||||||
double the_half_view = tan(m_field_of_view / 2);
|
double the_half_view = tan(m_field_of_view / 2);
|
||||||
double the_aspect_ratio = (double)m_h_size / m_v_size;
|
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_width = the_half_view * the_aspect_ratio;
|
||||||
m_half_height = the_half_view;
|
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)
|
Matrix &Camera::transform(void)
|
||||||
{
|
{
|
||||||
return m_transform;
|
return m_transform;
|
||||||
@@ -92,5 +102,33 @@ Matrix &Camera::transform(void)
|
|||||||
|
|
||||||
double Camera::pixel_size(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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "matrix.h"
|
#include "matrix.h"
|
||||||
|
#include "ray.h"
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@@ -44,10 +45,14 @@ namespace Raytracer
|
|||||||
uint16_t hsize(void) const;
|
uint16_t hsize(void) const;
|
||||||
uint16_t vsize(void) const;
|
uint16_t vsize(void) const;
|
||||||
double field_of_view(void) const;
|
double field_of_view(void) const;
|
||||||
|
|
||||||
|
void set_transform(const Matrix &a_matrix);
|
||||||
Matrix &transform(void);
|
Matrix &transform(void);
|
||||||
|
|
||||||
double pixel_size(void);
|
double pixel_size(void);
|
||||||
|
|
||||||
|
Ray ray_for_pixel(double an_x, double an_y) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t m_h_size;
|
uint16_t m_h_size;
|
||||||
|
|
||||||
|
|||||||
@@ -38,10 +38,9 @@
|
|||||||
|
|
||||||
bool Raytracer::double_equal(double a, double b)
|
bool Raytracer::double_equal(double a, double b)
|
||||||
{
|
{
|
||||||
if ((std::abs((a) - (b)) < kEpsilon))
|
#if 0
|
||||||
{
|
double the_fabs = std::fabs(a - b);
|
||||||
return true;
|
bool the_test = the_fabs < kEpsilon;
|
||||||
}
|
#endif
|
||||||
|
return std::fabs(a - b) < kEpsilon;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,13 @@ Tuple::Tuple(std::vector<double> 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
|
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) &&
|
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))
|
double_equal(m_w, an_other.m_w))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user