chapter 9

This commit is contained in:
Zack Buhman 2024-08-09 19:57:21 -05:00
parent e312755e3d
commit cbecc15fb8
23 changed files with 806 additions and 460 deletions

2
.gitignore vendored
View File

@ -12,6 +12,8 @@ test/test_materials
test/test_spheres test/test_spheres
test/test_world test/test_world
test/test_camera test/test_camera
test/test_shapes
test/test_planes
raytracer raytracer
*.ppm *.ppm
*.png *.png

View File

@ -50,11 +50,11 @@ struct ray camera_ray_for_pixel(struct camera * camera, float px, float py)
float world_x = camera->half_width - xoffset; float world_x = camera->half_width - xoffset;
float world_y = camera->half_height - yoffset; float world_y = camera->half_height - yoffset;
struct mat4x4 t_inverse = mat4x4_inverse(&camera->transform); struct mat4x4 t_inverse = mat4x4_inverse(camera->transform);
struct tuple world_point = point(world_x, world_y, -1.0f); struct tuple world_point = point(world_x, world_y, -1.0f);
struct tuple pixel = mat4x4_mul_t(&t_inverse, &world_point); struct tuple pixel = mat4x4_mul_t(t_inverse, world_point);
struct tuple world_origin = point(0.0f, 0.0f, 0.0f); struct tuple world_origin = point(0.0f, 0.0f, 0.0f);
struct tuple origin = mat4x4_mul_t(&t_inverse, &world_origin); struct tuple origin = mat4x4_mul_t(t_inverse, world_origin);
struct tuple direction = tuple_normalize(tuple_sub(pixel, origin)); struct tuple direction = tuple_normalize(tuple_sub(pixel, origin));
return ray(origin, direction); return ray(origin, direction);

View File

@ -1,29 +1,26 @@
#pragma once #pragma once
#include <stdarg.h> #include <stdarg.h>
#include <assert.h>
#include <stdbool.h>
#include "spheres.h"
#include "rays.h"
struct intersection { struct intersection {
float t; float t;
struct sphere const * object; struct shape const * object;
}; };
struct intersection intersection(float t, struct sphere const * const object) #ifndef INTERSECTIONS_MAX
{ #define INTERSECTIONS_MAX 1024
return (struct intersection){ t, object }; #endif
}
#define MAX_INTERSECTIONS 1024
struct intersections { struct intersections {
int count; int count;
struct intersection i[MAX_INTERSECTIONS]; struct intersection i[INTERSECTIONS_MAX];
}; };
struct intersection intersection(float t, struct shape const * const object)
{
return (struct intersection){ t, object };
}
inline static void intersections(struct intersections * intersections, int count, ...) inline static void intersections(struct intersections * intersections, int count, ...)
{ {
va_list ap; va_list ap;
@ -35,113 +32,3 @@ inline static void intersections(struct intersections * intersections, int count
intersections->count = count; intersections->count = count;
} }
inline static void intersect(struct sphere const * const s, struct ray r, struct intersections * intersections)
{
struct mat4x4 m = mat4x4_inverse(&s->transform);
struct ray r2 = ray_transform(r, &m);
struct tuple sphere_to_ray = tuple_sub(r2.origin, point(0.0f, 0.0f, 0.0f));
float a = tuple_dot(r2.direction, r2.direction);
float b = 2 * tuple_dot(r2.direction, sphere_to_ray);
float c = tuple_dot(sphere_to_ray, sphere_to_ray) - 1;
float discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return;
} else {
float root = sqrtf(discriminant);
float t1 = (-b - root) / (2 * a);
float t2 = (-b + root) / (2 * a);
intersections->i[intersections->count++] = intersection(t1, s);
intersections->i[intersections->count++] = intersection(t2, s);
assert(intersections->count < MAX_INTERSECTIONS);
return;
}
}
inline static struct intersection * hit(struct intersections * xs)
{
struct intersection * i = NULL;
for (int n = 0; n < xs->count; n++) {
if (xs->i[n].t >= 0) {
if (i == NULL || i->t > xs->i[n].t)
i = &xs->i[n];
}
}
return i;
}
inline static void intersections_sort(struct intersections * xs)
{
#define left_child(i) (2 * i + 1)
int start = xs->count / 2;
int end = xs->count;
while (end > 1) {
if (start > 0) {
start = start - 1;
} else {
end = end - 1;
struct intersection tmp = xs->i[0];
xs->i[0] = xs->i[end];
xs->i[end] = tmp;
}
int root = start;
while (left_child(root) < end) {
int child = left_child(root);
if (child + 1 < end && xs->i[child].t < xs->i[child+1].t) {
child = child + 1;
}
if (xs->i[root].t < xs->i[child].t) {
struct intersection tmp = xs->i[root];
xs->i[root] = xs->i[child];
xs->i[child] = tmp;
root = child;
} else {
break;
}
}
}
#undef left_child
}
struct computations {
float t;
struct sphere const * object;
struct tuple point;
struct tuple eyev;
struct tuple normalv;
bool inside;
struct tuple over_point;
};
inline static struct computations prepare_computations(struct intersection intersection, struct ray ray)
{
struct tuple point = ray_position(ray, intersection.t);
struct tuple eyev = tuple_neg(ray.direction);
struct tuple normalv = sphere_normal_at(intersection.object, point);
bool inside = false;
if (tuple_dot(normalv, eyev) < 0.0f) {
inside = true;
normalv = tuple_neg(normalv);
}
struct tuple over_point = tuple_add(point, tuple_mul(normalv, epsilon * 100));
return (struct computations){
intersection.t,
intersection.object,
point,
eyev,
normalv,
inside,
over_point
};
}

153
intersections_shapes.h Normal file
View File

@ -0,0 +1,153 @@
#pragma once
#include <assert.h>
#include <stdbool.h>
#include "rays.h"
#include "shapes.h"
#include "intersections.h"
#include "spheres.h"
#include "planes.h"
#ifdef TEST
struct ray intersections_saved_ray;
#endif
inline static void intersect(struct shape const * const s, struct ray r, struct intersections * intersections)
{
struct mat4x4 m = mat4x4_inverse(s->transform);
struct ray local_ray = ray_transform(r, m);
switch (s->type) {
#ifdef TEST
case SHAPE_TEST:
intersections_saved_ray = local_ray;
break;
#endif
case SHAPE_SPHERE:
sphere_intersect(s, local_ray, intersections);
break;
case SHAPE_PLANE:
plane_intersect(s, local_ray, intersections);
break;
default:
assert(false);
break;
}
assert(intersections->count < INTERSECTIONS_MAX);
}
inline static struct intersection * hit(struct intersections * xs)
{
struct intersection * i = NULL;
for (int n = 0; n < xs->count; n++) {
if (xs->i[n].t >= 0) {
if (i == NULL || i->t > xs->i[n].t)
i = &xs->i[n];
}
}
return i;
}
inline static void intersections_sort(struct intersections * xs)
{
#define left_child(i) (2 * i + 1)
int start = xs->count / 2;
int end = xs->count;
while (end > 1) {
if (start > 0) {
start = start - 1;
} else {
end = end - 1;
struct intersection tmp = xs->i[0];
xs->i[0] = xs->i[end];
xs->i[end] = tmp;
}
int root = start;
while (left_child(root) < end) {
int child = left_child(root);
if (child + 1 < end && xs->i[child].t < xs->i[child+1].t) {
child = child + 1;
}
if (xs->i[root].t < xs->i[child].t) {
struct intersection tmp = xs->i[root];
xs->i[root] = xs->i[child];
xs->i[child] = tmp;
root = child;
} else {
break;
}
}
}
#undef left_child
}
struct computations {
float t;
struct shape const * object;
struct tuple point;
struct tuple eyev;
struct tuple normalv;
bool inside;
struct tuple over_point;
};
inline static struct tuple normal_at(struct shape const * const s, struct tuple world_point)
{
struct mat4x4 inv = mat4x4_inverse(s->transform);
struct mat4x4 inv_t = mat4x4_transpose(inv);
struct tuple local_point = mat4x4_mul_t(inv, world_point);
struct tuple local_normal;
switch (s->type) {
#ifdef TEST
case SHAPE_TEST:
local_normal = vector(local_point.x, local_point.y, local_point.z);
break;
#endif
case SHAPE_SPHERE:
local_normal = sphere_normal_at(local_point);
break;
case SHAPE_PLANE:
local_normal = plane_normal_at(local_point);
break;
default:
assert(false);
break;
}
struct tuple world_normal = mat4x4_mul_t(inv_t, local_normal);
world_normal.w = 0.0f;
return tuple_normalize(world_normal);
}
inline static struct computations prepare_computations(struct intersection intersection, struct ray ray)
{
struct tuple point = ray_position(ray, intersection.t);
struct tuple eyev = tuple_neg(ray.direction);
struct tuple normalv = normal_at(intersection.object, point);
bool inside = false;
if (tuple_dot(normalv, eyev) < 0.0f) {
inside = true;
normalv = tuple_neg(normalv);
}
struct tuple over_point = tuple_add(point, tuple_mul(normalv, epsilon * 100));
return (struct computations){
intersection.t,
intersection.object,
point,
eyev,
normalv,
inside,
over_point
};
}

1
math.h
View File

@ -6,6 +6,7 @@
#define sinf __builtin_sinf #define sinf __builtin_sinf
#define powf __builtin_powf #define powf __builtin_powf
#define tanf __builtin_tanf #define tanf __builtin_tanf
#define fabsf __builtin_fabsf
static const float tau = 6.283185307179586f; static const float tau = 6.283185307179586f;
static const float pi = tau / 2.0f; static const float pi = tau / 2.0f;

View File

