[FEAT] Add Cube support - still issue on the shadow with the glass cube.
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -107,6 +107,7 @@
|
||||
"/home/jbnadal/sources/jb/raytracer_challenge/build/apps/CMakeFiles/chapter_10.dir",
|
||||
"/home/jbnadal/sources/jb/raytracer_challenge/build/apps/CMakeFiles/chapter_11_p1.dir",
|
||||
"/home/jbnadal/sources/jb/raytracer_challenge/build/apps/CMakeFiles/chapter_11_p2.dir",
|
||||
"/home/jbnadal/sources/jb/raytracer_challenge/build/apps/CMakeFiles/chapter_12.dir",
|
||||
"/home/jbnadal/sources/jb/raytracer_challenge/build/tests/CMakeFiles/raytracing_test.dir"
|
||||
]
|
||||
}
|
||||
@@ -27,3 +27,6 @@ target_link_libraries(chapter_11_p1 PRIVATE raytracing gcov OpenMP::OpenMP_CXX)
|
||||
|
||||
add_executable(chapter_11_p2 chapter_11_p2.cpp)
|
||||
target_link_libraries(chapter_11_p2 PRIVATE raytracing OpenMP::OpenMP_CXX)
|
||||
|
||||
add_executable(chapter_12 chapter_12.cpp)
|
||||
target_link_libraries(chapter_12 PRIVATE raytracing OpenMP::OpenMP_CXX)
|
||||
|
||||
273
apps/chapter_12.cpp
Normal file
273
apps/chapter_12.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
/*!
|
||||
* chapter_12.cpp
|
||||
*
|
||||
* Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* @Author: NADAL Jean-Baptiste
|
||||
* @Date: 14/03/2024
|
||||
*
|
||||
*/
|
||||
|
||||
// This is an independent project of an individual developer. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
|
||||
|
||||
// Coordinate came from:
|
||||
// https://github.com/sraaphorst/raytracer-kotlin/blob/main/src/main/kotlin/apps/ch12_world.kt
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
|
||||
#include <raytracing.h>
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
using namespace Raytracer;
|
||||
using namespace std;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
World the_world;
|
||||
Camera the_camera;
|
||||
Canvas the_canvas;
|
||||
|
||||
Cube *the_floor_ceiling, *the_walls, *the_table_top, *the_leg1, *the_leg2, *the_leg3, *the_leg4;
|
||||
Cube *the_glass_cube, *the_little_cube1, *the_little_cube2, *the_little_cube3, *the_little_cube4, *the_little_cube5;
|
||||
Cube *the_frame1, *the_frame2, *the_frame3, *the_frame, *the_mirror;
|
||||
|
||||
chrono::time_point<chrono::high_resolution_clock> the_start, the_end;
|
||||
|
||||
printf("Chapter 12 example.\n");
|
||||
|
||||
// Floor Ceiling
|
||||
the_floor_ceiling = new Cube();
|
||||
the_floor_ceiling->set_transform(Matrix::scaling(20, 7, 20) *
|
||||
Matrix::translation(0, 1, 0));
|
||||
Material &the_floor_material = the_floor_ceiling->material();
|
||||
the_floor_material.set_pattern(new CheckersPattern(Color::Black(), Color(0.25, 0.25, 0.25)));
|
||||
the_floor_material.pattern()->set_transform(Matrix::scaling(0.07, 0.07, 0.07));
|
||||
the_floor_material.set_ambient(0.25);
|
||||
the_floor_material.set_diffuse(0.7);
|
||||
the_floor_material.set_specular(0.9);
|
||||
the_floor_material.set_shininess(300);
|
||||
the_floor_material.set_reflective(0.1);
|
||||
the_world.add_object(the_floor_ceiling);
|
||||
|
||||
// Walls
|
||||
the_walls = new Cube();
|
||||
the_walls->set_transform(Matrix::scaling(10, 10, 10));
|
||||
Material &the_wall_material = the_walls->material();
|
||||
the_wall_material.set_pattern(new CheckersPattern(Color(0.4863, 0.3765, 0.2941), Color(0.3725, 0.2902, 0.2275)));
|
||||
the_wall_material.pattern()->set_transform(Matrix::scaling(0.05, 20, 0.05));
|
||||
the_wall_material.set_ambient(0.1);
|
||||
the_wall_material.set_diffuse(0.7);
|
||||
the_wall_material.set_specular(0.9);
|
||||
the_wall_material.set_shininess(300);
|
||||
the_wall_material.set_reflective(0.05);
|
||||
the_world.add_object(the_walls);
|
||||
|
||||
// Table Color
|
||||
Color the_table_color = Color(0.5529, 0.4235, 0.3255);
|
||||
|
||||
// Table Top
|
||||
the_table_top = new Cube();
|
||||
the_table_top->set_transform(Matrix::translation(0, 3.1, 0) *
|
||||
Matrix::scaling(3, 0.1, 2));
|
||||
Material &the_table_top_material = the_table_top->material();
|
||||
the_table_top_material.set_pattern(new StripePattern(the_table_color, Color(0.6588, 0.5098, 0.4000)));
|
||||
the_table_top_material.pattern()->set_transform(Matrix::scaling(0.05, 0.05, 0.05) *
|
||||
Matrix::rotation_y(0.1));
|
||||
the_table_top_material.set_ambient(0.1);
|
||||
the_table_top_material.set_diffuse(0.7);
|
||||
the_table_top_material.set_specular(0.9);
|
||||
the_table_top_material.set_shininess(300);
|
||||
the_table_top_material.set_reflective(0.2);
|
||||
the_world.add_object(the_table_top);
|
||||
|
||||
// Leg Material
|
||||
Material the_leg_material;
|
||||
the_leg_material.set_color(the_table_color);
|
||||
the_leg_material.set_ambient(0.2);
|
||||
the_leg_material.set_diffuse(0.7);
|
||||
|
||||
// Leg1
|
||||
the_leg1 = new Cube();
|
||||
the_leg1->set_transform(Matrix::translation(2.7, 1.5, -1.7) *
|
||||
Matrix::scaling(0.1, 1.5, 0.1));
|
||||
the_leg1->set_material(the_leg_material);
|
||||
the_world.add_object(the_leg1);
|
||||
|
||||
// Leg2
|
||||
the_leg2 = new Cube();
|
||||
the_leg2->set_transform(Matrix::translation(2.7, 1.5, 1.7) *
|
||||
Matrix::scaling(0.1, 1.5, 0.1));
|
||||
the_leg2->set_material(the_leg_material);
|
||||
the_world.add_object(the_leg2);
|
||||
|
||||
// Leg3
|
||||
the_leg3 = new Cube();
|
||||
the_leg3->set_transform(Matrix::translation(-2.7, 1.5, -1.7) *
|
||||
Matrix::scaling(0.1, 1.5, 0.1));
|
||||
the_leg3->set_material(the_leg_material);
|
||||
the_world.add_object(the_leg3);
|
||||
|
||||
// Leg4
|
||||
the_leg4 = new Cube();
|
||||
the_leg4->set_transform(Matrix::translation(-2.7, 1.5, 1.7) *
|
||||
Matrix::scaling(0.1, 1.5, 0.1));
|
||||
the_leg4->set_material(the_leg_material);
|
||||
the_world.add_object(the_leg4);
|
||||
|
||||
// Glass Cube
|
||||
the_glass_cube = new Cube();
|
||||
the_glass_cube->set_transform(Matrix::translation(0, 3.45001, 0) *
|
||||
Matrix::rotation_y(0.2) *
|
||||
Matrix::scaling(0.25, 0.25, 0.25));
|
||||
Material &the_glass_cube_material = the_glass_cube->material();
|
||||
the_glass_cube_material.set_color(Color(1, 1, 0.8));
|
||||
the_glass_cube_material.set_ambient(0.0);
|
||||
the_glass_cube_material.set_diffuse(0.3);
|
||||
the_glass_cube_material.set_specular(0.9);
|
||||
the_glass_cube_material.set_shininess(300);
|
||||
the_glass_cube_material.set_reflective(0.7);
|
||||
the_glass_cube_material.set_transparency(0.7);
|
||||
the_glass_cube_material.set_refractive_index(1.5);
|
||||
the_world.add_object(the_glass_cube);
|
||||
|
||||
// Little Cube 1
|
||||
the_little_cube1 = new Cube();
|
||||
the_little_cube1->set_transform(Matrix::translation(1, 3.35, -0.9) *
|
||||
Matrix::rotation_y(-0.4) *
|
||||
Matrix::scaling(0.15, 0.15, 0.15));
|
||||
Material &the_little_cube1_material = the_little_cube1->material();
|
||||
the_little_cube1_material.set_color(Color(1, 0.5, 0.5));
|
||||
the_little_cube1_material.set_reflective(0.6);
|
||||
the_little_cube1_material.set_diffuse(0.4);
|
||||
the_world.add_object(the_little_cube1);
|
||||
|
||||
// Little Cube 2
|
||||
the_little_cube2 = new Cube();
|
||||
the_little_cube2->set_transform(Matrix::translation(-1.5, 3.27, 0.3) *
|
||||
Matrix::rotation_y(0.4) *
|
||||
Matrix::scaling(0.15, 0.07, 0.15));
|
||||
Material &the_little_cube2_material = the_little_cube2->material();
|
||||
the_little_cube2_material.set_color(Color(1, 1, 0.5));
|
||||
the_world.add_object(the_little_cube2);
|
||||
|
||||
// Little Cube 3
|
||||
the_little_cube3 = new Cube();
|
||||
the_little_cube3->set_transform(Matrix::translation(0, 3.25, 1) *
|
||||
Matrix::rotation_y(0.4) *
|
||||
Matrix::scaling(0.2, 0.05, 0.05));
|
||||
Material &the_little_cube3_material = the_little_cube3->material();
|
||||
the_little_cube3_material.set_color(Color(0.5, 1, 0.5));
|
||||
the_world.add_object(the_little_cube3);
|
||||
|
||||
// Little Cube 4
|
||||
the_little_cube4 = new Cube();
|
||||
the_little_cube4->set_transform(Matrix::translation(-0.6, 3.4, -1) *
|
||||
Matrix::rotation_y(0.8) *
|
||||
Matrix::scaling(0.05, 0.2, 0.05));
|
||||
Material &the_little_cube4_material = the_little_cube4->material();
|
||||
the_little_cube4_material.set_color(Color(0.5, 0.5, 1));
|
||||
the_world.add_object(the_little_cube4);
|
||||
|
||||
// Little Cube 5
|
||||
the_little_cube5 = new Cube();
|
||||
the_little_cube5->set_transform(Matrix::translation(2, 3.4, 1) *
|
||||
Matrix::rotation_y(0.8) *
|
||||
Matrix::scaling(0.05, 0.2, 0.05));
|
||||
Material &the_little_cube5_material = the_little_cube5->material();
|
||||
the_little_cube5_material.set_color(Color(0.5, 1, 1));
|
||||
the_world.add_object(the_little_cube5);
|
||||
|
||||
// Frame 1
|
||||
the_frame1 = new Cube();
|
||||
the_frame1->set_transform(Matrix::translation(-10, 4, 1) *
|
||||
Matrix::scaling(0.05, 1, 1));
|
||||
Material &the_frame1_material = the_frame1->material();
|
||||
the_frame1_material.set_color(Color(0.7098, 0.2471, 0.2196));
|
||||
the_frame1_material.set_diffuse(0.6);
|
||||
the_world.add_object(the_frame1);
|
||||
|
||||
// Frame 2
|
||||
the_frame2 = new Cube();
|
||||
the_frame2->set_transform(Matrix::translation(-10, 3.4, 2.7) *
|
||||
Matrix::scaling(0.05, 0.4, 0.4));
|
||||
Material &the_frame2_material = the_frame2->material();
|
||||
the_frame2_material.set_color(Color(0.2667, 0.2706, 0.6902));
|
||||
the_frame2_material.set_diffuse(0.6);
|
||||
the_world.add_object(the_frame2);
|
||||
|
||||
// Frame 3
|
||||
the_frame3 = new Cube();
|
||||
the_frame3->set_transform(Matrix::translation(-10, 4.6, 2.7) *
|
||||
Matrix::scaling(0.05, 0.4, 0.4));
|
||||
Material &the_frame3_material = the_frame3->material();
|
||||
the_frame3_material.set_color(Color(0.3098, 0.5961, 0.3098));
|
||||
the_frame3_material.set_diffuse(0.6);
|
||||
the_world.add_object(the_frame3);
|
||||
|
||||
// Frame
|
||||
the_frame = new Cube();
|
||||
the_frame->set_transform(Matrix::translation(-2, 3.5, 9.95) *
|
||||
Matrix::scaling(5, 1.5, 0.05));
|
||||
Material &the_frame_material = the_frame->material();
|
||||
the_frame_material.set_color(Color(0.3882, 0.2627, 0.1882));
|
||||
the_frame_material.set_diffuse(0.7);
|
||||
the_world.add_object(the_frame);
|
||||
|
||||
// Mirror
|
||||
the_mirror = new Cube();
|
||||
the_mirror->set_transform(Matrix::translation(-2, 3.5, 9.95) *
|
||||
Matrix::scaling(4.8, 1.4, 0.06));
|
||||
Material &the_mirror_material = the_mirror->material();
|
||||
the_mirror_material.set_color(Color::Black());
|
||||
the_mirror_material.set_ambient(0.0);
|
||||
the_mirror_material.set_diffuse(0.0);
|
||||
the_mirror_material.set_specular(0.0);
|
||||
the_mirror_material.set_shininess(300);
|
||||
the_mirror_material.set_reflective(1.0);
|
||||
the_world.add_object(the_mirror);
|
||||
|
||||
// The Light source is white, shining from above and to the left
|
||||
the_world.set_light(PointLight(Tuple::Point(0, 6.9, -5), Color(1, 1, 0.9)));
|
||||
|
||||
// Configure the camera.
|
||||
// the_camera = Camera(100, 50, 0.7805);
|
||||
// the_camera = Camera(320, 200, 0.7805);
|
||||
// the_camera = Camera(640, 480, 0.7805);
|
||||
the_camera = Camera(960, 480, 0.7805);
|
||||
// the_camera = Camera(2400, 1200, 0.7805);
|
||||
|
||||
the_camera.set_transform(
|
||||
Matrix::view_transform(Tuple::Point(8, 6, -8), Tuple::Point(0, 3, 0), Tuple::Vector(0, 1, 0)));
|
||||
|
||||
the_start = chrono::high_resolution_clock::now();
|
||||
the_camera.show_progress_bar();
|
||||
the_canvas = the_camera.render(the_world);
|
||||
the_end = chrono::high_resolution_clock::now();
|
||||
|
||||
the_canvas.save_to_file("chapter_12.ppm");
|
||||
|
||||
chrono::duration<double> the_elapsed_time = the_end - the_start;
|
||||
printf("Execution Time: %f secondes\n", the_elapsed_time.count());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -41,7 +41,7 @@ using namespace Raytracer;
|
||||
|
||||
Intersections Cube::local_intersect(const Ray &a_ray)
|
||||
{
|
||||
double the_tmin, the_max;
|
||||
double the_tmin, the_tmax;
|
||||
Intersections the_intersections;
|
||||
|
||||
const auto [the_xtmin, the_xtmax] = check_axis(a_ray.origin().x(), a_ray.direction().x());
|
||||
@@ -49,10 +49,15 @@ Intersections Cube::local_intersect(const Ray &a_ray)
|
||||
const auto [the_ztmin, the_ztmax] = check_axis(a_ray.origin().z(), a_ray.direction().z());
|
||||
|
||||
the_tmin = std::max({the_xtmin, the_ytmin, the_ztmin});
|
||||
the_max = std::min({the_xtmax, the_ytmax, the_ztmax});
|
||||
the_tmax = std::min({the_xtmax, the_ytmax, the_ztmax});
|
||||
|
||||
if (the_tmin > the_tmax)
|
||||
{
|
||||
return the_intersections;
|
||||
}
|
||||
|
||||
the_intersections.add(Intersection(the_tmin, this));
|
||||
the_intersections.add(Intersection(the_max, this));
|
||||
the_intersections.add(Intersection(the_tmax, this));
|
||||
|
||||
return the_intersections;
|
||||
}
|
||||
@@ -61,7 +66,18 @@ Intersections Cube::local_intersect(const Ray &a_ray)
|
||||
|
||||
Tuple Cube::local_normal_at(const Tuple &a_local_point) const
|
||||
{
|
||||
return Tuple::Vector(0, 1, 0);
|
||||
double the_maxc = std::max({std::abs(a_local_point.x()), std::abs(a_local_point.y()), std::abs(a_local_point.z())});
|
||||
|
||||
if (double_equal(the_maxc, std::abs(a_local_point.x())))
|
||||
{
|
||||
return Tuple::Vector(a_local_point.x(), 0, 0);
|
||||
}
|
||||
else if (double_equal(the_maxc, std::abs(a_local_point.y())))
|
||||
{
|
||||
return Tuple::Vector(0, a_local_point.y(), 0);
|
||||
}
|
||||
|
||||
return Tuple::Vector(0, 0, a_local_point.z());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -33,7 +33,7 @@ using namespace Raytracer;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class CubeTest
|
||||
class CubeTestIntersect
|
||||
{
|
||||
public:
|
||||
Tuple origin;
|
||||
@@ -44,6 +44,15 @@ public:
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class CubeTestNormal
|
||||
{
|
||||
public:
|
||||
Tuple point;
|
||||
Tuple normal;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("A Ray intersects a cube", "[features/cubes.feature]")
|
||||
{
|
||||
// | | origin | direction | t1 | t2 |
|
||||
@@ -54,7 +63,7 @@ SCENARIO("A Ray intersects a cube", "[features/cubes.feature]")
|
||||
// | +z | point(0.5, 0, 5) | vector( 0, 0,-1) | 4 | 6 |
|
||||
// | -z | point(0.5, 0, -5) | vector( 0, 0, 1) | 4 | 6 |
|
||||
// | inside | point(0, 0.5, 0) | vector( 0, 0, 1) | -1 | -1 |
|
||||
CubeTest the_test[7] = {
|
||||
CubeTestIntersect the_test[] = {
|
||||
{ Tuple::Point(5.0, 0.5, 0.0), Tuple::Vector(-1, 0, 0), 4, 6},
|
||||
{Tuple::Point(-5.0, 0.5, 0.0), Tuple::Vector(1, 0, 0), 4, 6},
|
||||
{ Tuple::Point(0.5, 5.0, 0.0), Tuple::Vector(0, -1, 0), 4, 6},
|
||||
@@ -92,3 +101,87 @@ SCENARIO("A Ray intersects a cube", "[features/cubes.feature]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("A Ray misses a cube", "[features/cubes.feature]")
|
||||
{
|
||||
// | point | direction |
|
||||
// | point(-2, 0, 0) | vector(0.2673, 0.5345, 0.8018) |
|
||||
// | point(0, -2, 0) | vector(0.8018, 0.2673, 0.5345) |
|
||||
// | point(0, 0, -2) | vector(0.5345, 0.8018, 0.2673) |
|
||||
// | point(2, 0, 2) | vector(0, 0, -1) |
|
||||
// | point(0, 2, 2) | vector(0, -1, 0) |
|
||||
// | point(2, 2, 0) | vector(-1, 0, 0) |
|
||||
CubeTestIntersect the_test[] = {
|
||||
{Tuple::Point(-2, 0, 0), Tuple::Vector(0.2673, 0.5345, 0.8018), -1, -1},
|
||||
{ Tuple::Point(0, -2, 0), Tuple::Vector(0.8018, 0.2673, 0.5345), -1, -1},
|
||||
{ Tuple::Point(0, 0, -2), Tuple::Vector(0.5345, 0.8018, 0.2673), -1, -1},
|
||||
{ Tuple::Point(2, 0, 2), Tuple::Vector(0, 0, -1), -1, -1},
|
||||
{ Tuple::Point(0, 2, 2), Tuple::Vector(0, -1, 0), -1, -1},
|
||||
{ Tuple::Point(2, 2, 0), Tuple::Vector(-1, 0, 0), -1, -1}
|
||||
};
|
||||
GIVEN("c <- cube()")
|
||||
{
|
||||
Cube c;
|
||||
AND_GIVEN("r <- ray(<origin>, <direction>)")
|
||||
{
|
||||
WHEN("xs <- local_intersect(c,r)")
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
Ray r(the_test[i].origin, the_test[i].direction);
|
||||
Intersections xs = c.local_intersect(r);
|
||||
THEN("xs.count = 0")
|
||||
{
|
||||
REQUIRE(xs.count() == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
SCENARIO("The normal on the surface of a cube", "[features/cubes.feature]")
|
||||
{
|
||||
// | origin | normal |
|
||||
// | point(1, 0.5, -0.8) | vector(1, 0, 0) |
|
||||
// | point(-1, -0.2, 0.9) | vector(-1, 0, 0) |
|
||||
// | point(-0.4, 1, -0.1) | vector(0, 1, 0) |
|
||||
// | point(0.3, -1, -0.7) | vector(0, -1, 0) |
|
||||
// | point(-0.6, 0.3, 1) | vector(0, 0, 1) |
|
||||
// | point(0.4, 0.4, -1) | vector(0, 0, -1) |
|
||||
// | point(1, 1, -1) | vector(1, 0, 0) |
|
||||
// | point(-1,-1, -1) | vector(-1, 0, 0) |
|
||||
CubeTestNormal the_test[] = {
|
||||
{ Tuple::Point(1, 0.5, -0.8), Tuple::Vector(1, 0, 0)},
|
||||
{ Tuple::Point(-1, -0.2, 0.9), Tuple::Vector(-1, 0, 0)},
|
||||
{Tuple::Point(-0.4, 1, -0.1), Tuple::Vector(0, 1, 0)},
|
||||
{ Tuple::Point(0.3, -1, -0.7), Tuple::Vector(0, -1, 0)},
|
||||
{Tuple::Point(-0.6, 0.3, 1), Tuple::Vector(0, 0, 1)},
|
||||
{ Tuple::Point(0.4, 0.4, -1), Tuple::Vector(0, 0, -1)},
|
||||
{ Tuple::Point(1, 1, -1), Tuple::Vector(1, 0, 0)},
|
||||
{ Tuple::Point(-1, -1, -1), Tuple::Vector(-1, 0, 0)}
|
||||
};
|
||||
GIVEN("c <- cube()")
|
||||
{
|
||||
Cube c;
|
||||
AND_GIVEN("p <- <point>)")
|
||||
{
|
||||
WHEN("normal <- local_normal_at(p)")
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Tuple p = the_test[i].point;
|
||||
Tuple normal = c.local_normal_at(p);
|
||||
THEN("normal = <normal>")
|
||||
{
|
||||
REQUIRE(normal == the_test[i].normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user