Refraction is fully there, with magic fresnel!
This commit is contained in:
@@ -41,3 +41,7 @@ From Chapter 10:
|
|||||||
From Chapter 11:
|
From Chapter 11:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
BIN
output/ch11_refraction.png
Normal file
BIN
output/ch11_refraction.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
BIN
output/ch11_test.png
Normal file
BIN
output/ch11_test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 194 KiB |
@@ -23,6 +23,32 @@ struct Computation
|
|||||||
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside),
|
object(object), t(t), hitPoint(point), eyeVector(eyev), normalVector(normalv), inside(inside),
|
||||||
overHitPoint(overHitP), underHitPoint(underHitP), reflectVector(reflectV), n1(n1), n2(n2) { };
|
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;
|
Shape *object;
|
||||||
double t;
|
double t;
|
||||||
Tuple hitPoint;
|
Tuple hitPoint;
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ Tuple World::shadeHit(Computation comps, uint32_t depthCount)
|
|||||||
Tuple reflected = this->reflectColour(comps, depthCount);
|
Tuple reflected = this->reflectColour(comps, depthCount);
|
||||||
Tuple refracted = this->refractedColour(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;
|
return surface + reflected + refracted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ int main()
|
|||||||
Sphere glassBall = Sphere();
|
Sphere glassBall = Sphere();
|
||||||
glassBall.material.shininess = 300;
|
glassBall.material.shininess = 300;
|
||||||
glassBall.material.transparency = 1;
|
glassBall.material.transparency = 1;
|
||||||
|
glassBall.material.reflective = 1;
|
||||||
glassBall.material.refractiveIndex = 1.52;
|
glassBall.material.refractiveIndex = 1.52;
|
||||||
glassBall.material.diffuse = 0.1;
|
glassBall.material.diffuse = 0.1;
|
||||||
w.addObject(&glassBall);
|
w.addObject(&glassBall);
|
||||||
@@ -45,6 +46,7 @@ int main()
|
|||||||
airBall.setTransform(scaling(0.5, 0.5, 0.5));
|
airBall.setTransform(scaling(0.5, 0.5, 0.5));
|
||||||
airBall.material.shininess = 300;
|
airBall.material.shininess = 300;
|
||||||
airBall.material.transparency = 1;
|
airBall.material.transparency = 1;
|
||||||
|
airBall.material.reflective = 1;
|
||||||
airBall.material.refractiveIndex = 1.0009;
|
airBall.material.refractiveIndex = 1.0009;
|
||||||
airBall.material.diffuse = 0.1;
|
airBall.material.diffuse = 0.1;
|
||||||
w.addObject(&airBall);
|
w.addObject(&airBall);
|
||||||
@@ -54,7 +56,7 @@ int main()
|
|||||||
w.addLight(&light);
|
w.addLight(&light);
|
||||||
|
|
||||||
/* Set the camera */
|
/* 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),
|
camera.setTransform(viewTransform(Point(0, 2.5, 0),
|
||||||
Point(0, 0, 0),
|
Point(0, 0, 0),
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ int main()
|
|||||||
w.addLight(&light);
|
w.addLight(&light);
|
||||||
|
|
||||||
/* Set the camera */
|
/* 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),
|
camera.setTransform(viewTransform(Point(-2.6, 1.5, -3.9),
|
||||||
Point(-0.6, 1, -0.8),
|
Point(-0.6, 1, -0.8),
|
||||||
Vector(0, 1, 0)));
|
Vector(0, 1, 0)));
|
||||||
|
|||||||
@@ -254,3 +254,52 @@ TEST(IntersectTest, The_under_point_is_offset_below_the_surface)
|
|||||||
ASSERT_TRUE(double_equal(comps.underHitPoint.z, getEpsilon() / 2));
|
ASSERT_TRUE(double_equal(comps.underHitPoint.z, getEpsilon() / 2));
|
||||||
ASSERT_LT(comps.hitPoint.z, comps.underHitPoint.z);
|
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);
|
||||||
|
}
|
||||||
@@ -393,3 +393,37 @@ TEST(WorldTest, Shade_hit_with_a_transparent_material)
|
|||||||
|
|
||||||
set_equal_precision(FLT_EPSILON);
|
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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user