@ -48,61 +48,61 @@ inline static struct mat2x2 mat2x2(float a1, float a2,
}}; }};
} }
inline static bool mat4x4_equal(struct mat4x4 const * const a, inline static bool mat4x4_equal(struct mat4x4 a,
struct mat4x4 const * const b) struct mat4x4 b)
{ {
return return
float_equal(a->e[0][0], b->e[0][0]) && float_equal(a.e[0][0], b.e[0][0]) &&
float_equal(a->e[0][1], b->e[0][1]) && float_equal(a.e[0][1], b.e[0][1]) &&
float_equal(a->e[0][2], b->e[0][2]) && float_equal(a.e[0][2], b.e[0][2]) &&
float_equal(a->e[0][3], b->e[0][3]) && float_equal(a.e[0][3], b.e[0][3]) &&
float_equal(a->e[1][0], b->e[1][0]) && float_equal(a.e[1][0], b.e[1][0]) &&
float_equal(a->e[1][1], b->e[1][1]) && float_equal(a.e[1][1], b.e[1][1]) &&
float_equal(a->e[1][2], b->e[1][2]) && float_equal(a.e[1][2], b.e[1][2]) &&
float_equal(a->e[1][3], b->e[1][3]) && float_equal(a.e[1][3], b.e[1][3]) &&
float_equal(a->e[2][0], b->e[2][0]) && float_equal(a.e[2][0], b.e[2][0]) &&
float_equal(a->e[2][1], b->e[2][1]) && float_equal(a.e[2][1], b.e[2][1]) &&
float_equal(a->e[2][2], b->e[2][2]) && float_equal(a.e[2][2], b.e[2][2]) &&
float_equal(a->e[2][3], b->e[2][3]) && float_equal(a.e[2][3], b.e[2][3]) &&
float_equal(a->e[3][0], b->e[3][0]) && float_equal(a.e[3][0], b.e[3][0]) &&
float_equal(a->e[3][1], b->e[3][1]) && float_equal(a.e[3][1], b.e[3][1]) &&
float_equal(a->e[3][2], b->e[3][2]) && float_equal(a.e[3][2], b.e[3][2]) &&
float_equal(a->e[3][3], b->e[3][3]); float_equal(a.e[3][3], b.e[3][3]);
} }
inline static bool mat3x3_equal(struct mat3x3 * a, inline static bool mat3x3_equal(struct mat3x3 a,
struct mat3x3 * b) struct mat3x3 b)
{ {
return return
float_equal(a->e[0][0], b->e[0][0]) && float_equal(a.e[0][0], b.e[0][0]) &&
float_equal(a->e[0][1], b->e[0][1]) && float_equal(a.e[0][1], b.e[0][1]) &&
float_equal(a->e[0][2], b->e[0][2]) && float_equal(a.e[0][2], b.e[0][2]) &&
float_equal(a->e[1][0], b->e[1][0]) && float_equal(a.e[1][0], b.e[1][0]) &&
float_equal(a->e[1][1], b->e[1][1]) && float_equal(a.e[1][1], b.e[1][1]) &&
float_equal(a->e[1][2], b->e[1][2]) && float_equal(a.e[1][2], b.e[1][2]) &&
float_equal(a->e[2][0], b->e[2][0]) && float_equal(a.e[2][0], b.e[2][0]) &&
float_equal(a->e[2][1], b->e[2][1]) && float_equal(a.e[2][1], b.e[2][1]) &&
float_equal(a->e[2][2], b->e[2][2]); float_equal(a.e[2][2], b.e[2][2]);
} }
inline static bool mat2x2_equal(struct mat2x2 * a, inline static bool mat2x2_equal(struct mat2x2 a,
struct mat2x2 * b) struct mat2x2 b)
{ {
return return
float_equal(a->e[0][0], b->e[0][0]) && float_equal(a.e[0][0], b.e[0][0]) &&
float_equal(a->e[0][1], b->e[0][1]) && float_equal(a.e[0][1], b.e[0][1]) &&
float_equal(a->e[1][0], b->e[1][0]) && float_equal(a.e[1][0], b.e[1][0]) &&
float_equal(a->e[1][1], b->e[1][1]); float_equal(a.e[1][1], b.e[1][1]);
} }
inline static struct mat4x4 mat4x4_mul_m(struct mat4x4 const * const a, inline static struct mat4x4 mat4x4_mul_m(struct mat4x4 a,
struct mat4x4 const * const b) struct mat4x4 b)
{ {
#define dot(row, col) \ #define dot(row, col) \
a->e[row][0] * b->e[0][col] + \ a.e[row][0] * b.e[0][col] + \
a->e[row][1] * b->e[1][col] + \ a.e[row][1] * b.e[1][col] + \
a->e[row][2] * b->e[2][col] + \ a.e[row][2] * b.e[2][col] + \
a->e[row][3] * b->e[3][col] a.e[row][3] * b.e[3][col]
return mat4x4(dot(0, 0), dot(0, 1), dot(0, 2), dot(0, 3), return mat4x4(dot(0, 0), dot(0, 1), dot(0, 2), dot(0, 3),
dot(1, 0), dot(1, 1), dot(1, 2), dot(1, 3), dot(1, 0), dot(1, 1), dot(1, 2), dot(1, 3),
@ -112,14 +112,14 @@ inline static struct mat4x4 mat4x4_mul_m(struct mat4x4 const * const a,
#undef dot #undef dot
} }
inline static struct tuple mat4x4_mul_t(struct mat4x4 const * const a, inline static struct tuple mat4x4_mul_t(struct mat4x4 a,
struct tuple * b) struct tuple b)
{ {
#define dot(row) \ #define dot(row) \
a->e[row][0] * b->e[0] + \ a.e[row][0] * b.e[0] + \
a->e[row][1] * b->e[1] + \ a.e[row][1] * b.e[1] + \
a->e[row][2] * b->e[2] + \ a.e[row][2] * b.e[2] + \
a->e[row][3] * b->e[3] a.e[row][3] * b.e[3]
return tuple(dot(0), dot(1), dot(2), dot(3)); return tuple(dot(0), dot(1), dot(2), dot(3));
#undef dot #undef dot
@ -133,20 +133,20 @@ inline static struct mat4x4 mat4x4_identity()
0.0f, 0.0f, 0.0f, 1.0f); 0.0f, 0.0f, 0.0f, 1.0f);
} }
inline static struct mat4x4 mat4x4_transpose(struct mat4x4 const * const a) inline static struct mat4x4 mat4x4_transpose(struct mat4x4 a)
{ {
return mat4x4(a->e[0][0], a->e[1][0], a->e[2][0], a->e[3][0], return mat4x4(a.e[0][0], a.e[1][0], a.e[2][0], a.e[3][0],
a->e[0][1], a->e[1][1], a->e[2][1], a->e[3][1], a.e[0][1], a.e[1][1], a.e[2][1], a.e[3][1],
a->e[0][2], a->e[1][2], a->e[2][2], a->e[3][2], a.e[0][2], a.e[1][2], a.e[2][2], a.e[3][2],
a->e[0][3], a->e[1][3], a->e[2][3], a->e[3][3]); a.e[0][3], a.e[1][3], a.e[2][3], a.e[3][3]);
} }
inline static float mat2x2_determinant(struct mat2x2 * a) inline static float mat2x2_determinant(struct mat2x2 a)
{ {
return a->e[0][0] * a->e[1][1] - a->e[0][1] * a->e[1][0]; return a.e[0][0] * a.e[1][1] - a.e[0][1] * a.e[1][0];
} }
inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 * a, int r, int c) inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 a, int r, int c)
{ {
struct mat2x2 b; struct mat2x2 b;
int row2 = 0; int row2 = 0;
@ -155,7 +155,7 @@ inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 * a, int r, int c)
int col2 = 0; int col2 = 0;
for (int col3 = 0; col3 < 3; col3++) { for (int col3 = 0; col3 < 3; col3++) {
if (col3 == c) continue; if (col3 == c) continue;
b.e[row2][col2] = a->e[row3][col3]; b.e[row2][col2] = a.e[row3][col3];
col2++; col2++;
} }
row2++; row2++;
@ -163,7 +163,7 @@ inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 * a, int r, int c)
return b; return b;
} }
inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 const * const a, int r, int c) inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 a, int r, int c)
{ {
struct mat3x3 b; struct mat3x3 b;
int row3 = 0; int row3 = 0;
@ -172,7 +172,7 @@ inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 const * const a, int
int col3 = 0; int col3 = 0;
for (int col4 = 0; col4 < 4; col4++) { for (int col4 = 0; col4 < 4; col4++) {
if (col4 == c) continue; if (col4 == c) continue;
b.e[row3][col3] = a->e[row4][col4]; b.e[row3][col3] = a.e[row4][col4];
col3++; col3++;
} }
row3++; row3++;
@ -180,14 +180,14 @@ inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 const * const a, int
return b; return b;
} }
inline static float mat3x3_minor(struct mat3x3 * a, int r, int c) inline static float mat3x3_minor(struct mat3x3 a, int r, int c)
{ {
struct mat2x2 s = mat3x3_submatrix(a, r, c); struct mat2x2 s = mat3x3_submatrix(a, r, c);
float ret = mat2x2_determinant(&s); float ret = mat2x2_determinant(s);
return ret; return ret;
} }
inline static float mat3x3_cofactor(struct mat3x3 * a, int r, int c) inline static float mat3x3_cofactor(struct mat3x3 a, int r, int c)
{ {
float minor = mat3x3_minor(a, r, c); float minor = mat3x3_minor(a, r, c);
if ((r + c) & 1) if ((r + c) & 1)
@ -196,25 +196,25 @@ inline static float mat3x3_cofactor(struct mat3x3 * a, int r, int c)
return minor; return minor;
} }
inline static float mat3x3_determinant(struct mat3x3 * a) inline static float mat3x3_determinant(struct mat3x3 a)
{ {
float f0 = mat3x3_cofactor(a, 0, 0); float f0 = mat3x3_cofactor(a, 0, 0);
float f1 = mat3x3_cofactor(a, 0, 1); float f1 = mat3x3_cofactor(a, 0, 1);
float f2 = mat3x3_cofactor(a, 0, 2); float f2 = mat3x3_cofactor(a, 0, 2);
return return
a->e[0][0] * f0 + a.e[0][0] * f0 +
a->e[0][1] * f1 + a.e[0][1] * f1 +
a->e[0][2] * f2; a.e[0][2] * f2;
} }
inline static float mat4x4_minor(struct mat4x4 const * const a, int r, int c) inline static float mat4x4_minor(struct mat4x4 a, int r, int c)
{ {
struct mat3x3 s = mat4x4_submatrix(a, r, c); struct mat3x3 s = mat4x4_submatrix(a, r, c);
float ret = mat3x3_determinant(&s); float ret = mat3x3_determinant(s);
return ret; return ret;
} }
inline static float mat4x4_cofactor(struct mat4x4 const * const a, int r, int c) inline static float mat4x4_cofactor(struct mat4x4 a, int r, int c)
{ {
float minor = mat4x4_minor(a, r, c); float minor = mat4x4_minor(a, r, c);
if ((r + c) & 1) if ((r + c) & 1)
@ -223,25 +223,25 @@ inline static float mat4x4_cofactor(struct mat4x4 const * const a, int r, int c)
return minor; return minor;
} }
inline static float mat4x4_determinant(struct mat4x4 const * const a) inline static float mat4x4_determinant(struct mat4x4 a)
{ {
float f0 = mat4x4_cofactor(a, 0, 0); float f0 = mat4x4_cofactor(a, 0, 0);
float f1 = mat4x4_cofactor(a, 0, 1); float f1 = mat4x4_cofactor(a, 0, 1);
float f2 = mat4x4_cofactor(a, 0, 2); float f2 = mat4x4_cofactor(a, 0, 2);
float f3 = mat4x4_cofactor(a, 0, 3); float f3 = mat4x4_cofactor(a, 0, 3);
return return
a->e[0][0] * f0 + a.e[0][0] * f0 +
a->e[0][1] * f1 + a.e[0][1] * f1 +
a->e[0][2] * f2 + a.e[0][2] * f2 +
a->e[0][3] * f3; a.e[0][3] * f3;
} }
inline static bool mat4x4_is_invertible(struct mat4x4 const * const a) inline static bool mat4x4_is_invertible(struct mat4x4 a)
{ {
return !float_equal(mat4x4_determinant(a), 0.f); return !float_equal(mat4x4_determinant(a), 0.f);
} }
inline static struct mat4x4 mat4x4_inverse(struct mat4x4 const * const a) inline static struct mat4x4 mat4x4_inverse(struct mat4x4 a)
{ {
struct mat4x4 m; struct mat4x4 m;
float det = mat4x4_determinant(a); float det = mat4x4_determinant(a);

35
planes.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include "math.h"
#include "matrices.h"
#include "materials.h"
#include "shapes.h"
#include "rays.h"
#include "intersections.h"
inline static struct shape plane()
{
return (struct shape){
mat4x4_identity(),
material(),
SHAPE_PLANE,
};
}
inline static struct tuple plane_normal_at(struct tuple local_point)
{
return vector(0.0f, 1.0f, 0.0f);
}
inline static void plane_intersect(struct shape const * const s, struct ray local_ray, struct intersections * intersections)
{
if (fabsf(local_ray.direction.y) < epsilon) {
return;
}
float t = -local_ray.origin.y / local_ray.direction.y;
intersections->i[intersections->count++] = intersection(t, s);
return;
}

7
rays.h
View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "spheres.h"
#include "tuples.h" #include "tuples.h"
#include "matrices.h" #include "matrices.h"
@ -19,8 +18,8 @@ inline static struct tuple ray_position(struct ray ray, float t)
return tuple_add(ray.origin, tuple_mul(ray.direction, t)); return tuple_add(ray.origin, tuple_mul(ray.direction, t));
} }
inline static struct ray ray_transform(struct ray r, struct mat4x4 const * const m) inline static struct ray ray_transform(struct ray r, struct mat4x4 m)
{ {
return ray(mat4x4_mul_t(m, &r.origin), return ray(mat4x4_mul_t(m, r.origin),
mat4x4_mul_t(m, &r.direction)); mat4x4_mul_t(m, r.direction));
} }

View File

