[FEAT] until test3 of schlick implementation

This commit is contained in:
NADAL Jean-Baptiste
2024-03-12 18:42:19 +01:00
parent 6f55253ffd
commit 6e17dd94c1
5 changed files with 190 additions and 5 deletions

View File

@@ -6,6 +6,7 @@
"NADAL", "NADAL",
"noninvertible", "noninvertible",
"Raytracer", "Raytracer",
"Schlick",
"submatrix" "submatrix"
], ],
"files.associations": { "files.associations": {

View File

@@ -28,6 +28,7 @@
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
#include <cmath>
#include <cstdio> #include <cstdio>
#include "intersection-data.h" #include "intersection-data.h"
@@ -213,3 +214,33 @@ const double IntersectionData::n2(void) const
{ {
return m_n2; return m_n2;
} }
/* ------------------------------------------------------------------------- */
double IntersectionData::schlick(void)
{
double the_cos, the_r0;
// Find the cosine of the angle between the eye and the normal vectors
the_cos = m_eyev.dot(m_normalv);
// Total internal reflection can only occur if n1 > n2
if (m_n1 > m_n2)
{
double the_n, the_sin2_t, the_cos_t;
the_n = m_n1 / m_n2;
the_sin2_t = std::pow(the_n, 2) * (1.0 - std::pow(the_cos, 2));
if (the_sin2_t > 1.0)
{
return 1.0;
}
// Compute cosine of the theta_t using trig identity
the_cos_t = std::sqrt(1.0 - the_sin2_t);
the_cos = the_cos_t;
}
the_r0 = std::pow(((m_n1 - m_n2) / (m_n1 + m_n2)), 2);
return the_r0 + (1 - the_r0) * std::pow((1 - the_cos), 5);
}

View File

@@ -75,6 +75,8 @@ namespace Raytracer
void set_n2(double an_n2); void set_n2(double an_n2);
const double n2(void) const; const double n2(void) const;
double schlick(void);
private: private:
bool m_is_inside; bool m_is_inside;
double m_distance; double m_distance;

View File

@@ -168,7 +168,8 @@ Color World::shade_hit(const IntersectionData &an_intersection_data, uint32_t a_
Color the_surface = the_object->material().lighting(the_object, m_light, an_intersection_data.over_point(), Color the_surface = the_object->material().lighting(the_object, m_light, an_intersection_data.over_point(),
an_intersection_data.eyev(), an_intersection_data.normalv(), the_shadowed); an_intersection_data.eyev(), an_intersection_data.normalv(), the_shadowed);
Color the_reflected = reflected_color(an_intersection_data, a_remaining); Color the_reflected = reflected_color(an_intersection_data, a_remaining);
return the_surface + the_reflected; Color the_refracted = refracted_color(an_intersection_data, a_remaining);
return the_surface + the_reflected + the_refracted;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@@ -194,7 +195,7 @@ Color World::reflected_color(const IntersectionData &a_data, uint32_t a_remainin
Color World::refracted_color(const IntersectionData &an_intersection_data, uint32_t a_remaining) const Color World::refracted_color(const IntersectionData &an_intersection_data, uint32_t a_remaining) const
{ {
double the_n_ratio, the_cos_i, the_cos_t, the_sin_t; double the_n_ratio, the_cos_i, the_cos_t, the_sin2_t;
Tuple the_direction; Tuple the_direction;
Color the_color; Color the_color;
double the_transparency; double the_transparency;
@@ -218,14 +219,14 @@ Color World::refracted_color(const IntersectionData &an_intersection_data, uint3
the_cos_i = an_intersection_data.eyev().dot(an_intersection_data.normalv()); the_cos_i = an_intersection_data.eyev().dot(an_intersection_data.normalv());
// Find sin(theta_t)^2 via trigonometric identity // Find sin(theta_t)^2 via trigonometric identity
the_sin_t = the_n_ratio * the_n_ratio * (1.0 - the_cos_i * the_cos_i); the_sin2_t = the_n_ratio * the_n_ratio * (1.0 - the_cos_i * the_cos_i);
if (the_sin_t > 1) if (the_sin2_t > 1)
{ {
return Color(0, 0, 0); return Color(0, 0, 0);
} }
// Find cos(theta_t) via trigonometric identity // Find cos(theta_t) via trigonometric identity
the_cos_t = std::sqrt(1.0 - the_sin_t); the_cos_t = std::sqrt(1.0 - the_sin2_t);
// Compute the direction of the refracted ray // Compute the direction of the refracted ray
the_direction = an_intersection_data.normalv() * (the_n_ratio * the_cos_i - the_cos_t) - the_direction = an_intersection_data.normalv() * (the_n_ratio * the_cos_i - the_cos_t) -

View File

@@ -633,3 +633,153 @@ SCENARIO("The refracted color with a refracted ray", "[features/world.feature]")
} }
} }
} }
/* ------------------------------------------------------------------------- */
SCENARIO("shade_hit() with a transparent material", "[features/world.feature]")
{
GIVEN("w <- default_world()")
{
World w = World::default_world();
AND_GIVEN("floor <- plane() with:")
{
// | transform | translation(0, -1, 0) |
// | material.transparency | 0.5 |
// | material.refractive_index | 1.5 |
Plane floor;
floor.set_transform(Matrix::translation(0, -1, 0));
floor.material().set_transparency(0.5);
floor.material().set_refractive_index(1.5);
AND_GIVEN("floor is added to w")
{
w.add_object(&floor);
AND_GIVEN("ball <- sphere() with:")
{
// | material.color | (1, 0, 0) |
// | material.ambient | 0.5 |
// | transform | translation(0, -3.5, -0.5) |
Sphere ball;
ball.material().set_color(Color(1, 0, 0));
ball.material().set_ambient(0.5);
ball.set_transform(Matrix::translation(0, -3.5, -0.5));
AND_GIVEN("ball is added to w")
{
w.add_object(&ball);
AND_GIVEN("r <- ray(point(0, 0, -3), vector(0, -sqrt(2) / 2, sqrt(2) / 2))")
{
Ray r(Tuple::Point(0, 0, -3), Tuple::Vector(0, -sqrt(2) / 2, sqrt(2) / 2));
AND_GIVEN("xs <- intersections(sqrt(2):floor)")
{
Intersections xs = Intersections({Intersection(sqrt(2), &floor)});
WHEN("comps <- prepare_computations(xs[0], r, xs)")
{
IntersectionData comps = xs[0].prepare_computations(r, &xs);
AND_WHEN("color <- shade_hit(w, comps, 5)")
{
Color color = w.shade_hit(comps, 5);
THEN("color = color(0.93642, 0.68642, 0.68642)")
{
REQUIRE(color == Color(0.93642, 0.68642, 0.68642));
}
}
}
}
}
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The Schlick approximation under total internal reflection", "[features/intersections.feature]")
{
GIVEN("shape <- glass_sphere()")
{
Sphere shape = Sphere::Glass();
AND_GIVEN("r <- ray(point(0, 0, sqrt(2) / 2)), vector(0, 1, 0)")
{
Ray r(Tuple::Point(0, 0, sqrt(2) / 2), Tuple::Vector(0, 1, 0));
AND_GIVEN("xs <- intersections(-sqrt(2) / 2):shape, sqrt(2) / 2):shape)")
{
Intersections xs = Intersections({Intersection(-sqrt(2) / 2, &shape),
Intersection(sqrt(2) / 2, &shape)});
WHEN("comps <- prepare_computations(xs[1], r, xs)")
{
IntersectionData comps = xs[1].prepare_computations(r, &xs);
AND_WHEN("reflectance <- schlick(comps)")
{
double reflectance = comps.schlick();
THEN("reflectance = 1.0")
{
REQUIRE(reflectance == 1.0);
}
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The Schlick approximation with a perpendicular viewing angle", "[features/intersections.feature]")
{
GIVEN("shape <- glass_sphere()")
{
Sphere shape = Sphere::Glass();
AND_GIVEN("r <- ray(point(0, 0, 0), vector(0, 1, 0)")
{
Ray r(Tuple::Point(0, 0, 0), Tuple::Vector(0, 1, 0));
AND_GIVEN("xs <- intersections(-1:shape, 1:shape)")
{
Intersections xs = Intersections({Intersection(-1, &shape),
Intersection(1, &shape)});
WHEN("comps <- prepare_computations(xs[1], r, xs)")
{
IntersectionData comps = xs[1].prepare_computations(r, &xs);
AND_WHEN("reflectance <- schlick(comps)")
{
double reflectance = comps.schlick();
THEN("reflectance = 0.04")
{
REQUIRE(double_equal(reflectance, 0.04));
}
}
}
}
}
}
}
/* ------------------------------------------------------------------------- */
SCENARIO("The Schlick approximation with a small angle and n2 > n1", "[features/intersections.feature]")
{
GIVEN("shape <- glass_sphere()")
{
Sphere shape = Sphere::Glass();
AND_GIVEN("r <- ray(point(0, 0.99, -2), vector(0, 0, 1)")
{
Ray r(Tuple::Point(0, 0.99, -2), Tuple::Vector(0, 0, 1));
AND_GIVEN("xs <- intersections(1.8589:shape)")
{
Intersections xs = Intersections({Intersection(1.8589, &shape)});
WHEN("comps <- prepare_computations(xs[0], r, xs)")
{
IntersectionData comps = xs[0].prepare_computations(r, &xs);
AND_WHEN("reflectance <- schlick(comps)")
{
double reflectance = comps.schlick();
THEN("reflectance = 0.48873")
{
REQUIRE(double_equal(reflectance, 0.48873));
}
}
}
}
}
}
}