[FEAT] Update cyclinder

This commit is contained in:
NADAL Jean-Baptiste
2024-03-19 18:42:19 +01:00
parent d34ad6a60b
commit 38107165a7
5 changed files with 180 additions and 39 deletions

View File

@@ -212,8 +212,8 @@ int main(void)
// Configure the camera.
// the_camera = Camera(100, 50, std::numbers::pi / 10);
the_camera = Camera(320, 200, std::numbers::pi / 10);
// the_camera = Camera(640, 480, std::numbers::pi / 10);
// the_camera = Camera(320, 200, std::numbers::pi / 10);
the_camera = Camera(640, 480, std::numbers::pi / 10);
the_camera.show_progress_bar();
the_camera.set_transform(
Matrix::view_transform(Tuple::Point(8, 3.5, -9), Tuple::Point(0, 0.3, 0), Tuple::Vector(0, 1, 0)));

View File

@@ -34,11 +34,17 @@
/* ------------------------------------------------------------------------- */
bool Raytracer::double_equal(double a, double b)
bool Raytracer::double_equal(double the_a, double the_b)
{
#if 0
double the_fabs = std::fabs(a - b);
bool the_test = the_fabs < kEpsilon;
#endif
return std::fabs(a - b) < kEpsilon;
if (the_a == std::numeric_limits<double>::infinity() && the_b == std::numeric_limits<double>::infinity())
return true;
if (the_a == -std::numeric_limits<double>::infinity() && the_b == -std::numeric_limits<double>::infinity())
return true;
return std::fabs(the_a - the_b) < kEpsilon;
}

View File

@@ -41,7 +41,7 @@ using namespace Raytracer;
Intersections Cylinder::local_intersect(const Ray &a_ray)
{
double the_a, the_b, the_c, the_disc;
double the_a, the_b, the_c, the_discriminant;
double the_t0, the_t1;
double the_y0, the_y1;
Intersections the_intersections;
@@ -51,24 +51,22 @@ Intersections Cylinder::local_intersect(const Ray &a_ray)
the_a = std::pow(the_ray_direction.x(), 2) + std::pow(the_ray_direction.z(), 2);
// Ray is parallel to the y axis
if (double_equal(the_a, 0))
if (double_equal(the_a, 0) == false)
{
return the_intersections;
}
the_b = 2 * the_ray_origin.x() * the_ray_direction.x() +
2 * the_ray_origin.z() * the_ray_direction.z();
the_c = std::pow(the_ray_origin.x(), 2) + std::pow(the_ray_origin.z(), 2) - 1;
the_disc = std::pow(the_b, 2) - 4 * the_a * the_c;
the_discriminant = std::pow(the_b, 2) - 4 * the_a * the_c;
if (the_disc < 0)
if (the_discriminant < 0)
{
return the_intersections;
}
the_t0 = (-the_b - std::sqrt(the_disc)) / (2 * the_a);
the_t1 = (-the_b + std::sqrt(the_disc)) / (2 * the_a);
the_t0 = (-the_b - std::sqrt(the_discriminant)) / (2 * the_a);
the_t1 = (-the_b + std::sqrt(the_discriminant)) / (2 * the_a);
if (the_t0 > the_t1)
{
std::swap(the_t0, the_t1);
@@ -85,6 +83,10 @@ Intersections Cylinder::local_intersect(const Ray &a_ray)
{
the_intersections.add(Intersection(the_t1, this));
}
}
// Caps
intersect_caps(a_ray, the_intersections);
return the_intersections;
}
@@ -123,3 +125,60 @@ void Cylinder::set_maximum(double a_value)
{
m_maximum = a_value;
}
/* ------------------------------------------------------------------------- */
bool Cylinder::closed(void)
{
return m_closed;
}
/* ------------------------------------------------------------------------- */
void Cylinder::set_closed(bool a_state)
{
m_closed = a_state;
}
/* ------------------------------------------------------------------------- */
bool Cylinder::check_cap(const Ray &a_ray, double a_distance_t)
{
double the_x, the_z;
const Tuple &the_ray_direction = a_ray.direction();
const Tuple &the_ray_origin = a_ray.origin();
the_x = the_ray_origin.x() + a_distance_t * the_ray_direction.x();
the_z = the_ray_origin.z() + a_distance_t * the_ray_direction.z();
return (std::pow(the_x, 2) + std::pow(the_z, 2)) <= 1;
}
/* ------------------------------------------------------------------------- */
void Cylinder::intersect_caps(const Ray &a_ray, Intersections &an_xs)
{
double the_distance_t;
// Caps only matter if the cylinder is closed. and might possibility be intersected the ray.
if ((m_closed == false) or (double_equal(a_ray.direction().y(), 0)))
{
return;
}
// Check for an intersection with the lower end cap by intersecting
// the ray with the plane at y = cyl.minimum
the_distance_t = (m_minimum - a_ray.origin().y()) / a_ray.direction().y();
if (check_cap(a_ray, the_distance_t))
{
an_xs.add(Intersection(the_distance_t, this));
}
// Check for an intersection with the upper end cap by intersecting
// the ray with the plane at y = cyl.maximum
the_distance_t = (m_maximum - a_ray.origin().y()) / a_ray.direction().y();
if (check_cap(a_ray, the_distance_t))
{
an_xs.add(Intersection(the_distance_t, this));
}
}