@ -22,59 +22,60 @@ int main()
float pixel_size = wall_size / (float)canvas_pixels; float pixel_size = wall_size / (float)canvas_pixels;
float half = wall_size / 2.0f; float half = wall_size / 2.0f;
struct sphere floor = sphere(); struct shape floor = plane();
floor.transform = scaling(10.0f, 0.01f, 10.0f);
floor.material.color = color(1.0f, 0.9f, 0.9f); floor.material.color = color(1.0f, 0.9f, 0.9f);
floor.material.specular = 0.0f; floor.material.specular = 0.0f;
struct sphere left_wall = sphere(); /*
struct shape left_wall = sphere();
{ {
struct mat4x4 _translation = translation(0.0f, 0.0f, 5.0f); struct mat4x4 _translation = translation(0.0f, 0.0f, 5.0f);
struct mat4x4 _rotation_y = rotation_y(-pi / 4.0f); struct mat4x4 _rotation_y = rotation_y(-pi / 4.0f);
struct mat4x4 _rotation_x = rotation_x(pi / 2.0f); struct mat4x4 _rotation_x = rotation_x(pi / 2.0f);
struct mat4x4 _scaling = scaling(10.0f, 0.05f, 10.0f); struct mat4x4 _scaling = scaling(10.0f, 0.05f, 10.0f);
struct mat4x4 t0 = mat4x4_mul_m(&_rotation_x, &_scaling); struct mat4x4 t0 = mat4x4_mul_m(_rotation_x, _scaling);
struct mat4x4 t1 = mat4x4_mul_m(&_rotation_y, &t0); struct mat4x4 t1 = mat4x4_mul_m(_rotation_y, t0);
struct mat4x4 t2 = mat4x4_mul_m(&_translation, &t1); struct mat4x4 t2 = mat4x4_mul_m(_translation, t1);
left_wall.transform = t2; left_wall.transform = t2;
} }
left_wall.material = floor.material; left_wall.material = floor.material;
struct sphere right_wall = sphere(); struct shape right_wall = sphere();
{ {
struct mat4x4 _translation = translation(0.0f, 0.0f, 5.0f); struct mat4x4 _translation = translation(0.0f, 0.0f, 5.0f);
struct mat4x4 _rotation_y = rotation_y(pi / 4.0f); struct mat4x4 _rotation_y = rotation_y(pi / 4.0f);
struct mat4x4 _rotation_x = rotation_x(pi / 2.0f); struct mat4x4 _rotation_x = rotation_x(pi / 2.0f);
struct mat4x4 _scaling = scaling(10.0f, 0.05f, 10.0f); struct mat4x4 _scaling = scaling(10.0f, 0.05f, 10.0f);
struct mat4x4 t0 = mat4x4_mul_m(&_rotation_x, &_scaling); struct mat4x4 t0 = mat4x4_mul_m(_rotation_x, _scaling);
struct mat4x4 t1 = mat4x4_mul_m(&_rotation_y, &t0); struct mat4x4 t1 = mat4x4_mul_m(_rotation_y, t0);
struct mat4x4 t2 = mat4x4_mul_m(&_translation, &t1); struct mat4x4 t2 = mat4x4_mul_m(_translation, t1);
right_wall.transform = t2; right_wall.transform = t2;
} }
right_wall.material = floor.material; right_wall.material = floor.material;
*/
struct sphere middle = sphere(); struct shape middle = sphere();
middle.transform = translation(-0.5f, 1.0f, 0.5f); middle.transform = translation(-0.5f, 1.0f, 0.5f);
middle.material.color = color((float)0xfc / 255.f , (float)0x6d / 255.f, (float)0x09 / 255.f); middle.material.color = color((float)0xfc / 255.f , (float)0x6d / 255.f, (float)0x09 / 255.f);
middle.material.diffuse = 0.7; middle.material.diffuse = 0.7;
middle.material.specular = 0.3; middle.material.specular = 0.3;
struct sphere right = sphere(); struct shape right = sphere();
struct mat4x4 right_t = translation(1.5f, 0.5f, -0.5f); struct mat4x4 right_t = translation(1.5f, 0.5f, -0.5f);
struct mat4x4 right_s = scaling(0.5f, 0.5f, 0.5f); struct mat4x4 right_s = scaling(0.5f, 0.5f, 0.5f);
right.transform = mat4x4_mul_m(&right_t, &right_s); right.transform = mat4x4_mul_m(right_t, right_s);
right.material.color = color(0.5f, 1.0f, 0.1f); right.material.color = color(0.5f, 1.0f, 0.1f);
right.material.diffuse = 0.7; right.material.diffuse = 0.7;
right.material.specular = 0.3; right.material.specular = 0.3;
struct sphere left = sphere(); struct shape left = sphere();
struct mat4x4 left_t = translation(-1.5f, 0.33f, -0.75f); struct mat4x4 left_t = translation(-1.5f, 0.33f, -0.75f);
struct mat4x4 left_s = scaling(0.33f, 0.33f, 0.33f); struct mat4x4 left_s = scaling(0.33f, 0.33f, 0.33f);
left.transform = mat4x4_mul_m(&left_t, &left_s); left.transform = mat4x4_mul_m(left_t, left_s);
left.material.color = color((float)0x12 / 255.f, (float)0xc9 / 255.f, (float)0xcc / 255.f); left.material.color = color((float)0x12 / 255.f, (float)0xc9 / 255.f, (float)0xcc / 255.f);
left.material.diffuse = 0.7; left.material.diffuse = 0.7;
left.material.specular = 0.3; left.material.specular = 0.3;
@ -83,42 +84,104 @@ int main()
struct tuple light_color = color(1.0f, 1.0f, 1.0f); struct tuple light_color = color(1.0f, 1.0f, 1.0f);
struct light light = point_light(light_position, light_color); struct light light = point_light(light_position, light_color);
struct shape h1 = plane();
struct shape h2 = plane();
struct shape h3 = plane();
struct shape h4 = plane();
struct shape h5 = plane();
struct shape h6 = plane();
struct mat4x4 h1_t = translation(0, 8, 8);
struct mat4x4 h2_t = translation(4, 0, 6.9282);
struct mat4x4 h3_t = translation(-4, 0, 6.9282);
struct mat4x4 h4_t = translation(0, -8, 8);
struct mat4x4 h5_t = translation(-4, 0, -6.9282);
struct mat4x4 h6_t = translation(4, 0, -6.9282);
struct mat4x4 h1_r = rotation_x(tau / 4.0f);
struct mat4x4 h2_r = rotation_x(tau / 4.0f);
struct mat4x4 h3_r = rotation_x(tau / 4.0f);
struct mat4x4 h4_r = rotation_x(tau / 4.0f);
struct mat4x4 h5_r = rotation_x(tau / 4.0f);
struct mat4x4 h6_r = rotation_x(tau / 4.0f);
struct mat4x4 h1_rr = rotation_y(tau / 4.0f * 0);
h1.transform = mat4x4_mul_m(h1_t, h1_r);
h1.transform = mat4x4_mul_m(h1_rr, h1.transform);
struct mat4x4 h2_rr = rotation_y(tau / 4.0f * 1);
h2.transform = mat4x4_mul_m(h2_t, h2_r);
h2.transform = mat4x4_mul_m(h2_rr, h2.transform);
struct mat4x4 h3_rr = rotation_y(tau / 4.0f * 2);
h3.transform = mat4x4_mul_m(h3_t, h3_r);
h3.transform = mat4x4_mul_m(h3_rr, h3.transform);
struct mat4x4 h4_rr = rotation_y(tau / 4.0f * 3);
h4.transform = mat4x4_mul_m(h4_t, h4_r);
h4.transform = mat4x4_mul_m(h4_rr, h4.transform);
struct mat4x4 h5_rr = rotation_y(tau / 4.0f);
h5.transform = mat4x4_mul_m(h5_rr, h5_r);
h5.transform = mat4x4_mul_m(h5_t, h5.transform);
struct mat4x4 h6_rr = rotation_y(tau / 4.0f);
h6.transform = mat4x4_mul_m(h6_rr, h6_r);
h6.transform = mat4x4_mul_m(h6_t, h6.transform);
h1.material = floor.material;
h1.material.color = color(1.0f, 0.0f, 0.0f);
h2.material = floor.material;
h2.material.color = color(0.0f, 1.0f, 0.0f);
h3.material = floor.material;
h3.material.color = color(0.0f, 0.0f, 1.0f);
h4.material = floor.material;
h4.material.color = color(1.0f, 1.0f, 0.0f);
h5.material = floor.material;
h5.material.color = color(0.0f, 1.0f, 1.0f);
h6.material = floor.material;
h6.material.color = color(1.0f, 0.0f, 1.0f);
struct world world; struct world world;
world.light = light; world.light = light;
world.object_count = 6; world.object_count = 4 + 4;
world.objects[0] = floor; world.objects[0] = floor;
world.objects[1] = left_wall; world.objects[1] = middle;
world.objects[2] = right_wall; world.objects[2] = right;
world.objects[3] = middle; world.objects[3] = left;
world.objects[4] = right;
world.objects[5] = left;
struct camera _camera = camera(1600.0f, 800.0f, pi / 3.0f); world.objects[4] = h1;
world.objects[5] = h2;
world.objects[6] = h3;
world.objects[7] = h4;
world.objects[8] = h5;
world.objects[9] = h6;
struct camera _camera = camera(1600.0f, 800.0f, pi / 4.f);
_camera.transform = view_transform(point(0.0f, 1.5f, -5.0f), _camera.transform = view_transform(point(0.0f, 1.5f, -5.0f),
point(0.0f, 1.0f, 0.0f), point(0.0f, 1.0f, 0.0f),
vector(0.0f, 1.0f, 0.0f)); vector(0.0f, 1.0f, 0.0f));
struct mat4x4 middle_t = world.objects[3].transform; struct mat4x4 middle_t = world.objects[1].transform;
for (int i = 0; i < 360; i++) { for (int i = 0; i < 360; i++) {
_camera.transform = view_transform(point(5.0f * cosf(pi / 360 * (float)i / 10), _camera.transform = view_transform(point(2.0f * cosf(pi / 360 * (float)i * 0.5),
1.5f, 8.5f,
-5.0f * sinf(pi / 360 * (float)i / 10)), 1.0f * sinf(pi / 360 * (float)i * 0.5)),
point(0.0f, 1.0f, 0.0f), point(0.0f, 1.0f, 0.0f),
vector(0.0f, 1.0f, 0.0f)); vector(0.0f, 1.0f, 0.0f));
struct tuple light_position = point(-10.0f * cosf(pi / 360 * (float)i), struct tuple light_position = point(-6.0f * cosf(pi / 360 * (float)i * 3),
10.0f, 10.0f,
-10.0f * sinf(pi / 360 * (float)i)); -6.0f * sinf(pi / 360 * (float)i * 3));
world.light.position = light_position; world.light.position = light_position;
struct mat4x4 middle_s = scaling(1.0f, 0.4f, 1.0f); struct mat4x4 middle_s = scaling(1.0f, 0.4f, 1.0f);
struct mat4x4 middle_rz = rotation_z(tau / 360.f * (float)i); struct mat4x4 middle_rz = rotation_z(tau / 360.f * (float)i);
struct mat4x4 middle_ry = rotation_y(tau / 360.f * (float)i); struct mat4x4 middle_ry = rotation_y(tau / 360.f * (float)i);
struct mat4x4 middle_r = mat4x4_mul_m(&middle_rz, &middle_ry); struct mat4x4 middle_r = mat4x4_mul_m(middle_rz, middle_ry);
struct mat4x4 middle_transform = mat4x4_mul_m(&middle_r, &middle_s); struct mat4x4 middle_transform = mat4x4_mul_m(middle_r, middle_s);
world.objects[3].transform = mat4x4_mul_m(&middle_t, &middle_transform); world.objects[1].transform = mat4x4_mul_m(middle_t, middle_transform);
camera_render(&_camera, &world, &_canvas); camera_render(&_camera, &world, &_canvas);

25
shapes.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "matrices.h"
#include "materials.h"
enum shape_type {
SHAPE_TEST,
SHAPE_SPHERE,
SHAPE_PLANE,
};
struct shape {
struct mat4x4 transform;
struct material material;
enum shape_type type;
};
inline static struct shape shape()
{
return (struct shape){
mat4x4_identity(),
material(),
SHAPE_TEST,
};
}

View File

@ -2,27 +2,43 @@
#include "matrices.h" #include "matrices.h"
#include "materials.h" #include "materials.h"
#include "shapes.h"
#include "rays.h"
#include "intersections.h"
struct sphere { inline static struct shape sphere()
struct mat4x4 transform;
struct material material;
};
inline static struct sphere sphere()
{ {
return (struct sphere){ return (struct shape){
mat4x4_identity(), mat4x4_identity(),
material() material(),
SHAPE_SPHERE,
}; };
} }
inline static struct tuple sphere_normal_at(struct sphere const * const s, struct tuple world_point) inline static struct tuple sphere_normal_at(struct tuple local_point)
{ {
struct mat4x4 inv = mat4x4_inverse(&s->transform); return tuple_sub(local_point, point(0.0f, 0.0f, 0.0f));
struct tuple object_point = mat4x4_mul_t(&inv, &world_point); }
struct tuple object_normal = tuple_sub(object_point, point(0.0f, 0.0f, 0.0f));
struct mat4x4 inv_t = mat4x4_transpose(&inv); inline static void sphere_intersect(struct shape const * const s, struct ray local_ray, struct intersections * intersections)
struct tuple world_normal = mat4x4_mul_t(&inv_t, &object_normal); {
world_normal.w = 0.0f; struct tuple sphere_to_ray = tuple_sub(local_ray.origin, point(0.0f, 0.0f, 0.0f));
return tuple_normalize(world_normal);
float a = tuple_dot(local_ray.direction, local_ray.direction);
float b = 2 * tuple_dot(local_ray.direction, sphere_to_ray);
float c = tuple_dot(sphere_to_ray, sphere_to_ray) - 1;
float discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return;
} else {
float root = sqrtf(discriminant);
float t1 = (-b - root) / (2 * a);
float t2 = (-b + root) / (2 * a);
intersections->i[intersections->count++] = intersection(t1, s);
intersections->i[intersections->count++] = intersection(t2, s);
return;
}
} }

View File

@ -2,10 +2,13 @@
set -eux set -eux
for name in tuples canvas matrices transformations rays intersections spheres lights materials world camera; do
for name in tuples canvas matrices transformations rays intersections shapes spheres planes lights materials world camera; do
gcc -g -gdwarf-5 \ gcc -g -gdwarf-5 \
-Wall -Werror -Wfatal-errors \ -Wall -Werror -Wfatal-errors \
-Wno-error=unused-variable \
-I. \ -I. \
-DTEST \
test/test_${name}.c -o test/test_${name} -O0 -lm test/test_${name}.c -o test/test_${name} -O0 -lm
./test/test_${name} ./test/test_${name}
done done

View File

@ -21,7 +21,7 @@ static bool camera_test_0(const char ** scenario)
float_equal(c.hsize, 160.0f) && float_equal(c.hsize, 160.0f) &&
float_equal(c.vsize, 120.0f) && float_equal(c.vsize, 120.0f) &&
float_equal(c.field_of_view, pi / 2.0f) && float_equal(c.field_of_view, pi / 2.0f) &&
mat4x4_equal(&c.transform, &identity_matrix); mat4x4_equal(c.transform, identity_matrix);
} }
static bool camera_test_1(const char ** scenario) static bool camera_test_1(const char ** scenario)
@ -73,7 +73,7 @@ static bool camera_test_5(const char ** scenario)
struct camera c = camera(201.0f, 101.0f, pi / 2.0f); struct camera c = camera(201.0f, 101.0f, pi / 2.0f);
struct mat4x4 rotate = rotation_y(pi / 4.0f); struct mat4x4 rotate = rotation_y(pi / 4.0f);
struct mat4x4 translate = translation(0.0f, -2.0f, 5.0f); struct mat4x4 translate = translation(0.0f, -2.0f, 5.0f);
c.transform = mat4x4_mul_m(&rotate, &translate); c.transform = mat4x4_mul_m(rotate, translate);
struct ray r = camera_ray_for_pixel(&c, 100.0f, 50.0f); struct ray r = camera_ray_for_pixel(&c, 100.0f, 50.0f);
return return

