123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429 |
- /*
- * DoRayMe - a quick and dirty Raytracer
- * World unit tests
- *
- * Created by Manoël Trapier
- * Copyright (c) 2020 986-Studio.
- *
- */
- #include <world.h>
- #include <light.h>
- #include <sphere.h>
- #include <material.h>
- #include <transformation.h>
- #include <worldbuilder.h>
- #include <testpattern.h>
- #include <math.h>
- #include <gtest/gtest.h>
- #include <plane.h>
- TEST(WorldTest, Creating_a_world)
- {
- World w;
- ASSERT_EQ(w.lightCount, 0);
- ASSERT_EQ(w.objectCount, 0);
- }
- TEST(WorldTest, The_default_world)
- {
- World w = DefaultWorld();
- Light l = Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1));
- Sphere s1 = Sphere();
- Sphere s2 = Sphere();
- Material s1Mat = Material();
- s1Mat.colour = Colour(0.8, 1.0, 0.6);
- s1Mat.diffuse = 0.7;
- s1Mat.specular = 0.2;
- s1.setMaterial(s1Mat);
- s2.setTransform(scaling(0.5, 0.5,0.5));
- ASSERT_TRUE(w.lightIsIn(l));
- ASSERT_TRUE(w.objectIsIn(s1));
- ASSERT_TRUE(w.objectIsIn(s2));
- };
- TEST(WorldTest, Intersect_a_world_with_a_ray)
- {
- World w = DefaultWorld();
- Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
- Intersect xs = w.intersect(r);
- ASSERT_EQ(xs.count(), 4);
- ASSERT_EQ(xs[0].t, 4);
- ASSERT_EQ(xs[1].t, 4.5);
- ASSERT_EQ(xs[2].t, 5.5);
- ASSERT_EQ(xs[3].t, 6);
- }
- TEST(WorldTest, Shading_an_intersection)
- {
- World w = DefaultWorld();
- Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
- Shape *s = w.getObject(0);
- Intersection i = Intersection(4, s);
- Computation comps = i.prepareComputation(r);
- Tuple c = w.shadeHit(comps);
- /* Temporary lower the precision */
- set_equal_precision(0.00001);
- ASSERT_EQ(c, Colour(0.38066, 0.47583, 0.2855));
- set_equal_precision(FLT_EPSILON);
- }
- TEST(WorldTest, The_when_ray_miss)
- {
- World w = DefaultWorld();
- Ray r = Ray(Point(0, 0, -5), Vector(0, 1, 0));
- Tuple c = w.colourAt(r);
- ASSERT_EQ(c, Colour(0, 0, 0));
- }
- TEST(WorldTest, The_when_ray_hit)
- {
- World w = DefaultWorld();
- Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
- Tuple c = w.colourAt(r);
- /* Temporary lower the precision */
- set_equal_precision(0.00001);
- ASSERT_EQ(c, Colour(0.38066, 0.47583, 0.2855));
- set_equal_precision(FLT_EPSILON);
- }
- TEST(WorldTest, The_colour_with_an_intersection_behind_the_ray)
- {
- World w = DefaultWorld();
- Shape *outer = w.getObject(0);
- outer->material.ambient = 1;
- Shape *inner = w.getObject(1);
- inner->material.ambient = 1;
- Ray r = Ray(Point(0, 0, 0.75), Vector(0, 0, -1));
- Tuple c = w.colourAt(r);
- ASSERT_EQ(c, inner->material.colour);
- }
- TEST(WorldTest, There_is_no_shadow_when_nothing_is_collinear_with_point_and_light)
- {
- World w = DefaultWorld();
- Tuple p = Point(0, 10, 0);
- ASSERT_FALSE(w.isShadowed(p));
- }
- TEST(WorldTest, The_shadow_when_an_object_is_between_the_point_and_the_light)
- {
- World w = DefaultWorld();
- Tuple p = Point(10, -10, 10);
- ASSERT_TRUE(w.isShadowed(p));
- }
- TEST(WorldTest, There_is_no_shadow_whne_an_object_is_behing_the_light)
- {
- World w = DefaultWorld();
- Tuple p = Point(-20, 20, -20);
- ASSERT_FALSE(w.isShadowed(p));
- }
- TEST(WorldTest, There_is_no_shadow_when_an_object_is_behing_the_point)
- {
- World w = DefaultWorld();
- Tuple p = Point(-2, 2, -2);
- ASSERT_FALSE(w.isShadowed(p));
- }
- TEST(WorldTest, Shade_hit_is_given_an_intersection_in_shadow)
- {
- World w = World();
- Light l = Light(POINT_LIGHT, Point(0, 0, -10), Colour(1, 1, 1));
- w.addLight(&l);
- Sphere s1 = Sphere();
- w.addObject(&s1);
- Sphere s2 = Sphere();
- s2.setTransform(translation(0, 0, 10));
- w.addObject(&s2);
- Ray r = Ray(Point(0, 0, 5), Vector(0, 0, 1));
- Intersection i = Intersection(4, &s2);
- Computation comps = i.prepareComputation(r);
- Tuple c = w.shadeHit(comps);
- ASSERT_EQ(c, Colour(0.1, 0.1, 0.1));
- };
- TEST(WorldTest, The_reflected_colour_for_a_non_reflective_material)
- {
- World w = DefaultWorld();
- Ray r = Ray(Point(0, 0, 0), Vector(0, 0, 1));
- Shape *shape = w.getObject(1); /* The second object */
- shape->material.ambient = 1; /* We use this to get a predictable colour */
- Intersection i = Intersection(1, shape);
- Computation comps = i.prepareComputation(r);
- Colour colour = w.reflectColour(comps);
- ASSERT_EQ(colour, Colour(0, 0, 0));
- }
- TEST(WorldTest, The_reflected_colour_for_a_reflective_material)
- {
- World w = DefaultWorld();
- Plane shape = Plane();
- shape.material.reflective = 0.5;
- shape.setTransform(translation(0, -1, 0));
- w.addObject(&shape);
- Ray r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2)/2, sqrt(2)/2));
- Intersection i = Intersection(sqrt(2), &shape);
- Computation comps = i.prepareComputation(r);
- Colour colour = w.reflectColour(comps);
- /* Temporary lower the precision */
- set_equal_precision(0.00002);
- ASSERT_EQ(colour, Colour(0.19032, 0.2379, 0.14274));
- set_equal_precision(FLT_EPSILON);
- }
- TEST(WorldTest, Shade_hit_with_a_reflective_material)
- {
- World w = DefaultWorld();
- Plane shape = Plane();
- shape.material.reflective = 0.5;
- shape.setTransform(translation(0, -1, 0));
- w.addObject(&shape);
- Ray r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2)/2, sqrt(2)/2));
- Intersection i = Intersection(sqrt(2), &shape);
- Computation comps = i.prepareComputation(r);
- Tuple colour = w.shadeHit(comps);
- /* Temporary lower the precision */
- set_equal_precision(0.00005);
- ASSERT_EQ(colour, Colour(0.87677, 0.92436, 0.82918));
- set_equal_precision(FLT_EPSILON);
- }
- TEST(WorldTest, Colour_at_with_mutually_reflective_surfaces)
- {
- World w = World();
- Light l = Light(POINT_LIGHT, Point(0, 0, 0), Colour(1, 1, 1));
- w.addLight(&l);
- Plane lower = Plane();
- lower.material.reflective = 1;
- lower.setTransform(translation(0, -1, 0));
- Plane higher = Plane();
- higher.material.reflective = 1;
- higher.setTransform(translation(0, 1, 0));
- w.addObject(&lower);
- w.addObject(&higher);
- Ray r = Ray(Point(0, 0, 0), Vector(0, 1, 0));
- /* It should just exit, we don't care about the actual colour */
- w.colourAt(r);
- SUCCEED();
- }
- TEST(WorldTest, The_reflected_colour_at_the_maximum_recursion_depth)
- {
- World w = DefaultWorld();
- Plane shape = Plane();
- shape.material.reflective = 0.5;
- shape.setTransform(translation(0, -1, 0));
- w.addObject(&shape);
- Ray r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2)/2, sqrt(2)/2));
- Intersection i = Intersection(sqrt(2), &shape);
- Computation comps = i.prepareComputation(r);
- Tuple colour = w.reflectColour(comps, 0);
- /* Temporary lower the precision */
- ASSERT_EQ(colour, Colour(0, 0, 0));
- }
- TEST(WorldTest, The_refracted_colour_with_an_opaque_surface)
- {
- World w = DefaultWorld();
- Shape *shape = w.getObject(0);
- Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
- Intersect xs = Intersect();
- xs.add(Intersection(4, shape));
- xs.add(Intersection(6, shape));
- Computation comps = xs[0].prepareComputation(r, &xs);
- Colour c = w.refractedColour(comps, 5);
- ASSERT_EQ(c, Colour(0, 0, 0));
- }
- TEST(WorldTest, The_refracted_colour_at_the_maximum_recursive_depth)
- {
- World w = DefaultWorld();
- Shape *shape = w.getObject(0);
- shape->material.transparency = 1.0;
- shape->material.refractiveIndex = 1.5;
- Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1));
- Intersect xs = Intersect();
- xs.add(Intersection(4, shape));
- xs.add(Intersection(6, shape));
- Computation comps = xs[0].prepareComputation(r, &xs);
- Colour c = w.refractedColour(comps, 0);
- ASSERT_EQ(c, Colour(0, 0, 0));
- }
- TEST(WorldTest, The_refracted_colour_under_total_internal_reflection)
- {
- World w = DefaultWorld();
- Shape *shape = w.getObject(0);
- shape->material.transparency = 1.0;
- shape->material.refractiveIndex = 1.5;
- 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);
- Colour c = w.refractedColour(comps, 5);
- ASSERT_EQ(c, Colour(0, 0, 0));
- }
- TEST(WorldTest, The_refracted_coloud_with_a_refracted_ray)
- {
- World w = DefaultWorld();
- Shape *A = w.getObject(0);
- A->material.ambient = 1.0;
- A->material.pattern = new TestPattern();
- Shape *B = w.getObject(1);
- B->material.transparency = 1.0;
- B->material.refractiveIndex = 1.5;
- Ray r = Ray(Point(0, 0, 0.1), Vector(0, 1, 0));
- Intersect xs = Intersect();
- xs.add(Intersection(-0.9899, A));
- xs.add(Intersection(-0.4899, B));
- xs.add(Intersection(0.4899, B));
- xs.add(Intersection(0.9899, A));
- Computation comps = xs[2].prepareComputation(r, &xs);
- Colour c = w.refractedColour(comps, 5);
- /* Temporary lower the precision */
- set_equal_precision(0.00005);
- ASSERT_EQ(c, Colour(0, 0.99888, 0.04725));
- set_equal_precision(FLT_EPSILON);
- }
- TEST(WorldTest, Shade_hit_with_a_transparent_material)
- {
- World w = DefaultWorld();
- Plane floor = Plane();
- floor.setTransform(translation(0, -1, 0));
- floor.material.transparency = 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);
- Ray r = Ray(Point(0, 0, -3), Vector(0, -sqrt(2)/2, sqrt(2)/2));
- 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.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);
- }
|