raytracer-c/test/module_raytracer/test_camera.c

196 lines
6.6 KiB
C

#include "test_world_utils.h"
#include <camera.h>
#include <canvas.h>
#include <ray.h>
#include <tuples.h>
#include <unity.h>
void setUp(void) {}
void tearDown(void) {}
void test_transformation_matrix_for_default_orientation(void) {
TUPLES_Point from, to;
TUPLES_Vector up;
TUPLES_init_vector(&from, 0, 0, 0);
TUPLES_init_vector(&to, 0, 0, -1);
TUPLES_init_vector(&up, 0, 1, 0);
MATRIX_Matrix *t = CAMERA_view_transform(&from, &to, &up);
MATRIX_Matrix *expected = MATRIX_new_identity(4);
TEST_ASSERT_TRUE(MATRIX_is_equal(expected, t));
MATRIX_delete_all(t, expected);
}
void test_transformation_matrix_when_looking_in_positive_z_direction(void) {
TUPLES_Point from, to;
TUPLES_Vector up;
TUPLES_init_vector(&from, 0, 0, 0);
TUPLES_init_vector(&to, 0, 0, 1);
TUPLES_init_vector(&up, 0, 1, 0);
MATRIX_Matrix *t = CAMERA_view_transform(&from, &to, &up);
MATRIX_Matrix *expected = MATRIX_new_scaling(-1, 1, -1);
TEST_ASSERT_TRUE(MATRIX_is_equal(expected, t));
MATRIX_delete_all(t, expected);
}
void test_transformation_moves_the_world(void) {
TUPLES_Point from, to;
TUPLES_Vector up;
TUPLES_init_vector(&from, 0, 0, 8);
TUPLES_init_vector(&to, 0, 0, 0);
TUPLES_init_vector(&up, 0, 1, 0);
MATRIX_Matrix *t = CAMERA_view_transform(&from, &to, &up);
MATRIX_Matrix *expected = MATRIX_new_translation(0, 0, -8);
TEST_ASSERT_TRUE(MATRIX_is_equal(expected, t));
MATRIX_delete_all(t, expected);
}
void test_arbitrary_view_transformation(void) {
TUPLES_Point from, to;
TUPLES_Vector up;
TUPLES_init_vector(&from, 1, 3, 2);
TUPLES_init_vector(&to, 4, -2, 8);
TUPLES_init_vector(&up, 1, 1, 0);
MATRIX_Matrix *t = CAMERA_view_transform(&from, &to, &up);
MATRIX_Matrix *expected = MATRIX_new(4, 4);
MATRIX_fill(expected, -0.50709, 0.50709, 0.67612, -2.36643, 0.76772, 0.60609, 0.12122, -2.82842, -0.35857, 0.59761, -0.71714, 0.0, 0.0, 0.0, 0.0, 1.0);
TEST_ASSERT_TRUE(MATRIX_is_equal(expected, t));
MATRIX_delete_all(t, expected);
}
void test_construct_a_camera(void) {
CAMERA_Camera *camera = CAMERA_new(160, 120, M_PI_2);
TEST_ASSERT_NOT_NULL(camera);
TEST_ASSERT_EQUAL_DOUBLE(160, camera->hsize);
TEST_ASSERT_EQUAL_DOUBLE(120, camera->vsize);
TEST_ASSERT_EQUAL_DOUBLE(M_PI_2, camera->field_of_view);
MATRIX_Matrix *expected = MATRIX_new_identity(4);
TEST_ASSERT_TRUE(MATRIX_is_equal(expected, camera->transform));
CAMERA_delete(camera);
MATRIX_delete(expected);
}
void test_pixel_size_for_horizontal_canvas(void) {
CAMERA_Camera *camera = CAMERA_new(200, 125, M_PI_2);
TEST_ASSERT_EQUAL_DOUBLE(0.01, camera->pixel_size);
CAMERA_delete(camera);
}
void test_pixel_size_for_vertical_canvas(void) {
CAMERA_Camera *camera = CAMERA_new(125, 200, M_PI_2);
TEST_ASSERT_EQUAL_DOUBLE(0.01, camera->pixel_size);
CAMERA_delete(camera);
}
void test_get_ray_through_center_of_canvas(void) {
CAMERA_Camera *camera = CAMERA_new(201, 101, M_PI_2);
RAY_Ray r;
CAMERA_ray_for_pixel(&r, camera, 100, 50);
TUPLES_Point origin_expected;
TUPLES_Vector direction_expected;
TUPLES_init_point(&origin_expected, 0, 0, 0);
TUPLES_init_vector(&direction_expected, 0, 0, -1);
TEST_ASSERT_TRUE(TUPLES_is_equal(&origin_expected, &r.origin));
TEST_ASSERT_TRUE(TUPLES_is_equal(&direction_expected, &r.direction));
CAMERA_delete(camera);
}
void test_get_ray_through_corner_of_canvas(void) {
CAMERA_Camera *camera = CAMERA_new(201, 101, M_PI_2);
RAY_Ray r;
CAMERA_ray_for_pixel(&r, camera, 0, 0);
TUPLES_Point origin_expected;
TUPLES_Vector direction_expected;
TUPLES_init_point(&origin_expected, 0, 0, 0);
TUPLES_init_vector(&direction_expected, 0.66519, 0.33259, -0.66851);
TEST_ASSERT_TRUE(TUPLES_is_equal(&origin_expected, &r.origin));
TEST_ASSERT_TRUE(TUPLES_is_equal(&direction_expected, &r.direction));
CAMERA_delete(camera);
}
void test_get_ray_when_camera_is_transformed(void) {
CAMERA_Camera *camera = CAMERA_new(201, 101, M_PI_2);
MATRIX_Matrix *rotation = MATRIX_new_rotation_y(M_PI_4);
MATRIX_Matrix *translation = MATRIX_new_translation(0, -2, 5);
MATRIX_Matrix *transform = MATRIX_multiply(rotation, translation);
CAMERA_set_transform(camera, transform);
RAY_Ray r;
CAMERA_ray_for_pixel(&r, camera, 100, 50);
TUPLES_Point origin_expected;
TUPLES_Vector direction_expected;
TUPLES_init_point(&origin_expected, 0, 2, -5);
TUPLES_init_vector(&direction_expected, sqrt(2) / 2.0, 0, -sqrt(2) / 2.0);
TEST_ASSERT_TRUE(TUPLES_is_equal(&origin_expected, &r.origin));
TEST_ASSERT_TRUE(TUPLES_is_equal(&direction_expected, &r.direction));
MATRIX_delete_all(rotation, translation, transform);
CAMERA_delete(camera);
}
void test_redering_world_with_a_camera(void) {
WORLD_World *world = construct_test_world();
CAMERA_Camera *camera = CAMERA_new(11, 11, M_PI_2);
TUPLES_Point from, to;
TUPLES_Vector up;
TUPLES_init_point(&from, 0, 0, -5);
TUPLES_init_point(&to, 0, 0, 0);
TUPLES_init_vector(&up, 0, 1, 0);
MATRIX_Matrix *transform = CAMERA_view_transform(&from, &to, &up);
CAMERA_set_transform(camera, transform);
MATRIX_delete(transform);
CANVAS_Canvas *canvas = CAMERA_render(camera, world);
TUPLES_Color *c = CANVAS_read_pixel(canvas, 5, 5);
TUPLES_Color expected;
TUPLES_init_color(&expected, 0.38066, 0.47583, 0.2855);
TEST_ASSERT_TRUE(TUPLES_is_equal(&expected, c));
TUPLES_delete(c);
destruct_test_world(world);
CAMERA_delete(camera);
CANVAS_delete(canvas);
}
void test_load_camera_from_yaml(void) {
char data[] = "- add: camera\n"
" width: 400\n"
" height: 200\n"
" field-of-view: 1.152\n"
" from: [-2.6, 1.5, -3.9]\n"
" to: [-0.6, 1, -0.8]\n"
" up: [0, 1, 0]\n";
CAMERA_Camera *result = CAMERA_parse_camera(data);
TEST_ASSERT_NOT_NULL(result);
//TODO calculate & compare the expected transformation matrix for this test
TEST_ASSERT_EQUAL(400, result->hsize);
TEST_ASSERT_EQUAL(200, result->vsize);
TEST_ASSERT_EQUAL_DOUBLE(1.152, result->field_of_view);
CAMERA_delete(result);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_transformation_matrix_for_default_orientation);
RUN_TEST(test_transformation_matrix_when_looking_in_positive_z_direction);
RUN_TEST(test_transformation_moves_the_world);
RUN_TEST(test_arbitrary_view_transformation);
RUN_TEST(test_construct_a_camera);
RUN_TEST(test_pixel_size_for_horizontal_canvas);
RUN_TEST(test_pixel_size_for_vertical_canvas);
RUN_TEST(test_get_ray_through_center_of_canvas);
RUN_TEST(test_get_ray_through_corner_of_canvas);
RUN_TEST(test_get_ray_when_camera_is_transformed);
RUN_TEST(test_load_camera_from_yaml);
UNITY_END();
}