7 wip
This commit is contained in:
parent
15ac0aa031
commit
f1b8b66c95
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@ test/test_rays
|
|||||||
test/test_lights
|
test/test_lights
|
||||||
test/test_materials
|
test/test_materials
|
||||||
test/test_spheres
|
test/test_spheres
|
||||||
|
test/test_world
|
||||||
raytracer
|
raytracer
|
||||||
*.ppm
|
*.ppm
|
||||||
*.png
|
*.png
|
114
intersections.h
114
intersections.h
@ -1,11 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "spheres.h"
|
#include "spheres.h"
|
||||||
#include "rays.h"
|
#include "rays.h"
|
||||||
|
|
||||||
struct intersection {
|
struct intersection {
|
||||||
float t;
|
float t;
|
||||||
struct sphere const * const object;
|
struct sphere const * object;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intersection intersection(float t, struct sphere const * const object)
|
struct intersection intersection(float t, struct sphere const * const object)
|
||||||
@ -13,32 +16,26 @@ struct intersection intersection(float t, struct sphere const * const object)
|
|||||||
return (struct intersection){ t, object };
|
return (struct intersection){ t, object };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_INTERSECTIONS 1024
|
||||||
|
|
||||||
struct intersections {
|
struct intersections {
|
||||||
int count;
|
int count;
|
||||||
struct intersection i[];
|
struct intersection i[MAX_INTERSECTIONS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct intersections2 {
|
inline static void intersections(struct intersections * intersections, int count, ...)
|
||||||
int count;
|
|
||||||
struct intersection i[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct intersections4 {
|
|
||||||
int count;
|
|
||||||
struct intersection i[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct intersections2 intersections2(struct intersection a, struct intersection b)
|
|
||||||
{
|
{
|
||||||
return (struct intersections2){ 2, {a, b} };
|
va_list ap;
|
||||||
|
va_start(ap, count);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
intersections->i[i] = va_arg(ap, struct intersection);
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
intersections->count = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct intersections4 intersections4(struct intersection a, struct intersection b, struct intersection c, struct intersection d)
|
inline static void intersect(struct sphere const * const s, struct ray r, struct intersections * intersections)
|
||||||
{
|
|
||||||
return (struct intersections4){ 4, {a, b, c, d} };
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static struct intersections2 intersect(struct sphere const * const s, struct ray r)
|
|
||||||
{
|
{
|
||||||
struct mat4x4 m = mat4x4_inverse(&s->transform);
|
struct mat4x4 m = mat4x4_inverse(&s->transform);
|
||||||
struct ray r2 = ray_transform(r, &m);
|
struct ray r2 = ray_transform(r, &m);
|
||||||
@ -51,15 +48,16 @@ inline static struct intersections2 intersect(struct sphere const * const s, str
|
|||||||
float discriminant = b * b - 4 * a * c;
|
float discriminant = b * b - 4 * a * c;
|
||||||
|
|
||||||
if (discriminant < 0) {
|
if (discriminant < 0) {
|
||||||
return (struct intersections2) { 0 };
|
return;
|
||||||
} else {
|
} else {
|
||||||
float root = sqrtf(discriminant);
|
float root = sqrtf(discriminant);
|
||||||
float t1 = (-b - root) / (2 * a);
|
float t1 = (-b - root) / (2 * a);
|
||||||
float t2 = (-b + root) / (2 * a);
|
float t2 = (-b + root) / (2 * a);
|
||||||
|
|
||||||
return
|
intersections->i[intersections->count++] = intersection(t1, s);
|
||||||
intersections2(intersection(t1, s),
|
intersections->i[intersections->count++] = intersection(t2, s);
|
||||||
intersection(t2, s));
|
assert(intersections->count < MAX_INTERSECTIONS);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,3 +72,71 @@ inline static struct intersection * hit(struct intersections * xs)
|
|||||||
}
|
}
|
||||||
return i;
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (struct computations){
|
||||||
|
intersection.t,
|
||||||
|
intersection.object,
|
||||||
|
point,
|
||||||
|
eyev,
|
||||||
|
normalv,
|
||||||
|
inside
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -eux
|
set -eux
|
||||||
|
|
||||||
for name in tuples canvas matrices transformations rays intersections spheres lights materials; do
|
for name in tuples canvas matrices transformations rays intersections spheres lights materials world; do
|
||||||
gcc -g -gdwarf-5 \
|
gcc -g -gdwarf-5 \
|
||||||
-Wall -Werror -Wfatal-errors \
|
-Wall -Werror -Wfatal-errors \
|
||||||
-I. \
|
-I. \
|
||||||
|
@ -18,12 +18,13 @@ static bool intersections_test_0(const char ** scenario)
|
|||||||
|
|
||||||
static bool intersections_test_1(const char ** scenario)
|
static bool intersections_test_1(const char ** scenario)
|
||||||
{
|
{
|
||||||
*scenario = "Aggregating intersections2";
|
*scenario = "Aggregating intersections";
|
||||||
|
|
||||||
struct sphere s = sphere();
|
struct sphere 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 intersections2 xs = intersections2(i1, i2);
|
struct intersections xs;
|
||||||
|
intersections(&xs, 2, i1, i2);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 2 &&
|
xs.count == 2 &&
|
||||||
@ -33,12 +34,13 @@ static bool intersections_test_1(const char ** scenario)
|
|||||||
|
|
||||||
static bool intersections_test_2(const char ** scenario)
|
static bool intersections_test_2(const char ** scenario)
|
||||||
{
|
{
|
||||||
*scenario = "The hit, when all intersections2 have positive t";
|
*scenario = "The hit, when all intersections have positive t";
|
||||||
|
|
||||||
struct sphere s = sphere();
|
struct sphere 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 intersections2 xs = intersections2(i2, i1);
|
struct intersections xs;
|
||||||
|
intersections(&xs, 2, i2, i1);
|
||||||
|
|
||||||
struct intersection * i = hit((struct intersections *)&xs);
|
struct intersection * i = hit((struct intersections *)&xs);
|
||||||
|
|
||||||
@ -50,12 +52,13 @@ static bool intersections_test_2(const char ** scenario)
|
|||||||
|
|
||||||
static bool intersections_test_3(const char ** scenario)
|
static bool intersections_test_3(const char ** scenario)
|
||||||
{
|
{
|
||||||
*scenario = "The hit, when some intersections2 have negative t";
|
*scenario = "The hit, when some intersections have negative t";
|
||||||
|
|
||||||
struct sphere s = sphere();
|
struct sphere 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 intersections2 xs = intersections2(i2, i1);
|
struct intersections xs;
|
||||||
|
intersections(&xs, 2, i2, i1);
|
||||||
|
|
||||||
struct intersection * i = hit((struct intersections *)&xs);
|
struct intersection * i = hit((struct intersections *)&xs);
|
||||||
|
|
||||||
@ -67,12 +70,13 @@ static bool intersections_test_3(const char ** scenario)
|
|||||||
|
|
||||||
static bool intersections_test_4(const char ** scenario)
|
static bool intersections_test_4(const char ** scenario)
|
||||||
{
|
{
|
||||||
*scenario = "The hit, when all intersections2 have negative t";
|
*scenario = "The hit, when all intersections have negative t";
|
||||||
|
|
||||||
struct sphere s = sphere();
|
struct sphere 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 intersections2 xs = intersections2(i2, i1);
|
struct intersections xs;
|
||||||
|
intersections(&xs, 2, i2, i1);
|
||||||
|
|
||||||
struct intersection * i = hit((struct intersections *)&xs);
|
struct intersection * i = hit((struct intersections *)&xs);
|
||||||
|
|
||||||
@ -88,7 +92,8 @@ static bool intersections_test_5(const char ** scenario)
|
|||||||
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);
|
||||||
struct intersection i4 = intersection( 2.0f, &s);
|
struct intersection i4 = intersection( 2.0f, &s);
|
||||||
struct intersections4 xs = intersections4(i1, i2, i3, i4);
|
struct intersections xs;
|
||||||
|
intersections(&xs, 4, i1, i2, i3, i4);
|
||||||
|
|
||||||
struct intersection * i = hit((struct intersections *)&xs);
|
struct intersection * i = hit((struct intersections *)&xs);
|
||||||
|
|
||||||
@ -98,6 +103,84 @@ static bool intersections_test_5(const char ** scenario)
|
|||||||
i->object == i4.object;
|
i->object == i4.object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool intersections_test_6(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "In-place ascending sort of intersections";
|
||||||
|
|
||||||
|
struct sphere s1 = sphere();
|
||||||
|
s1.material.ambient = 1.0f;
|
||||||
|
struct sphere s2 = sphere();
|
||||||
|
s2.material.ambient = 2.0f;
|
||||||
|
struct sphere s3 = sphere();
|
||||||
|
s3.material.ambient = 3.0f;
|
||||||
|
struct sphere s4 = sphere();
|
||||||
|
s4.material.ambient = 4.0f;
|
||||||
|
struct intersection i1 = intersection( 5.0f, &s1);
|
||||||
|
struct intersection i2 = intersection( 7.0f, &s2);
|
||||||
|
struct intersection i3 = intersection(-3.0f, &s3);
|
||||||
|
struct intersection i4 = intersection( 2.0f, &s4);
|
||||||
|
struct intersections xs;
|
||||||
|
intersections(&xs, 4, i1, i2, i3, i4);
|
||||||
|
|
||||||
|
intersections_sort(&xs);
|
||||||
|
|
||||||
|
return
|
||||||
|
float_equal(xs.i[0].t, -3.0f) &&
|
||||||
|
float_equal(xs.i[0].object->material.ambient, 3.0f) &&
|
||||||
|
float_equal(xs.i[1].t, 2.0f) &&
|
||||||
|
float_equal(xs.i[1].object->material.ambient, 4.0f) &&
|
||||||
|
float_equal(xs.i[2].t, 5.0f) &&
|
||||||
|
float_equal(xs.i[2].object->material.ambient, 1.0f) &&
|
||||||
|
float_equal(xs.i[3].t, 7.0f) &&
|
||||||
|
float_equal(xs.i[3].object->material.ambient, 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool intersections_test_7(const char ** scenario)
|
||||||
|
{
|
||||||
|
*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 sphere shape = sphere();
|
||||||
|
struct intersection i = intersection(4.0f, &shape);
|
||||||
|
struct computations comps = prepare_computations(i, r);
|
||||||
|
|
||||||
|
return
|
||||||
|
float_equal(comps.t, i.t) &&
|
||||||
|
comps.object == &shape &&
|
||||||
|
tuple_equal(comps.point, point(0.0f, 0.0f, -1.0f)) &&
|
||||||
|
tuple_equal(comps.eyev, vector(0.0f, 0.0f, -1.0f)) &&
|
||||||
|
tuple_equal(comps.normalv, vector(0.0f, 0.0f, -1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool intersections_test_8(const char ** scenario)
|
||||||
|
{
|
||||||
|
*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 sphere shape = sphere();
|
||||||
|
struct intersection i = intersection(4.0f, &shape);
|
||||||
|
struct computations comps = prepare_computations(i, r);
|
||||||
|
|
||||||
|
return
|
||||||
|
comps.inside == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool intersections_test_9(const char ** scenario)
|
||||||
|
{
|
||||||
|
*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 sphere shape = sphere();
|
||||||
|
struct intersection i = intersection(1.0f, &shape);
|
||||||
|
struct computations comps = prepare_computations(i, r);
|
||||||
|
|
||||||
|
return
|
||||||
|
tuple_equal(comps.point, point(0.0f, 0.0f, 1.0f)) &&
|
||||||
|
tuple_equal(comps.eyev, vector(0.0f, 0.0f, -1.0f)) &&
|
||||||
|
comps.inside == true &&
|
||||||
|
tuple_equal(comps.normalv, vector(0.0f, 0.0f, -1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
test_t intersections_tests[] = {
|
test_t intersections_tests[] = {
|
||||||
intersections_test_0,
|
intersections_test_0,
|
||||||
intersections_test_1,
|
intersections_test_1,
|
||||||
@ -105,6 +188,10 @@ test_t intersections_tests[] = {
|
|||||||
intersections_test_3,
|
intersections_test_3,
|
||||||
intersections_test_4,
|
intersections_test_4,
|
||||||
intersections_test_5,
|
intersections_test_5,
|
||||||
|
intersections_test_6,
|
||||||
|
intersections_test_7,
|
||||||
|
intersections_test_8,
|
||||||
|
intersections_test_9,
|
||||||
};
|
};
|
||||||
|
|
||||||
RUNNER(intersections_tests);
|
RUNNER(intersections_tests);
|
||||||
|
@ -14,7 +14,9 @@ static bool spheres_test_0(const char ** scenario)
|
|||||||
|
|
||||||
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 sphere s = sphere();
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 2 &&
|
xs.count == 2 &&
|
||||||
@ -28,7 +30,9 @@ static bool spheres_test_1(const char ** scenario)
|
|||||||
|
|
||||||
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 sphere s = sphere();
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 2 &&
|
xs.count == 2 &&
|
||||||
@ -42,7 +46,9 @@ static bool spheres_test_2(const char ** scenario)
|
|||||||
|
|
||||||
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 sphere s = sphere();
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return xs.count == 0;
|
return xs.count == 0;
|
||||||
}
|
}
|
||||||
@ -53,7 +59,9 @@ static bool spheres_test_3(const char ** scenario)
|
|||||||
|
|
||||||
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 sphere s = sphere();
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 2 &&
|
xs.count == 2 &&
|
||||||
@ -67,7 +75,9 @@ static bool spheres_test_4(const char ** scenario)
|
|||||||
|
|
||||||
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 sphere s = sphere();
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 2 &&
|
xs.count == 2 &&
|
||||||
@ -81,7 +91,9 @@ static bool spheres_test_5(const char ** scenario)
|
|||||||
|
|
||||||
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 sphere s = sphere();
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 2 &&
|
xs.count == 2 &&
|
||||||
@ -117,7 +129,9 @@ static bool spheres_test_8(const char ** scenario)
|
|||||||
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 sphere s = sphere();
|
||||||
s.transform = scaling(2.0f, 2.0f, 2.0f);
|
s.transform = scaling(2.0f, 2.0f, 2.0f);
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 2 &&
|
xs.count == 2 &&
|
||||||
@ -132,7 +146,9 @@ static bool spheres_test_9(const char ** scenario)
|
|||||||
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 sphere s = sphere();
|
||||||
s.transform = translation(5.0f, 0.0f, 0.0f);
|
s.transform = translation(5.0f, 0.0f, 0.0f);
|
||||||
struct intersections2 xs = intersect(&s, r);
|
struct intersections xs;
|
||||||
|
xs.count = 0;
|
||||||
|
intersect(&s, r, &xs);
|
||||||
|
|
||||||
return xs.count == 0;
|
return xs.count == 0;
|
||||||
}
|
}
|
||||||
|
135
test/test_world.c
Normal file
135
test/test_world.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "world.h"
|
||||||
|
#include "runner.h"
|
||||||
|
|
||||||
|
static bool world_test_0(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "Creating a world";
|
||||||
|
|
||||||
|
struct world w = world();
|
||||||
|
|
||||||
|
return
|
||||||
|
w.object_count == 0 &&
|
||||||
|
tuple_equal(w.light.intensity, tuple(0.0f, 0.0f, 0.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_1(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "The default world";
|
||||||
|
|
||||||
|
struct light light = point_light(point(-10.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
|
struct sphere s1 = sphere();
|
||||||
|
s1.material.color = color(0.8f, 1.0f, 0.6f);
|
||||||
|
s1.material.diffuse = 0.7f;
|
||||||
|
s1.material.specular = 0.2f;
|
||||||
|
struct sphere s2 = sphere();
|
||||||
|
s2.transform = scaling(0.5f, 0.5f, 0.5f);
|
||||||
|
struct world w = default_world();
|
||||||
|
return
|
||||||
|
tuple_equal(w.light.position, light.position) &&
|
||||||
|
tuple_equal(w.light.intensity, light.intensity) &&
|
||||||
|
w.object_count == 2 &&
|
||||||
|
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.specular, s1.material.specular) &&
|
||||||
|
mat4x4_equal(&w.objects[1].transform, &s2.transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_2(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "Intersect a world with a ray";
|
||||||
|
|
||||||
|
struct world w = default_world();
|
||||||
|
|
||||||
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
|
struct intersections xs;
|
||||||
|
intersect_world(&w, r, &xs);
|
||||||
|
|
||||||
|
return
|
||||||
|
xs.count == 4 &&
|
||||||
|
float_equal(xs.i[0].t, 4.0f) &&
|
||||||
|
float_equal(xs.i[1].t, 4.5f) &&
|
||||||
|
float_equal(xs.i[2].t, 5.5f) &&
|
||||||
|
float_equal(xs.i[3].t, 6.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_3(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "Shading an intersection";
|
||||||
|
|
||||||
|
struct world w = default_world();
|
||||||
|
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 intersection i = intersection(4.0f, shape);
|
||||||
|
struct computations comps = prepare_computations(i, r);
|
||||||
|
struct tuple c = shade_hit(&w, &comps);
|
||||||
|
|
||||||
|
return tuple_equal(c, color(0.38066, 0.47583, 0.2855));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_4(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "Shading an intersection from the inside";
|
||||||
|
|
||||||
|
struct world w = default_world();
|
||||||
|
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 sphere * shape = &w.objects[1];
|
||||||
|
struct intersection i = intersection(0.5f, shape);
|
||||||
|
struct computations comps = prepare_computations(i, r);
|
||||||
|
struct tuple c = shade_hit(&w, &comps);
|
||||||
|
|
||||||
|
return tuple_equal(c, color(0.90498, 0.90498, 0.90498));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_5(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "The color when a ray misses";
|
||||||
|
|
||||||
|
struct world w = default_world();
|
||||||
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 1.0f, 0.0f));
|
||||||
|
struct tuple c = color_at(&w, r);
|
||||||
|
|
||||||
|
return tuple_equal(c, color(0.0f, 0.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_6(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "The color when a ray hits";
|
||||||
|
|
||||||
|
struct world w = default_world();
|
||||||
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
|
struct tuple c = color_at(&w, r);
|
||||||
|
|
||||||
|
return tuple_equal(c, color(0.38066f, 0.47583f, 0.2855f));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_7(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "The color with an intersection behind the ray";
|
||||||
|
|
||||||
|
struct world w = default_world();
|
||||||
|
struct sphere * outer = &w.objects[0];
|
||||||
|
outer->material.ambient = 1.0f;
|
||||||
|
struct sphere * inner = &w.objects[1];
|
||||||
|
inner->material.ambient = 1.0f;
|
||||||
|
struct ray r = ray(point(0.0f, 0.0f, 0.75f), vector(0.0f, 0.0f, -1.0f));
|
||||||
|
struct tuple c = color_at(&w, r);
|
||||||
|
|
||||||
|
return tuple_equal(c, inner->material.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_t world_tests[] = {
|
||||||
|
world_test_0,
|
||||||
|
world_test_1,
|
||||||
|
world_test_2,
|
||||||
|
world_test_3,
|
||||||
|
world_test_4,
|
||||||
|
world_test_5,
|
||||||
|
world_test_6,
|
||||||
|
world_test_7,
|
||||||
|
};
|
||||||
|
|
||||||
|
RUNNER(world_tests)
|
73
world.h
Normal file
73
world.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lights.h"
|
||||||
|
#include "spheres.h"
|
||||||
|
#include "transformations.h"
|
||||||
|
#include "intersections.h"
|
||||||
|
#include "rays.h"
|
||||||
|
#include "materials.h"
|
||||||
|
|
||||||
|
#define WORLD_MAX_OBJECTS 128
|
||||||
|
|
||||||
|
struct world {
|
||||||
|
struct light light;
|
||||||
|
int object_count;
|
||||||
|
struct sphere objects[WORLD_MAX_OBJECTS];
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static struct world world()
|
||||||
|
{
|
||||||
|
return (struct world){
|
||||||
|
.light = (struct light){{{{0}}}},
|
||||||
|
.object_count = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static struct world default_world()
|
||||||
|
{
|
||||||
|
struct sphere s1 = sphere();
|
||||||
|
s1.material.color = color(0.8f, 1.0f, 0.6f);
|
||||||
|
s1.material.diffuse = 0.7f;
|
||||||
|
s1.material.specular = 0.2f;
|
||||||
|
struct sphere s2 = sphere();
|
||||||
|
s2.transform = scaling(0.5f, 0.5f, 0.5f);
|
||||||
|
|
||||||
|
return (struct world){
|
||||||
|
.light = point_light(point(-10.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f)),
|
||||||
|
.object_count = 2,
|
||||||
|
.objects = { s1, s2 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void intersect_world(struct world * world, struct ray ray, struct intersections * intersections)
|
||||||
|
{
|
||||||
|
intersections->count = 0;
|
||||||
|
for (int i = 0; i < world->object_count; i++) {
|
||||||
|
intersect(&world->objects[i], ray, intersections);
|
||||||
|
}
|
||||||
|
intersections_sort(intersections);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static struct tuple shade_hit(struct world * world, struct computations * computations)
|
||||||
|
{
|
||||||
|
struct tuple color = lighting(computations->object->material,
|
||||||
|
world->light,
|
||||||
|
computations->point,
|
||||||
|
computations->eyev,
|
||||||
|
computations->normalv);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static struct tuple color_at(struct world * world, struct ray ray)
|
||||||
|
{
|
||||||
|
struct intersections xs;
|
||||||
|
intersect_world(world, ray, &xs);
|
||||||
|
if (xs.count >= 1) {
|
||||||
|
struct intersection i = *hit(&xs);
|
||||||
|
struct computations computations = prepare_computations(i, ray);
|
||||||
|
struct tuple color = shade_hit(world, &computations);
|
||||||
|
return color;
|
||||||
|
} else {
|
||||||
|
return color(0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user