View File

@ -1,7 +1,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include "intersections.h" #include "intersections_shapes.h"
#include "transformations.h" #include "transformations.h"
#include "runner.h" #include "runner.h"
@ -9,7 +9,7 @@ static bool intersections_test_0(const char ** scenario)
{ {
*scenario = "An intersection encapsulates t and object"; *scenario = "An intersection encapsulates t and object";
struct sphere s = sphere(); struct shape s = sphere();
struct intersection i = intersection(3.5f, &s); struct intersection i = intersection(3.5f, &s);
return return
@ -21,7 +21,7 @@ static bool intersections_test_1(const char ** scenario)
{ {
*scenario = "Aggregating intersections"; *scenario = "Aggregating intersections";
struct sphere s = sphere(); struct shape s = sphere();
struct intersection i1 = intersection(1.0f, &s); struct intersection i1 = intersection(1.0f, &s);
struct intersection i2 = intersection(2.0f, &s); struct intersection i2 = intersection(2.0f, &s);
struct intersections xs; struct intersections xs;
@ -37,7 +37,7 @@ static bool intersections_test_2(const char ** scenario)
{ {
*scenario = "The hit, when all intersections have positive t"; *scenario = "The hit, when all intersections have positive t";
struct sphere s = sphere(); struct shape s = sphere();
struct intersection i1 = intersection(1.0f, &s); struct intersection i1 = intersection(1.0f, &s);
struct intersection i2 = intersection(2.0f, &s); struct intersection i2 = intersection(2.0f, &s);
struct intersections xs; struct intersections xs;
@ -55,7 +55,7 @@ static bool intersections_test_3(const char ** scenario)
{ {
*scenario = "The hit, when some intersections have negative t"; *scenario = "The hit, when some intersections have negative t";
struct sphere s = sphere(); struct shape s = sphere();
struct intersection i1 = intersection(-1.0f, &s); struct intersection i1 = intersection(-1.0f, &s);
struct intersection i2 = intersection( 1.0f, &s); struct intersection i2 = intersection( 1.0f, &s);
struct intersections xs; struct intersections xs;
@ -73,7 +73,7 @@ static bool intersections_test_4(const char ** scenario)
{ {
*scenario = "The hit, when all intersections have negative t"; *scenario = "The hit, when all intersections have negative t";
struct sphere s = sphere(); struct shape s = sphere();
struct intersection i1 = intersection(-2.0f, &s); struct intersection i1 = intersection(-2.0f, &s);
struct intersection i2 = intersection(-1.0f, &s); struct intersection i2 = intersection(-1.0f, &s);
struct intersections xs; struct intersections xs;
@ -88,7 +88,7 @@ static bool intersections_test_5(const char ** scenario)
{ {
*scenario = "The hit is always the lowest nonnegative intersection"; *scenario = "The hit is always the lowest nonnegative intersection";
struct sphere s = sphere(); struct shape s = sphere();
struct intersection i1 = intersection( 5.0f, &s); struct intersection i1 = intersection( 5.0f, &s);
struct intersection i2 = intersection( 7.0f, &s); struct intersection i2 = intersection( 7.0f, &s);
struct intersection i3 = intersection(-3.0f, &s); struct intersection i3 = intersection(-3.0f, &s);
@ -108,13 +108,13 @@ static bool intersections_test_6(const char ** scenario)
{ {
*scenario = "In-place ascending sort of intersections"; *scenario = "In-place ascending sort of intersections";
struct sphere s1 = sphere(); struct shape s1 = sphere();
s1.material.ambient = 1.0f; s1.material.ambient = 1.0f;
struct sphere s2 = sphere(); struct shape s2 = sphere();
s2.material.ambient = 2.0f; s2.material.ambient = 2.0f;
struct sphere s3 = sphere(); struct shape s3 = sphere();
s3.material.ambient = 3.0f; s3.material.ambient = 3.0f;
struct sphere s4 = sphere(); struct shape s4 = sphere();
s4.material.ambient = 4.0f; s4.material.ambient = 4.0f;
struct intersection i1 = intersection( 5.0f, &s1); struct intersection i1 = intersection( 5.0f, &s1);
struct intersection i2 = intersection( 7.0f, &s2); struct intersection i2 = intersection( 7.0f, &s2);
@ -141,7 +141,7 @@ static bool intersections_test_7(const char ** scenario)
*scenario = "Precomputing the state of an intersection"; *scenario = "Precomputing the state of an intersection";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere shape = sphere(); struct shape shape = sphere();
struct intersection i = intersection(4.0f, &shape); struct intersection i = intersection(4.0f, &shape);
struct computations comps = prepare_computations(i, r); struct computations comps = prepare_computations(i, r);
@ -158,7 +158,7 @@ static bool intersections_test_8(const char ** scenario)
*scenario = "The hit, when an intersection occurs on the outside"; *scenario = "The hit, when an intersection occurs on the outside";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere shape = sphere(); struct shape shape = sphere();
struct intersection i = intersection(4.0f, &shape); struct intersection i = intersection(4.0f, &shape);
struct computations comps = prepare_computations(i, r); struct computations comps = prepare_computations(i, r);
@ -171,7 +171,7 @@ static bool intersections_test_9(const char ** scenario)
*scenario = "The hit, when an intersection occurs on the inside"; *scenario = "The hit, when an intersection occurs on the inside";
struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere shape = sphere(); struct shape shape = sphere();
struct intersection i = intersection(1.0f, &shape); struct intersection i = intersection(1.0f, &shape);
struct computations comps = prepare_computations(i, r); struct computations comps = prepare_computations(i, r);
@ -187,7 +187,7 @@ static bool intersections_test_10(const char ** scenario)
*scenario = "The hit should offset the point"; *scenario = "The hit should offset the point";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere shape = sphere(); struct shape shape = sphere();
shape.transform = translation(0.0f, 0.0f, 1.0f); shape.transform = translation(0.0f, 0.0f, 1.0f);
struct intersection i = intersection(5.0f, &shape); struct intersection i = intersection(5.0f, &shape);
struct computations comps = prepare_computations(i, r); struct computations comps = prepare_computations(i, r);

View File

@ -58,7 +58,7 @@ static bool matrices_test_3(const char ** scenario)
9.0f, 8.0f, 7.0f, 6.0f, 9.0f, 8.0f, 7.0f, 6.0f,
5.0f, 4.0f, 3.0f, 2.0f); 5.0f, 4.0f, 3.0f, 2.0f);
return mat4x4_equal(&a, &b); return mat4x4_equal(a, b);
} }
static bool matrices_test_4(const char ** scenario) static bool matrices_test_4(const char ** scenario)
@ -75,7 +75,7 @@ static bool matrices_test_4(const char ** scenario)
8.0f, 7.0f, 6.0f, 5.0f, 8.0f, 7.0f, 6.0f, 5.0f,
4.0f, 3.0f, 2.0f, 1.0f); 4.0f, 3.0f, 2.0f, 1.0f);
return !mat4x4_equal(&a, &b); return !mat4x4_equal(a, b);
} }
static bool matrices_test_5(const char ** scenario) static bool matrices_test_5(const char ** scenario)
@ -92,12 +92,12 @@ static bool matrices_test_5(const char ** scenario)
4.0f, 3.0f, 6.0f, 5.0f, 4.0f, 3.0f, 6.0f, 5.0f,
1.0f, 2.0f, 7.0f, 8.0f); 1.0f, 2.0f, 7.0f, 8.0f);
struct mat4x4 m1 = mat4x4_mul_m(&a, &b); struct mat4x4 m1 = mat4x4_mul_m(a, b);
struct mat4x4 m2 = mat4x4(20.0f, 22.0f, 50.0f, 48.0f, struct mat4x4 m2 = mat4x4(20.0f, 22.0f, 50.0f, 48.0f,
44.0f, 54.0f, 114.0f, 108.0f, 44.0f, 54.0f, 114.0f, 108.0f,
40.0f, 58.0f, 110.0f, 102.0f, 40.0f, 58.0f, 110.0f, 102.0f,
16.0f, 26.0f, 46.0f, 42.0f); 16.0f, 26.0f, 46.0f, 42.0f);
return mat4x4_equal(&m1, &m2); return mat4x4_equal(m1, m2);
} }
static bool matrices_test_6(const char ** scenario) static bool matrices_test_6(const char ** scenario)
@ -110,7 +110,7 @@ static bool matrices_test_6(const char ** scenario)
0.0f, 0.0f, 0.0f, 1.0f); 0.0f, 0.0f, 0.0f, 1.0f);
struct tuple b = tuple(1.0f, 2.0f, 3.0f, 1.0f); struct tuple b = tuple(1.0f, 2.0f, 3.0f, 1.0f);
struct tuple c = mat4x4_mul_t(&a, &b); struct tuple c = mat4x4_mul_t(a, b);
return tuple_equal(c, tuple(18, 24, 33, 1)); return tuple_equal(c, tuple(18, 24, 33, 1));
} }
@ -124,8 +124,8 @@ static bool matrices_test_7(const char ** scenario)
4.0f, 8.0f, 16.0f, 32.0f); 4.0f, 8.0f, 16.0f, 32.0f);
struct mat4x4 id = mat4x4_identity(); struct mat4x4 id = mat4x4_identity();
struct mat4x4 c = mat4x4_mul_m(&a, &id); struct mat4x4 c = mat4x4_mul_m(a, id);
return mat4x4_equal(&a, &c); return mat4x4_equal(a, c);
} }
static bool matrices_test_8(const char ** scenario) static bool matrices_test_8(const char ** scenario)
@ -135,7 +135,7 @@ static bool matrices_test_8(const char ** scenario)
struct tuple a = tuple(1.0f, 2.0f, 3.0f, 4.0f); struct tuple a = tuple(1.0f, 2.0f, 3.0f, 4.0f);
struct mat4x4 id = mat4x4_identity(); struct mat4x4 id = mat4x4_identity();
struct tuple c = mat4x4_mul_t(&id, &a); struct tuple c = mat4x4_mul_t(id, a);
return tuple_equal(a, c); return tuple_equal(a, c);
} }
@ -153,9 +153,9 @@ static bool matrices_test_9(const char ** scenario)
3.0f, 0.0f, 5.0f, 5.0f, 3.0f, 0.0f, 5.0f, 5.0f,
0.0f, 8.0f, 3.0f, 8.0f); 0.0f, 8.0f, 3.0f, 8.0f);
struct mat4x4 c = mat4x4_transpose(&a); struct mat4x4 c = mat4x4_transpose(a);
return mat4x4_equal(&c, &b); return mat4x4_equal(c, b);
} }
static bool matrices_test_10(const char ** scenario) static bool matrices_test_10(const char ** scenario)
@ -164,9 +164,9 @@ static bool matrices_test_10(const char ** scenario)
struct mat4x4 a = mat4x4_identity(); struct mat4x4 a = mat4x4_identity();
struct mat4x4 c = mat4x4_transpose(&a); struct mat4x4 c = mat4x4_transpose(a);
return mat4x4_equal(&a, &c); return mat4x4_equal(a, c);
} }
static bool matrices_test_11(const char ** scenario) static bool matrices_test_11(const char ** scenario)
@ -176,7 +176,7 @@ static bool matrices_test_11(const char ** scenario)
struct mat2x2 a = mat2x2( 1.0f, 5.0f, struct mat2x2 a = mat2x2( 1.0f, 5.0f,
-3.0f, 2.0f); -3.0f, 2.0f);
return float_equal(mat2x2_determinant(&a), 17); return float_equal(mat2x2_determinant(a), 17);
} }
static bool matrices_test_12(const char ** scenario) static bool matrices_test_12(const char ** scenario)
@ -187,11 +187,11 @@ static bool matrices_test_12(const char ** scenario)
-3.0f, 2.0f, 7.0f, -3.0f, 2.0f, 7.0f,
0.0f, 6.0f, -3.0f); 0.0f, 6.0f, -3.0f);
struct mat2x2 b = mat3x3_submatrix(&a, 0, 2); struct mat2x2 b = mat3x3_submatrix(a, 0, 2);
struct mat2x2 c = mat2x2(-3.0f, 2.0f, struct mat2x2 c = mat2x2(-3.0f, 2.0f,
0.0f, 6.0f); 0.0f, 6.0f);
return mat2x2_equal(&b, &c); return mat2x2_equal(b, c);
} }
static bool matrices_test_13(const char ** scenario) static bool matrices_test_13(const char ** scenario)
@ -203,12 +203,12 @@ static bool matrices_test_13(const char ** scenario)
-1.0f, 0.0f, 8.0f, 2.0f, -1.0f, 0.0f, 8.0f, 2.0f,
-7.0f, 1.0f, -1.0f, 1.0f); -7.0f, 1.0f, -1.0f, 1.0f);
struct mat3x3 b = mat4x4_submatrix(&a, 2, 1); struct mat3x3 b = mat4x4_submatrix(a, 2, 1);
struct mat3x3 c = mat3x3(-6.0f, 1.0f, 6.0f, struct mat3x3 c = mat3x3(-6.0f, 1.0f, 6.0f,
-8.0f, 8.0f, 6.0f, -8.0f, 8.0f, 6.0f,
-7.0f, -1.0f, 1.0f); -7.0f, -1.0f, 1.0f);
return mat3x3_equal(&b, &c); return mat3x3_equal(b, c);
} }
static bool matrices_test_14(const char ** scenario) static bool matrices_test_14(const char ** scenario)
@ -218,11 +218,11 @@ static bool matrices_test_14(const char ** scenario)
struct mat3x3 a = mat3x3(3, 5, 0, struct mat3x3 a = mat3x3(3, 5, 0,
2, -1, -7, 2, -1, -7,
6, -1, 5); 6, -1, 5);
struct mat2x2 b = mat3x3_submatrix(&a, 1, 0); struct mat2x2 b = mat3x3_submatrix(a, 1, 0);
return return
float_equal(mat2x2_determinant(&b), 25.0f) && float_equal(mat2x2_determinant(b), 25.0f) &&
float_equal(mat3x3_minor(&a, 1, 0), 25.0f); float_equal(mat3x3_minor(a, 1, 0), 25.0f);
} }
static bool matrices_test_15(const char ** scenario) static bool matrices_test_15(const char ** scenario)
@ -234,11 +234,11 @@ static bool matrices_test_15(const char ** scenario)
6, -1, 5); 6, -1, 5);
return return
float_equal(mat3x3_minor(&a, 0, 0), -12.0f) && float_equal(mat3x3_minor(a, 0, 0), -12.0f) &&
float_equal(mat3x3_cofactor(&a, 0, 0), -12.0f) && float_equal(mat3x3_cofactor(a, 0, 0), -12.0f) &&
float_equal(mat3x3_minor(&a, 1, 0), 25.0f) && float_equal(mat3x3_minor(a, 1, 0), 25.0f) &&
float_equal(mat3x3_cofactor(&a, 1, 0), -25.0f) && float_equal(mat3x3_cofactor(a, 1, 0), -25.0f) &&
float_equal(mat3x3_cofactor(&a, 2, 1), 21.0f); float_equal(mat3x3_cofactor(a, 2, 1), 21.0f);
} }
@ -251,10 +251,10 @@ static bool matrices_test_16(const char ** scenario)
2.0f, 6.0f, 4.0f); 2.0f, 6.0f, 4.0f);
return return
float_equal(mat3x3_cofactor(&a, 0, 0), 56.0f) && float_equal(mat3x3_cofactor(a, 0, 0), 56.0f) &&
float_equal(mat3x3_cofactor(&a, 0, 1), 12.0f) && float_equal(mat3x3_cofactor(a, 0, 1), 12.0f) &&
float_equal(mat3x3_cofactor(&a, 0, 2), -46.0f) && float_equal(mat3x3_cofactor(a, 0, 2), -46.0f) &&
float_equal(mat3x3_determinant(&a), -196.0f); float_equal(mat3x3_determinant(a), -196.0f);
} }
static bool matrices_test_17(const char ** scenario) static bool matrices_test_17(const char ** scenario)
@ -267,11 +267,11 @@ static bool matrices_test_17(const char ** scenario)
-6.0f, 7.0f, 7.0f, -9.0f); -6.0f, 7.0f, 7.0f, -9.0f);
return return
float_equal(mat4x4_cofactor(&a, 0, 0), 690.0f) && float_equal(mat4x4_cofactor(a, 0, 0), 690.0f) &&
float_equal(mat4x4_cofactor(&a, 0, 1), 447.0f) && float_equal(mat4x4_cofactor(a, 0, 1), 447.0f) &&
float_equal(mat4x4_cofactor(&a, 0, 2), 210.0f) && float_equal(mat4x4_cofactor(a, 0, 2), 210.0f) &&
float_equal(mat4x4_cofactor(&a, 0, 3), 51.0f) && float_equal(mat4x4_cofactor(a, 0, 3), 51.0f) &&
float_equal(mat4x4_determinant(&a), -4071.0f); float_equal(mat4x4_determinant(a), -4071.0f);
} }
static bool matrices_test_18(const char ** scenario) static bool matrices_test_18(const char ** scenario)
@ -284,8 +284,8 @@ static bool matrices_test_18(const char ** scenario)
9.0f, 1.0f, 7.0f, -6.0f); 9.0f, 1.0f, 7.0f, -6.0f);
return return
float_equal(mat4x4_determinant(&a), -2120.0f) && float_equal(mat4x4_determinant(a), -2120.0f) &&
mat4x4_is_invertible(&a); mat4x4_is_invertible(a);
} }
static bool matrices_test_19(const char ** scenario) static bool matrices_test_19(const char ** scenario)
@ -298,8 +298,8 @@ static bool matrices_test_19(const char ** scenario)
0.0f, 0.0f, 0.0f, 0.0f); 0.0f, 0.0f, 0.0f, 0.0f);
return return
float_equal(mat4x4_determinant(&a), 0.0f) && float_equal(mat4x4_determinant(a), 0.0f) &&
!mat4x4_is_invertible(&a); !mat4x4_is_invertible(a);
} }
static bool matrices_test_20(const char ** scenario) static bool matrices_test_20(const char ** scenario)
@ -310,7 +310,7 @@ static bool matrices_test_20(const char ** scenario)
1.0, -5.0, 1.0, 8.0, 1.0, -5.0, 1.0, 8.0,
7.0, 7.0, -6.0, -7.0, 7.0, 7.0, -6.0, -7.0,
1.0, -3.0, 7.0, 4.0); 1.0, -3.0, 7.0, 4.0);
struct mat4x4 b = mat4x4_inverse(&a); struct mat4x4 b = mat4x4_inverse(a);
struct mat4x4 c = mat4x4( 0.218045f, 0.451128f, 0.240602f, -0.045113f, struct mat4x4 c = mat4x4( 0.218045f, 0.451128f, 0.240602f, -0.045113f,
-0.808271f, -1.456767f, -0.443609f, 0.520677f, -0.808271f, -1.456767f, -0.443609f, 0.520677f,
@ -318,12 +318,12 @@ static bool matrices_test_20(const char ** scenario)
-0.522564f, -0.813910f, -0.300752f, 0.306391f); -0.522564f, -0.813910f, -0.300752f, 0.306391f);
return return
float_equal(mat4x4_determinant(&a), 532.0f) && float_equal(mat4x4_determinant(a), 532.0f) &&
float_equal(mat4x4_cofactor(&a, 2, 3), -160.0f) && float_equal(mat4x4_cofactor(a, 2, 3), -160.0f) &&
float_equal(b.e[3][2], -160.0f/532.0f) && float_equal(b.e[3][2], -160.0f/532.0f) &&
float_equal(mat4x4_cofactor(&a, 3, 2), 105.0f) && float_equal(mat4x4_cofactor(a, 3, 2), 105.0f) &&
float_equal(b.e[2][3], 105.0f/532.0f) && float_equal(b.e[2][3], 105.0f/532.0f) &&
mat4x4_equal(&b, &c); mat4x4_equal(b, c);
} }
static bool matrices_test_21(const char ** scenario) static bool matrices_test_21(const char ** scenario)
@ -335,14 +335,14 @@ static bool matrices_test_21(const char ** scenario)
-6.0f, 0.0f, 9.0f, 6.0f, -6.0f, 0.0f, 9.0f, 6.0f,
-3.0f, 0.0f, -9.0f, -4.0f); -3.0f, 0.0f, -9.0f, -4.0f);
struct mat4x4 b = mat4x4_inverse(&a); struct mat4x4 b = mat4x4_inverse(a);
struct mat4x4 c = mat4x4(-0.15385f, -0.15385f, -0.28205f, -0.53846f, struct mat4x4 c = mat4x4(-0.15385f, -0.15385f, -0.28205f, -0.53846f,
-0.07692f, 0.12308f, 0.02564f, 0.03077f, -0.07692f, 0.12308f, 0.02564f, 0.03077f,
0.35897f, 0.35897f, 0.43590f, 0.92308f, 0.35897f, 0.35897f, 0.43590f, 0.92308f,
-0.69231f, -0.69231f, -0.76923f, -1.92308f); -0.69231f, -0.69231f, -0.76923f, -1.92308f);
return mat4x4_equal(&b, &c); return mat4x4_equal(b, c);
} }
static bool matrices_test_22(const char ** scenario) static bool matrices_test_22(const char ** scenario)
@ -354,14 +354,14 @@ static bool matrices_test_22(const char ** scenario)
-4.0f, 9.0f, 6.0f, 4.0f, -4.0f, 9.0f, 6.0f, 4.0f,
-7.0f, 6.0f, 6.0f, 2.0f); -7.0f, 6.0f, 6.0f, 2.0f);
struct mat4x4 b = mat4x4_inverse(&a); struct mat4x4 b = mat4x4_inverse(a);
struct mat4x4 c = mat4x4(-0.04074f, -0.07778f, 0.14444f, -0.22222f, struct mat4x4 c = mat4x4(-0.04074f, -0.07778f, 0.14444f, -0.22222f,
-0.07778f, 0.03333f, 0.36667f, -0.33333f, -0.07778f, 0.03333f, 0.36667f, -0.33333f,
-0.02901f, -0.14630f, -0.10926f, 0.12963f, -0.02901f, -0.14630f, -0.10926f, 0.12963f,
0.17778f, 0.06667f, -0.26667f, 0.33333f); 0.17778f, 0.06667f, -0.26667f, 0.33333f);
return mat4x4_equal(&b, &c); return mat4x4_equal(b, c);
} }
static bool matrices_test_23(const char ** scenario) static bool matrices_test_23(const char ** scenario)
@ -378,12 +378,12 @@ static bool matrices_test_23(const char ** scenario)
7.0f, 0.0f, 5.0f, 4.0f, 7.0f, 0.0f, 5.0f, 4.0f,
6.0f, -2.0f, 0.0f, 5.0f); 6.0f, -2.0f, 0.0f, 5.0f);
struct mat4x4 c = mat4x4_mul_m(&a, &b); struct mat4x4 c = mat4x4_mul_m(a, b);
struct mat4x4 b_i = mat4x4_inverse(&b); struct mat4x4 b_i = mat4x4_inverse(b);
struct mat4x4 d = mat4x4_mul_m(&c, &b_i); struct mat4x4 d = mat4x4_mul_m(c, b_i);
return mat4x4_equal(&d, &a); return mat4x4_equal(d, a);
} }
test_t matrices_tests[] = { test_t matrices_tests[] = {

86
test/test_planes.c Normal file
View File

@ -0,0 +1,86 @@
#include <stdbool.h>
#include <stdio.h>
#include "rays.h"
#include "planes.h"
#include "intersections_shapes.h"
#include "runner.h"
#include "matrices.h"
#include "transformations.h"
static bool planes_test_0(const char ** scenario)
{
*scenario = "The normal of a plane is constant everywhere";
struct tuple n1 = plane_normal_at(point(0.0f, 0.0f, 0.0f));
struct tuple n2 = plane_normal_at(point(10.0f, 0.0f, -10.0f));
struct tuple n3 = plane_normal_at(point(-5.0f, 0.0f, 150.0f));
return
tuple_equal(n1, vector(0.0f, 1.0f, 0.0f)) &&
tuple_equal(n2, vector(0.0f, 1.0f, 0.0f)) &&
tuple_equal(n3, vector(0.0f, 1.0f, 0.0f));
}
static bool planes_test_1(const char ** scenario)
{
*scenario = "Intersect with a ray parallel to the plane";
struct shape p = plane();
struct ray r = ray(point(0.0f, 10.0f, 0.0f), vector(0.0f, 0.0f, 1.0f));
struct intersections xs;
xs.count = 0;
plane_intersect(&p, r, &xs);
return xs.count == 0;
}
static bool planes_test_2(const char ** scenario)
{
*scenario = "Intersect with a coplanar ray";
struct shape p = plane();
struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f));
struct intersections xs;
xs.count = 0;
plane_intersect(&p, r, &xs);
return xs.count == 0;
}
static bool planes_test_3(const char ** scenario)
{
*scenario = "A ray intersecting a plane from above";
struct shape p = plane();
struct ray r = ray(point(0.0f, 1.0f, 0.0f), vector(0.0f, -1.0f, 0.0f));
struct intersections xs;
xs.count = 0;
plane_intersect(&p, r, &xs);
return
xs.count == 1 &&
float_equal(xs.i[0].t, 1.0f) &&
xs.i[0].object == &p;
}
static bool planes_test_4(const char ** scenario)
{
*scenario = "A ray intersecting a plane from below";
struct shape p = plane();
struct ray r = ray(point(0.0f, -1.0f, 0.0f), vector(0.0f, 1.0f, 1.0f));
struct intersections xs;
xs.count = 0;
plane_intersect(&p, r, &xs);
return
xs.count == 1 &&
float_equal(xs.i[0].t, 1.0f) &&
xs.i[0].object == &p;
}
test_t planes_tests[] = {
planes_test_0,
planes_test_1,
planes_test_2,
planes_test_3,
planes_test_4,
};
RUNNER(planes_tests);

