Skip to content

Commit

Permalink
Refraction is fully there, with magic fresnel!
Browse files Browse the repository at this point in the history
  • Loading branch information
Godzil committed Feb 22, 2020
1 parent e45dbad commit 51a6bbe
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 3 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ From Chapter 10:

From Chapter 11:

![Chapter 11 reflections rendering test](output/ch11_reflection.png)
![Chapter 11 reflections rendering test](output/ch11_reflection.png)

![Chapter 11 refraction rendering test](output/ch11_refraction.png)

![Chapter 11 rendering test](output/ch11_test.png)
Binary file added output/ch11_refraction.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added output/ch11_test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions source/include/intersection.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@ struct Computation
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside),
overHitPoint(overHitP), underHitPoint(underHitP), reflectVector(reflectV), n1(n1), n2(n2) { };

double schlick()
{
/* Find the cos of the angle betzeen the eye and normal vector */
double cos = this->eyeVector.dot(this->normalVector);
double r0;
/* Total internal reflection can only occur when n1 > n2 */
if (this->n1 > this->n2)
{
double n, sin2_t;
n = this->n1 / this->n2;
sin2_t = (n * n) * (1.0 - (cos * cos));
if (sin2_t > 1.0)
{
return 1.0;
}
/* Compute the cos of theta */
cos = sqrt(1.0 - sin2_t);
}


r0 = ((this->n1 - this->n2) / (this->n1 + this->n2));
r0 = r0 * r0;

return r0 + (1 - r0) * ((1 - cos)*(1 - cos)*(1 - cos)*(1 - cos)*(1 - cos));
};

Shape *object;
double t;
Tuple hitPoint;
Expand Down
8 changes: 8 additions & 0 deletions source/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ Tuple World::shadeHit(Computation comps, uint32_t depthCount)
Tuple reflected = this->reflectColour(comps, depthCount);
Tuple refracted = this->refractedColour(comps, depthCount);

if ((comps.object->material.reflective > 0) && (comps.object->material.transparency > 0))
{
double reflectance = comps.schlick();

return surface + reflected * reflectance + refracted * (1 - reflectance);

}

return surface + reflected + refracted;
}

Expand Down
4 changes: 3 additions & 1 deletion tests/ch11_refraction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ int main()
Sphere glassBall = Sphere();
glassBall.material.shininess = 300;
glassBall.material.transparency = 1;
glassBall.material.reflective = 1;
glassBall.material.refractiveIndex = 1.52;
glassBall.material.diffuse = 0.1;
w.addObject(&glassBall);
Expand All @@ -45,6 +46,7 @@ int main()
airBall.setTransform(scaling(0.5, 0.5, 0.5));
airBall.material.shininess = 300;
airBall.material.transparency = 1;
airBall.material.reflective = 1;
airBall.material.refractiveIndex = 1.0009;
airBall.material.diffuse = 0.1;
w.addObject(&airBall);
Expand All @@ -54,7 +56,7 @@ int main()
w.addLight(&light);

/* Set the camera */
Camera camera = Camera(1000, 1000, M_PI / 3);
Camera camera = Camera(100, 100, M_PI / 3);

camera.setTransform(viewTransform(Point(0, 2.5, 0),
Point(0, 0, 0),
Expand Down
2 changes: 1 addition & 1 deletion tests/ch11_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ int main()
w.addLight(&light);

/* Set the camera */
Camera camera = Camera(800, 400, 1.152);
Camera camera = Camera(400, 100, 1.152);
camera.setTransform(viewTransform(Point(-2.6, 1.5, -3.9),
Point(-0.6, 1, -0.8),
Vector(0, 1, 0)));
Expand Down
49 changes: 49 additions & 0 deletions tests/intersect_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,53 @@ TEST(IntersectTest, The_under_point_is_offset_below_the_surface)

ASSERT_TRUE(double_equal(comps.underHitPoint.z, getEpsilon() / 2));
ASSERT_LT(comps.hitPoint.z, comps.underHitPoint.z);
}

TEST(IntersectTest, The_Schlick_approximation_under_total_internal_reflection)
{
GlassSphere shape = GlassSphere();

Ray r = Ray(Point(0, 0, sqrt(2)/2), Vector(0, 1, 0));
Intersect xs = Intersect();
xs.add(Intersection(-sqrt(2)/2, &shape));
xs.add(Intersection(sqrt(2)/2, &shape));

Computation comps = xs[1].prepareComputation(r, &xs);
double reflectance = comps.schlick();

ASSERT_EQ(reflectance, 1.0);
}

TEST(IntersectTest, The_Schlick_approximation_with_a_perpendicular_viewing_angle)
{
GlassSphere shape = GlassSphere();

Ray r = Ray(Point(0, 0, 0), Vector(0, 1, 0));
Intersect xs = Intersect();
xs.add(Intersection(-1, &shape));
xs.add(Intersection(1, &shape));

Computation comps = xs[1].prepareComputation(r, &xs);
double reflectance = comps.schlick();

ASSERT_TRUE(double_equal(reflectance, 0.04));
}

TEST(IntersectTest, The_Schlick_approximation_with_small_angle_and_n2_gt_n1)
{
GlassSphere shape = GlassSphere();

Ray r = Ray(Point(0, 0.99, -2), Vector(0, 0, 1));
Intersect xs = Intersect();
xs.add(Intersection(1.8589, &shape));

Computation comps = xs[0].prepareComputation(r, &xs);
double reflectance = comps.schlick();

/* Temporary lower the precision */
set_equal_precision(0.00001);

ASSERT_TRUE(double_equal(reflectance, 0.48873));

set_equal_precision(FLT_EPSILON);
}
34 changes: 34 additions & 0 deletions tests/world_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,39 @@ TEST(WorldTest, Shade_hit_with_a_transparent_material)

ASSERT_EQ(c, Colour(0.93642, 0.68642, 0.68642));

set_equal_precision(FLT_EPSILON);
}

TEST(WorldTest, Shade_hit_with_a_reflective_transparent_material)
{
World w = DefaultWorld();

Ray r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2)/2, sqrt(2)/2));

Plane floor = Plane();
floor.setTransform(translation(0, -1, 0));
floor.material.transparency = 0.5;
floor.material.reflective = 0.5;
floor.material.refractiveIndex = 1.5;
w.addObject(&floor);

Sphere ball = Sphere();
ball.material.colour = Colour(1, 0, 0);
ball.material.ambient = 0.5;
ball.setTransform(translation(0, -3.5, -0.5));
w.addObject(&ball);

Intersect xs = Intersect();
xs.add(Intersection(sqrt(2), &floor));

Computation comps = xs[0].prepareComputation(r, &xs);

Tuple c = w.shadeHit(comps, 5);

/* Temporary lower the precision */
set_equal_precision(0.00001);

ASSERT_EQ(c, Colour(0.93391, 0.69643, 0.69243));

set_equal_precision(FLT_EPSILON);
}

0 comments on commit 51a6bbe

Please sign in to comment.