144 lines
3.2 KiB
C
144 lines
3.2 KiB
C
#pragma once
|
|
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "spheres.h"
|
|
#include "rays.h"
|
|
|
|
struct intersection {
|
|
float t;
|
|
struct sphere const * object;
|
|
};
|
|
|
|
struct intersection intersection(float t, struct sphere const * const object)
|
|
{
|
|
return (struct intersection){ t, object };
|
|
}
|
|
|
|
#define MAX_INTERSECTIONS 1024
|
|
|
|
struct intersections {
|
|
int count;
|
|
struct intersection i[MAX_INTERSECTIONS];
|
|
};
|
|
|
|
inline static void intersections(struct intersections * intersections, int count, ...)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
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
|
|
};
|
|
}
|