View File

@ -38,7 +38,7 @@ static bool rays_test_2(const char ** scenario)
struct ray r = ray(point(1.0f, 2.0f, 3.0f), vector(0.0f, 1.0f, 0.0f)); struct ray r = ray(point(1.0f, 2.0f, 3.0f), vector(0.0f, 1.0f, 0.0f));
struct mat4x4 m = translation(3.0f, 4.0f, 5.0f); struct mat4x4 m = translation(3.0f, 4.0f, 5.0f);
struct ray r2 = ray_transform(r, &m); struct ray r2 = ray_transform(r, m);
return return
tuple_equal(r2.origin, point(4.0f, 6.0f, 8.0f)) && tuple_equal(r2.origin, point(4.0f, 6.0f, 8.0f)) &&
@ -51,7 +51,7 @@ static bool rays_test_3(const char ** scenario)
struct ray r = ray(point(1.0f, 2.0f, 3.0f), vector(0.0f, 1.0f, 0.0f)); struct ray r = ray(point(1.0f, 2.0f, 3.0f), vector(0.0f, 1.0f, 0.0f));
struct mat4x4 m = scaling(2.0f, 3.0f, 4.0f); struct mat4x4 m = scaling(2.0f, 3.0f, 4.0f);
struct ray r2 = ray_transform(r, &m); struct ray r2 = ray_transform(r, m);
return return
tuple_equal(r2.origin, point(2.0f, 6.0f, 12.0f)) && tuple_equal(r2.origin, point(2.0f, 6.0f, 12.0f)) &&