View File

@@ -49,9 +49,17 @@ namespace Raytracer
double maximum(void);
void set_maximum(double a_value);
bool closed(void);
void set_closed(bool a_state);
private:
double m_minimum = std::numeric_limits<double>::infinity();
bool check_cap(const Ray &a_ray, double a_distance_t);
void intersect_caps(const Ray &a_ray, Intersections &an_xs);
private:
double m_minimum = -std::numeric_limits<double>::infinity();
double m_maximum = std::numeric_limits<double>::infinity();
bool m_closed = false;
};
}; // namespace Raytracer

View File

@@ -185,9 +185,9 @@ SCENARIO("The default minimum and maximum for a cylinder", "[features/cylinders.
Cylinder cyl;
THEN("cym.minimum = -infinity")
{
REQUIRE(cyl.minimum() == std::numeric_limits<double>::infinity());
REQUIRE(cyl.minimum() == -std::numeric_limits<double>::infinity());
}
AND_THEN("cym.maximum = -infinity")
AND_THEN("cym.maximum = infinity")
{
REQUIRE(cyl.maximum() == std::numeric_limits<double>::infinity());
}
@@ -245,3 +245,71 @@ SCENARIO("Intersecting a constrained cylinder", "[features/cylinders.feature]")
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The default closed value for a cylinder", "[features/cylinders.feature]")
{
GIVEN("cyl <- cylinder()")
{
Cylinder cyl;
THEN("cyl.closed = false")
{
REQUIRE(cyl.closed() == false);
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("Intersecting the caps of a closed cylinder", "[features/cylinders.feature]")
{
// | | point | direction | count |
// | 1 | point(0, 3, 0) | vector(0, -1, 0) | 2 |
// | 2 | point(0, 3, -2) | vector(0, -1, 2) | 2 |
// | 3 | point(0, 4, -2) | vector(0, -1, 1) | 2 | # corner case
// | 4 | point(0, 0, -2) | vector(0, 1, 2) | 2 |
// | 5 | point(0, -1, -2) | vector(0, 1, 1) | 2 | # corner case
CylinderTestConstrained the_test[] = {
{Tuple::Point(0, 3, 0), Tuple::Vector(0, -1, 0), 2},
{Tuple::Point(0, 3, -2), Tuple::Vector(0, -1, 2), 2},
{Tuple::Point(0, 4, -2), Tuple::Vector(0, -1, 1), 2},
{Tuple::Point(0, 0, -2), Tuple::Vector(0, 1, 2), 2},
{Tuple::Point(0, -1, -2), Tuple::Vector(0, 1, 1), 2}
};
GIVEN("cyl <- cylinder()")
{
Cylinder cyl;
AND_GIVEN("cyl.minimum <- 1")
{
cyl.set_minimum(1);
AND_GIVEN("cyl.maximum <- 2")
{
cyl.set_maximum(2);
AND_GIVEN("cyl.closed <- true")
{
cyl.set_closed(true);
AND_GIVEN("direction <- normalize(<direction>)")
{
AND_GIVEN("r <- ray(<point>, direction)")
{
WHEN("xs <- local_intersect(cyl,r)")
{
for (int i = 0; i < 5; i++)
{
Tuple direction = the_test[i].direction.normalize();
Ray r(the_test[i].point, direction);
Intersections xs = cyl.local_intersect(r);
THEN("xs.count = <count>")
{
REQUIRE(xs.count() == the_test[i].count);
}
}
}
}
}
}
}
}
}
}