121
test/test_shapes.c Normal file
View File

@ -0,0 +1,121 @@
#include <stdbool.h>
#include <stdio.h>
#include "shapes.h"
#include "intersections_shapes.h"
#include "transformations.h"
#include "runner.h"
#include "rays.h"
#include "spheres.h"
static bool shapes_test_0(const char ** scenario)
{
*scenario = "A shape's default transformation";
struct shape s = shape();
struct mat4x4 identity = mat4x4_identity();
return mat4x4_equal(s.transform, identity);
}
static bool shapes_test_1(const char ** scenario)
{
*scenario = "Changing a shape's transformation";
struct shape s = shape();
struct mat4x4 t = translation(2.0f, 3.0f, 4.0f);
s.transform = t;
return mat4x4_equal(s.transform, t);
}
static bool shapes_test_2(const char ** scenario)
{
*scenario = "A shape has a default material";
struct shape s = shape();
struct material m = s.material;
return material_equal(m, material());
}
static bool shapes_test_3(const char ** scenario)
{
*scenario = "A shape may be assigned a material";
struct shape s = shape();
struct material m = material();
m.ambient = 1.0f;
s.material = m;
return material_equal(s.material, m);
}
static bool shapes_test_4(const char ** scenario)
{
*scenario = "Intersecting a scaled shape with a ray";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct shape s = shape();
s.transform = scaling(2.0f, 2.0f, 2.0f);
struct intersections xs;
xs.count = 0;
intersect(&s, r, &xs);
return
tuple_equal(intersections_saved_ray.origin, point(0.0f, 0.0f, -2.5f)) &&
tuple_equal(intersections_saved_ray.direction, vector(0.0f, 0.0f, 0.5f));
}
static bool shapes_test_5(const char ** scenario)
{
*scenario = "Intersecting a translated shape with a ray";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct shape s = shape();
s.transform = translation(5.0f, 0.0f, 0.0f);
struct intersections xs;
xs.count = 0;
intersect(&s, r, &xs);
return
tuple_equal(intersections_saved_ray.origin, point(-5.0f, 0.0f, -5.0f)) &&
tuple_equal(intersections_saved_ray.direction, vector(0.0f, 0.0f, 1.0f));
}
static bool shapes_test_6(const char ** scenario)
{
*scenario = "Computing the normal on a translated shape";
struct shape s = shape();
s.transform = translation(0.0f, 1.0f, 0.0f);
struct tuple n = normal_at(&s, point(0.0f, 1.70711f, -0.70711));
return tuple_equal(n, vector(0.0f, 0.70711f, -0.70711f));
}
static bool shapes_test_7(const char ** scenario)
{
*scenario = "Computing the normal on a transformed shape";
struct shape s = shape();
struct mat4x4 scale = scaling(1.0f, 0.5f, 1.0f);
struct mat4x4 rotate = rotation_z(pi / 5.0f);
struct mat4x4 m = mat4x4_mul_m(scale, rotate);
s.transform = m;
struct tuple n = normal_at(&s, point(0.0f, 0.7071067811865476, -0.7071067811865476));
return tuple_equal(n, vector(0.0f, 0.97014f, -0.24254f));
}
test_t shape_tests[] = {
shapes_test_0,
shapes_test_1,
shapes_test_2,
shapes_test_3,
shapes_test_4,
shapes_test_5,
shapes_test_6,
shapes_test_7,
};
RUNNER(shape_tests)

View File

@ -3,7 +3,7 @@
#include "rays.h" #include "rays.h"
#include "spheres.h" #include "spheres.h"
#include "intersections.h" #include "intersections_shapes.h"
#include "runner.h" #include "runner.h"
#include "matrices.h" #include "matrices.h"
#include "transformations.h" #include "transformations.h"
@ -13,7 +13,7 @@ static bool spheres_test_0(const char ** scenario)
*scenario = "A ray intersects a sphere at two points"; *scenario = "A ray intersects a sphere at two points";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
intersect(&s, r, &xs); intersect(&s, r, &xs);
@ -29,7 +29,7 @@ static bool spheres_test_1(const char ** scenario)
*scenario = "A ray intersects a sphere at a tangent"; *scenario = "A ray intersects a sphere at a tangent";
struct ray r = ray(point(0.0f, 1.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 1.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
intersect(&s, r, &xs); intersect(&s, r, &xs);
@ -45,7 +45,7 @@ static bool spheres_test_2(const char ** scenario)
*scenario = "A ray misses a sphere"; *scenario = "A ray misses a sphere";
struct ray r = ray(point(0.0f, 2.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 2.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
intersect(&s, r, &xs); intersect(&s, r, &xs);
@ -58,7 +58,7 @@ static bool spheres_test_3(const char ** scenario)
*scenario = "A ray originates in a sphere"; *scenario = "A ray originates in a sphere";
struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
intersect(&s, r, &xs); intersect(&s, r, &xs);
@ -74,7 +74,7 @@ static bool spheres_test_4(const char ** scenario)
*scenario = "A sphere is behind a ray"; *scenario = "A sphere is behind a ray";
struct ray r = ray(point(0.0f, 0.0f, 5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, 5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
intersect(&s, r, &xs); intersect(&s, r, &xs);
@ -90,7 +90,7 @@ static bool spheres_test_5(const char ** scenario)
*scenario = "Intersect sets the object on the intersection"; *scenario = "Intersect sets the object on the intersection";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
intersect(&s, r, &xs); intersect(&s, r, &xs);
@ -102,32 +102,11 @@ static bool spheres_test_5(const char ** scenario)
} }
static bool spheres_test_6(const char ** scenario) static bool spheres_test_6(const char ** scenario)
{
*scenario = "A sphere's default transformation";
struct sphere s = sphere();
struct mat4x4 identity = mat4x4_identity();
return mat4x4_equal(&s.transform, &identity);
}
static bool spheres_test_7(const char ** scenario)
{
*scenario = "Changing a sphere's transformation";
struct sphere s = sphere();
struct mat4x4 t = translation(2.0f, 3.0f, 4.0f);
s.transform = t;
return mat4x4_equal(&s.transform, &t);
}
static bool spheres_test_8(const char ** scenario)
{ {
*scenario = "Intersecting a scaled sphere with a ray"; *scenario = "Intersecting a scaled sphere with a ray";
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
s.transform = scaling(2.0f, 2.0f, 2.0f); s.transform = scaling(2.0f, 2.0f, 2.0f);
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
@ -139,12 +118,12 @@ static bool spheres_test_8(const char ** scenario)
float_equal(xs.i[1].t, 7.0f); float_equal(xs.i[1].t, 7.0f);
} }
static bool spheres_test_9(const char ** scenario) static bool spheres_test_7(const char ** scenario)
{ {
*scenario = "Intersecting a translated sphere with a ray"; *scenario = "Intersecting a translated sphere with a ray";
struct ray r = ray(point(0.0f, 0.0f, 5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, 5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere s = sphere(); struct shape s = sphere();
s.transform = translation(5.0f, 0.0f, 0.0f); s.transform = translation(5.0f, 0.0f, 0.0f);
struct intersections xs; struct intersections xs;
xs.count = 0; xs.count = 0;
@ -153,39 +132,39 @@ static bool spheres_test_9(const char ** scenario)
return xs.count == 0; return xs.count == 0;
} }
static bool spheres_test_10(const char ** scenario) static bool spheres_test_8(const char ** scenario)
{ {
*scenario = "The normal on a sphere at a point on the x axis"; *scenario = "The normal on a sphere at a point on the x axis";
struct sphere s = sphere(); struct shape s = sphere();
struct tuple n = sphere_normal_at(&s, point(1.0f, 0.0f, 0.0f)); struct tuple n = normal_at(&s, point(1.0f, 0.0f, 0.0f));
return tuple_equal(n, vector(1.0f, 0.0f, 0.0f)); return tuple_equal(n, vector(1.0f, 0.0f, 0.0f));
} }
static bool spheres_test_9(const char ** scenario)
{
*scenario = "The normal on a sphere at a point on the y axis";
struct shape s = sphere();
struct tuple n = normal_at(&s, point(0.0f, 1.0f, 0.0f));
return tuple_equal(n, vector(0.0f, 1.0f, 0.0f));
}
static bool spheres_test_10(const char ** scenario)
{
*scenario = "The normal on a sphere at a point on the z axis";
struct shape s = sphere();
struct tuple n = normal_at(&s, point(0.0f, 0.0f, 1.0f));
return tuple_equal(n, vector(0.0f, 0.0f, 1.0f));
}
static bool spheres_test_11(const char ** scenario) static bool spheres_test_11(const char ** scenario)
{
*scenario = "The normal on a sphere at a point on the y axis";
struct sphere s = sphere();
struct tuple n = sphere_normal_at(&s, point(0.0f, 1.0f, 0.0f));
return tuple_equal(n, vector(0.0f, 1.0f, 0.0f));
}
static bool spheres_test_12(const char ** scenario)
{
*scenario = "The normal on a sphere at a point on the z axis";
struct sphere s = sphere();
struct tuple n = sphere_normal_at(&s, point(0.0f, 0.0f, 1.0f));
return tuple_equal(n, vector(0.0f, 0.0f, 1.0f));
}
static bool spheres_test_13(const char ** scenario)
{ {
*scenario = "The normal on a sphere at a nonaxial point"; *scenario = "The normal on a sphere at a nonaxial point";
struct sphere s = sphere(); struct shape s = sphere();
struct tuple n = sphere_normal_at(&s, point(0.5773502691896257, struct tuple n = normal_at(&s, point(0.5773502691896257,
0.5773502691896257, 0.5773502691896257,
0.5773502691896257)); 0.5773502691896257));
return tuple_equal(n, vector(0.5773502691896257, return tuple_equal(n, vector(0.5773502691896257,
@ -193,63 +172,43 @@ static bool spheres_test_13(const char ** scenario)
0.5773502691896257)); 0.5773502691896257));
} }
static bool spheres_test_14(const char ** scenario) static bool spheres_test_12(const char ** scenario)
{ {
*scenario = "The normal is a normalized vector"; *scenario = "The normal is a normalized vector";
struct sphere s = sphere(); struct shape s = sphere();
struct tuple n = sphere_normal_at(&s, point(0.5773502691896257, struct tuple n = normal_at(&s, point(0.5773502691896257,
0.5773502691896257, 0.5773502691896257,
0.5773502691896257)); 0.5773502691896257));
return tuple_equal(n, tuple_normalize(n)); return tuple_equal(n, tuple_normalize(n));
} }
static bool spheres_test_15(const char ** scenario) static bool spheres_test_13(const char ** scenario)
{ {
*scenario = "Computing the normal on a translated sphere"; *scenario = "Computing the normal on a translated sphere";
struct sphere s = sphere(); struct shape s = sphere();
s.transform = translation(0.0f, 1.0f, 0.0f); s.transform = translation(0.0f, 1.0f, 0.0f);
struct tuple n = sphere_normal_at(&s, point(0.0f, 1.70711f, -0.70711)); struct tuple n = normal_at(&s, point(0.0f, 1.70711f, -0.70711));
return tuple_equal(n, vector(0.0f, 0.70711f, -0.70711f)); return tuple_equal(n, vector(0.0f, 0.70711f, -0.70711f));
} }
static bool spheres_test_16(const char ** scenario) static bool spheres_test_14(const char ** scenario)
{ {
*scenario = "Computing the normal on a transformed sphere"; *scenario = "Computing the normal on a transformed sphere";
struct sphere s = sphere(); struct shape s = sphere();
struct mat4x4 scale = scaling(1.0f, 0.5f, 1.0f); struct mat4x4 scale = scaling(1.0f, 0.5f, 1.0f);
struct mat4x4 rotate = rotation_z(pi / 5.0f); struct mat4x4 rotate = rotation_z(pi / 5.0f);
struct mat4x4 m = mat4x4_mul_m(&scale, &rotate); struct mat4x4 m = mat4x4_mul_m(scale, rotate);
s.transform = m; s.transform = m;
struct tuple n = sphere_normal_at(&s, point(0.0f, 0.7071067811865476, -0.7071067811865476)); struct tuple n = normal_at(&s, point(0.0f, 0.7071067811865476, -0.7071067811865476));
return tuple_equal(n, vector(0.0f, 0.97014f, -0.24254f)); return tuple_equal(n, vector(0.0f, 0.97014f, -0.24254f));
} }
static bool spheres_test_17(const char ** scenario)
{
*scenario = "A sphere has a default material";
struct sphere s = sphere();
struct material m = s.material;
return material_equal(m, material());
}
static bool spheres_test_18(const char ** scenario)
{
*scenario = "A sphere may be assigned a material";
struct sphere s = sphere();
struct material m = material();
m.ambient = 1.0f;
s.material = m;
return material_equal(s.material, m);
}
test_t spheres_tests[] = { test_t spheres_tests[] = {
spheres_test_0, spheres_test_0,
spheres_test_1, spheres_test_1,
@ -266,10 +225,6 @@ test_t spheres_tests[] = {
spheres_test_12, spheres_test_12,
spheres_test_13, spheres_test_13,
spheres_test_14, spheres_test_14,
spheres_test_15,
spheres_test_16,
spheres_test_17,
spheres_test_18,
}; };
RUNNER(spheres_tests); RUNNER(spheres_tests);

View File

@ -11,7 +11,7 @@ static bool transformations_test_0(const char ** scenario)
struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f);
struct tuple p = point(-3.0f, 4.0f, 5.0f); struct tuple p = point(-3.0f, 4.0f, 5.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 1.0f, 7.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 1.0f, 7.0f));
} }
static bool transformations_test_1(const char ** scenario) static bool transformations_test_1(const char ** scenario)
@ -19,10 +19,10 @@ static bool transformations_test_1(const char ** scenario)
*scenario = "Multiplying by the inverse of a translation matrix"; *scenario = "Multiplying by the inverse of a translation matrix";
struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f);
struct mat4x4 inv = mat4x4_inverse(&transform); struct mat4x4 inv = mat4x4_inverse(transform);
struct tuple p = point(-3.0f, 4.0f, 5.0f); struct tuple p = point(-3.0f, 4.0f, 5.0f);
return tuple_equal(mat4x4_mul_t(&inv, &p), point(-8.0f, 7.0f, 3.0f)); return tuple_equal(mat4x4_mul_t(inv, p), point(-8.0f, 7.0f, 3.0f));
} }
static bool transformations_test_2(const char ** scenario) static bool transformations_test_2(const char ** scenario)
@ -32,7 +32,7 @@ static bool transformations_test_2(const char ** scenario)
struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f);
struct tuple v = vector(-3.0f, 4.0f, 5.0f); struct tuple v = vector(-3.0f, 4.0f, 5.0f);
return tuple_equal(mat4x4_mul_t(&transform, &v), v); return tuple_equal(mat4x4_mul_t(transform, v), v);
} }
static bool transformations_test_3(const char ** scenario) static bool transformations_test_3(const char ** scenario)
@ -42,7 +42,7 @@ static bool transformations_test_3(const char ** scenario)
struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f);
struct tuple p = point(-4.0f, 6.0f, 8.0f); struct tuple p = point(-4.0f, 6.0f, 8.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(-8.0f, 18.0f, 32.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(-8.0f, 18.0f, 32.0f));
} }
static bool transformations_test_4(const char ** scenario) static bool transformations_test_4(const char ** scenario)
@ -52,7 +52,7 @@ static bool transformations_test_4(const char ** scenario)
struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f);
struct tuple v = vector(-4.0f, 6.0f, 8.0f); struct tuple v = vector(-4.0f, 6.0f, 8.0f);
return tuple_equal(mat4x4_mul_t(&transform, &v), vector(-8.0f, 18.0f, 32.0f)); return tuple_equal(mat4x4_mul_t(transform, v), vector(-8.0f, 18.0f, 32.0f));
} }
static bool transformations_test_5(const char ** scenario) static bool transformations_test_5(const char ** scenario)
@ -60,10 +60,10 @@ static bool transformations_test_5(const char ** scenario)
*scenario = "Multiplying by the inverse of a scaling matrix"; *scenario = "Multiplying by the inverse of a scaling matrix";
struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f);
struct mat4x4 inv = mat4x4_inverse(&transform); struct mat4x4 inv = mat4x4_inverse(transform);
struct tuple v = vector(-4.0f, 6.0f, 8.0f); struct tuple v = vector(-4.0f, 6.0f, 8.0f);
return tuple_equal(mat4x4_mul_t(&inv, &v), vector(-2.0f, 2.0f, 2.0f)); return tuple_equal(mat4x4_mul_t(inv, v), vector(-2.0f, 2.0f, 2.0f));
} }
static bool transformations_test_6(const char ** scenario) static bool transformations_test_6(const char ** scenario)
@ -73,7 +73,7 @@ static bool transformations_test_6(const char ** scenario)
struct mat4x4 transform = scaling(-1.0f, 1.0f, 1.0f); struct mat4x4 transform = scaling(-1.0f, 1.0f, 1.0f);
struct tuple p = point(2.0f, 3.0f, 4.0f); struct tuple p = point(2.0f, 3.0f, 4.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(-2.0f, 3.0f, 4.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(-2.0f, 3.0f, 4.0f));
} }
static bool transformations_test_7(const char ** scenario) static bool transformations_test_7(const char ** scenario)
@ -85,8 +85,8 @@ static bool transformations_test_7(const char ** scenario)
struct mat4x4 full_quarter = rotation_x(tau / 4); struct mat4x4 full_quarter = rotation_x(tau / 4);
return return
tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(0.0f, 0.7071067811865476, 0.7071067811865476)) && tuple_equal(mat4x4_mul_t(half_quarter, p), point(0.0f, 0.7071067811865476, 0.7071067811865476)) &&
tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(0.0f, 0.0f, 1.0f)); tuple_equal(mat4x4_mul_t(full_quarter, p), point(0.0f, 0.0f, 1.0f));
} }
static bool transformations_test_8(const char ** scenario) static bool transformations_test_8(const char ** scenario)
@ -98,8 +98,8 @@ static bool transformations_test_8(const char ** scenario)
struct mat4x4 full_quarter = rotation_y(tau / 4); struct mat4x4 full_quarter = rotation_y(tau / 4);
return return
tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(0.7071067811865476, 0.0f, 0.7071067811865476)) && tuple_equal(mat4x4_mul_t(half_quarter, p), point(0.7071067811865476, 0.0f, 0.7071067811865476)) &&
tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(1.0f, 0.0f, 0.0f)); tuple_equal(mat4x4_mul_t(full_quarter, p), point(1.0f, 0.0f, 0.0f));
} }
static bool transformations_test_9(const char ** scenario) static bool transformations_test_9(const char ** scenario)
@ -111,8 +111,8 @@ static bool transformations_test_9(const char ** scenario)
struct mat4x4 full_quarter = rotation_z(tau / 4); struct mat4x4 full_quarter = rotation_z(tau / 4);
return return
tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(-0.7071067811865476, 0.7071067811865476, 0.0f)) && tuple_equal(mat4x4_mul_t(half_quarter, p), point(-0.7071067811865476, 0.7071067811865476, 0.0f)) &&
tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(-1.0f, 0.0f, 0.0f)); tuple_equal(mat4x4_mul_t(full_quarter, p), point(-1.0f, 0.0f, 0.0f));
} }
static bool transformations_test_10(const char ** scenario) static bool transformations_test_10(const char ** scenario)
@ -122,7 +122,7 @@ static bool transformations_test_10(const char ** scenario)
struct mat4x4 transform = shearing(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); struct mat4x4 transform = shearing(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
struct tuple p = point(2.0f, 3.0f, 4.0f); struct tuple p = point(2.0f, 3.0f, 4.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(5.0f, 3.0f, 4.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(5.0f, 3.0f, 4.0f));
} }
static bool transformations_test_11(const char ** scenario) static bool transformations_test_11(const char ** scenario)
@ -132,7 +132,7 @@ static bool transformations_test_11(const char ** scenario)
struct mat4x4 transform = shearing(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); struct mat4x4 transform = shearing(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
struct tuple p = point(2.0f, 3.0f, 4.0f); struct tuple p = point(2.0f, 3.0f, 4.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(6.0f, 3.0f, 4.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(6.0f, 3.0f, 4.0f));
} }
static bool transformations_test_12(const char ** scenario) static bool transformations_test_12(const char ** scenario)
@ -142,7 +142,7 @@ static bool transformations_test_12(const char ** scenario)
struct mat4x4 transform = shearing(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); struct mat4x4 transform = shearing(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
struct tuple p = point(2.0f, 3.0f, 4.0f); struct tuple p = point(2.0f, 3.0f, 4.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 5.0f, 4.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 5.0f, 4.0f));
} }
static bool transformations_test_13(const char ** scenario) static bool transformations_test_13(const char ** scenario)
@ -152,7 +152,7 @@ static bool transformations_test_13(const char ** scenario)
struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
struct tuple p = point(2.0f, 3.0f, 4.0f); struct tuple p = point(2.0f, 3.0f, 4.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 7.0f, 4.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 7.0f, 4.0f));
} }
static bool transformations_test_14(const char ** scenario) static bool transformations_test_14(const char ** scenario)
@ -162,7 +162,7 @@ static bool transformations_test_14(const char ** scenario)
struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
struct tuple p = point(2.0f, 3.0f, 4.0f); struct tuple p = point(2.0f, 3.0f, 4.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 3.0f, 6.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 3.0f, 6.0f));
} }
static bool transformations_test_15(const char ** scenario) static bool transformations_test_15(const char ** scenario)
@ -172,7 +172,7 @@ static bool transformations_test_15(const char ** scenario)
struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
struct tuple p = point(2.0f, 3.0f, 4.0f); struct tuple p = point(2.0f, 3.0f, 4.0f);
return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 3.0f, 7.0f)); return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 3.0f, 7.0f));
} }
static bool transformations_test_16(const char ** scenario) static bool transformations_test_16(const char ** scenario)
@ -184,9 +184,9 @@ static bool transformations_test_16(const char ** scenario)
struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f); struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f);
struct mat4x4 c = translation(10.0f, 5.0f, 7.0f); struct mat4x4 c = translation(10.0f, 5.0f, 7.0f);
struct tuple p2 = mat4x4_mul_t(&a, &p); struct tuple p2 = mat4x4_mul_t(a, p);
struct tuple p3 = mat4x4_mul_t(&b, &p2); struct tuple p3 = mat4x4_mul_t(b, p2);
struct tuple p4 = mat4x4_mul_t(&c, &p3); struct tuple p4 = mat4x4_mul_t(c, p3);
return return
tuple_equal(p2, point(1.0f, -1.0f, 0.0f)) && tuple_equal(p2, point(1.0f, -1.0f, 0.0f)) &&
@ -203,9 +203,9 @@ static bool transformations_test_17(const char ** scenario)
struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f); struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f);
struct mat4x4 c = translation(10.0f, 5.0f, 7.0f); struct mat4x4 c = translation(10.0f, 5.0f, 7.0f);
struct mat4x4 t1 = mat4x4_mul_m(&c, &b); struct mat4x4 t1 = mat4x4_mul_m(c, b);
struct mat4x4 t2 = mat4x4_mul_m(&t1, &a); struct mat4x4 t2 = mat4x4_mul_m(t1, a);
struct tuple p1 = mat4x4_mul_t(&t2, &p); struct tuple p1 = mat4x4_mul_t(t2, p);
return tuple_equal(p1, point(15.0f, 0.0f, 7.0f)); return tuple_equal(p1, point(15.0f, 0.0f, 7.0f));
} }
@ -220,7 +220,7 @@ static bool transformations_test_18(const char ** scenario)
struct mat4x4 t = view_transform(from, to, up); struct mat4x4 t = view_transform(from, to, up);
struct mat4x4 identity_matrix = mat4x4_identity(); struct mat4x4 identity_matrix = mat4x4_identity();
return mat4x4_equal(&t, &identity_matrix); return mat4x4_equal(t, identity_matrix);
} }
static bool transformations_test_19(const char ** scenario) static bool transformations_test_19(const char ** scenario)
@ -233,7 +233,7 @@ static bool transformations_test_19(const char ** scenario)
struct mat4x4 t = view_transform(from, to, up); struct mat4x4 t = view_transform(from, to, up);
struct mat4x4 scaled = scaling(-1.0f, 1.0f, -1.0f); struct mat4x4 scaled = scaling(-1.0f, 1.0f, -1.0f);
return mat4x4_equal(&t, &scaled); return mat4x4_equal(t, scaled);
} }
static bool transformations_test_20(const char ** scenario) static bool transformations_test_20(const char ** scenario)
@ -246,7 +246,7 @@ static bool transformations_test_20(const char ** scenario)
struct mat4x4 t = view_transform(from, to, up); struct mat4x4 t = view_transform(from, to, up);
struct mat4x4 translated = translation(0.0f, 0.0f, -8.0f); struct mat4x4 translated = translation(0.0f, 0.0f, -8.0f);
return mat4x4_equal(&t, &translated); return mat4x4_equal(t, translated);
} }
static bool transformations_test_21(const char ** scenario) static bool transformations_test_21(const char ** scenario)
@ -263,7 +263,7 @@ static bool transformations_test_21(const char ** scenario)
-0.35857f, 0.59761f, -0.71714f, 0.00000f, -0.35857f, 0.59761f, -0.71714f, 0.00000f,
0.00000f, 0.00000f, 0.00000f, 1.00000f 0.00000f, 0.00000f, 0.00000f, 1.00000f
); );
return mat4x4_equal(&t, &expected); return mat4x4_equal(t, expected);
} }
test_t transformations_tests[] = { test_t transformations_tests[] = {

View File

@ -20,11 +20,11 @@ static bool world_test_1(const char ** scenario)
*scenario = "The default world"; *scenario = "The default world";
struct light light = point_light(point(-10.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f)); struct light light = point_light(point(-10.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
struct sphere s1 = sphere(); struct shape s1 = sphere();
s1.material.color = color(0.8f, 1.0f, 0.6f); s1.material.color = color(0.8f, 1.0f, 0.6f);
s1.material.diffuse = 0.7f; s1.material.diffuse = 0.7f;
s1.material.specular = 0.2f; s1.material.specular = 0.2f;
struct sphere s2 = sphere(); struct shape s2 = sphere();
s2.transform = scaling(0.5f, 0.5f, 0.5f); s2.transform = scaling(0.5f, 0.5f, 0.5f);
struct world w = world_default(); struct world w = world_default();
return return
@ -34,7 +34,7 @@ static bool world_test_1(const char ** scenario)
tuple_equal(w.objects[0].material.color, s1.material.color) && tuple_equal(w.objects[0].material.color, s1.material.color) &&
float_equal(w.objects[0].material.diffuse, s1.material.diffuse) && float_equal(w.objects[0].material.diffuse, s1.material.diffuse) &&
float_equal(w.objects[0].material.specular, s1.material.specular) && float_equal(w.objects[0].material.specular, s1.material.specular) &&
mat4x4_equal(&w.objects[1].transform, &s2.transform); mat4x4_equal(w.objects[1].transform, s2.transform);
} }
static bool world_test_2(const char ** scenario) static bool world_test_2(const char ** scenario)
@ -61,7 +61,7 @@ static bool world_test_3(const char ** scenario)
struct world w = world_default(); struct world w = world_default();
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere * shape = &w.objects[0]; struct shape * shape = &w.objects[0];
struct intersection i = intersection(4.0f, shape); struct intersection i = intersection(4.0f, shape);
struct computations comps = prepare_computations(i, r); struct computations comps = prepare_computations(i, r);
struct tuple c = world_shade_hit(&w, &comps); struct tuple c = world_shade_hit(&w, &comps);
@ -76,7 +76,7 @@ static bool world_test_4(const char ** scenario)
struct world w = world_default(); struct world w = world_default();
w.light = point_light(point(0.0f, 0.25f, 0.0f), color(1.0f, 1.0f, 1.0f)); w.light = point_light(point(0.0f, 0.25f, 0.0f), color(1.0f, 1.0f, 1.0f));
struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f));
struct sphere * shape = &w.objects[1]; struct shape * shape = &w.objects[1];
struct intersection i = intersection(0.5f, shape); struct intersection i = intersection(0.5f, shape);
struct computations comps = prepare_computations(i, r); struct computations comps = prepare_computations(i, r);
struct tuple c = world_shade_hit(&w, &comps); struct tuple c = world_shade_hit(&w, &comps);
@ -111,9 +111,9 @@ static bool world_test_7(const char ** scenario)
*scenario = "The color with an intersection behind the ray"; *scenario = "The color with an intersection behind the ray";
struct world w = world_default(); struct world w = world_default();
struct sphere * outer = &w.objects[0]; struct shape * outer = &w.objects[0];
outer->material.ambient = 1.0f; outer->material.ambient = 1.0f;
struct sphere * inner = &w.objects[1]; struct shape * inner = &w.objects[1];
inner->material.ambient = 1.0f; inner->material.ambient = 1.0f;
struct ray r = ray(point(0.0f, 0.0f, 0.75f), vector(0.0f, 0.0f, -1.0f)); struct ray r = ray(point(0.0f, 0.0f, 0.75f), vector(0.0f, 0.0f, -1.0f));
struct tuple c = world_color_at(&w, r); struct tuple c = world_color_at(&w, r);
@ -167,9 +167,9 @@ static bool world_test_12(const char ** scenario)
struct world w = world(); struct world w = world();
w.light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f)); w.light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
struct sphere s1 = sphere(); struct shape s1 = sphere();
w.objects[0] = s1; w.objects[0] = s1;
struct sphere s2 = sphere(); struct shape s2 = sphere();
s2.transform = translation(0.0f, 0.0f, 10.0f); s2.transform = translation(0.0f, 0.0f, 10.0f);
w.objects[1] = s2; w.objects[1] = s2;
w.object_count = 2; w.object_count = 2;

View File

@ -70,5 +70,5 @@ inline static struct mat4x4 view_transform(struct tuple from,
0.0f, 0.0f, 0.0f, 1.0f); 0.0f, 0.0f, 0.0f, 1.0f);
struct mat4x4 translate = translation(-from.x, -from.y, -from.z); struct mat4x4 translate = translation(-from.x, -from.y, -from.z);
return mat4x4_mul_m(&orientation, &translate); return mat4x4_mul_m(orientation, translate);
} }

View File

@ -3,7 +3,7 @@
#include "lights.h" #include "lights.h"
#include "spheres.h" #include "spheres.h"
#include "transformations.h" #include "transformations.h"
#include "intersections.h" #include "intersections_shapes.h"
#include "rays.h" #include "rays.h"
#include "materials.h" #include "materials.h"
@ -12,7 +12,7 @@
struct world { struct world {
struct light light; struct light light;
int object_count; int object_count;
struct sphere objects[WORLD_MAX_OBJECTS]; struct shape objects[WORLD_MAX_OBJECTS];
}; };
inline static struct world world() inline static struct world world()
@ -25,11 +25,11 @@ inline static struct world world()
inline static struct world world_default() inline static struct world world_default()
{ {
struct sphere s1 = sphere(); struct shape s1 = sphere();
s1.material.color = color(0.8f, 1.0f, 0.6f); s1.material.color = color(0.8f, 1.0f, 0.6f);
s1.material.diffuse = 0.7f; s1.material.diffuse = 0.7f;
s1.material.specular = 0.2f; s1.material.specular = 0.2f;
struct sphere s2 = sphere(); struct shape s2 = sphere();
s2.transform = scaling(0.5f, 0.5f, 0.5f); s2.transform = scaling(0.5f, 0.5f, 0.5f);
return (struct world){ return (struct world){