raytracer-c/module_shapes/triangle.c
2020-10-23 23:41:36 -04:00

170 lines
6.0 KiB
C

#include "triangle.h"
#include <assert.h>
#include <exceptions.h>
void TRIANGLE_bounds_of(const SHAPE_Shape *shape, BOUND_Box *box) {
assert(shape);
assert(box);
TRIANGLE_Triangle *triangle = (TRIANGLE_Triangle *)shape;
BOUND_init(box);
BOUND_add_point_from_tuple(box, &triangle->p1);
BOUND_add_point_from_tuple(box, &triangle->p2);
BOUND_add_point_from_tuple(box, &triangle->p3);
}
const SHAPE_vtable TRIANGLE_vtable = {&TRIANGLE_local_intersect, &TRIANGLE_delete_shape, &TRIANGLE_local_normal_at,
&SHAPE_default_shape_contains, &TRIANGLE_bounds_of, NULL};
const SHAPE_vtable TRIANGLE_smooth_vtable = {&TRIANGLE_local_intersect, &TRIANGLE_delete_shape, &TRIANGLE_smooth_local_normal_at,
&SHAPE_default_shape_contains, &TRIANGLE_bounds_of, NULL};
TRIANGLE_Triangle *TRIANGLE_new_from_points(const TUPLES_Point *p1, const TUPLES_Point *p2, const TUPLES_Point *p3) {
return TRIANGLE_new(p1->x, p1->y, p1->z, p2->x, p2->y, p2->z, p3->x, p3->y, p3->z);
}
TRIANGLE_Triangle *TRIANGLE_new(double p1x, double p1y, double p1z, double p2x, double p2y, double p2z, double p3x, double p3y, double p3z) {
TRIANGLE_Triangle *t = malloc(sizeof(TRIANGLE_Triangle));
if (!t) {
Throw(E_MALLOC_FAILED);
}
TRIANGLE_init(t, p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z);
return t;
}
void TRIANGLE_init_from_points(TRIANGLE_Triangle *triangle, const TUPLES_Point *p1, const TUPLES_Point *p2, const TUPLES_Point *p3) {
assert(triangle);
TRIANGLE_init(triangle, p1->x, p1->y, p1->z, p2->x, p2->y, p2->z, p3->x, p3->y, p3->z);
}
static void init_base_triangle_info(TRIANGLE_Triangle *triangle, double p1x, double p1y, double p1z, double p2x, double p2y, double p2z, double p3x, double p3y,
double p3z) {
assert(triangle);
TUPLES_init_point(&triangle->p1, p1x, p1y, p1z);
TUPLES_init_point(&triangle->p2, p2x, p2y, p2z);
TUPLES_init_point(&triangle->p3, p3x, p3y, p3z);
TUPLES_subtract(&triangle->e1, &triangle->p2, &triangle->p1);
TUPLES_subtract(&triangle->e2, &triangle->p3, &triangle->p1);
TUPLES_cross(&triangle->normal, &triangle->e2, &triangle->e1);
TUPLES_normalize(&triangle->normal);
}
void TRIANGLE_init(TRIANGLE_Triangle *triangle, double p1x, double p1y, double p1z, double p2x, double p2y, double p2z, double p3x, double p3y, double p3z) {
assert(triangle);
SHAPE_init(&triangle->shape, &TRIANGLE_vtable);
init_base_triangle_info(triangle, p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z);
}
void TRIANGLE_destroy(TRIANGLE_Triangle *triangle) {
assert(triangle);
SHAPE_destroy(&triangle->shape);
}
void TRIANGLE_delete(TRIANGLE_Triangle *triangle) {
assert(triangle);
TRIANGLE_destroy(triangle);
free(triangle);
}
void TRIANGLE_delete_shape(SHAPE_Shape *shape) {
assert(shape);
TRIANGLE_delete((TRIANGLE_Triangle *)shape);
}
void TRIANGLE_local_normal_at(TUPLES_Vector *local_normal, SHAPE_Shape *shape, const TUPLES_Point *local_point, const RAY_Xs *hit) {
assert(local_normal);
assert(shape);
assert(local_point);
UNUSED(hit);
UNUSED(local_point);
TRIANGLE_Triangle *triangle = (TRIANGLE_Triangle *)shape;
TUPLES_copy(local_normal, &triangle->normal);
}
void TRIANGLE_smooth_local_normal_at(TUPLES_Vector *local_normal, SHAPE_Shape *shape, const TUPLES_Point *local_point, const RAY_Xs *hit) {
assert(local_normal);
assert(shape);
assert(local_point);
UNUSED(local_point);
TRIANGLE_SmoothTriangle *st = (TRIANGLE_SmoothTriangle *)shape;
TUPLES_Vector partial1, partial2, partial3;
TUPLES_multiply(&partial2, &st->n2, hit->u);
TUPLES_multiply(&partial3, &st->n3, hit->v);
TUPLES_multiply(&partial1, &st->n1, (1 - hit->u - hit->v));
TUPLES_add(local_normal, &partial1, &partial2);
TUPLES_add(local_normal, local_normal, &partial3);
}
void TRIANGLE_local_intersect(RAY_Intersections *intersections, SHAPE_Shape *shape, const RAY_Ray *local_ray) {
assert(intersections);
assert(shape);
assert(local_ray);
TRIANGLE_Triangle *triangle = (TRIANGLE_Triangle *)shape;
TUPLES_Vector dir_cross_e2;
TUPLES_cross(&dir_cross_e2, &local_ray->direction, &triangle->e2);
double det = TUPLES_dot(&triangle->e1, &dir_cross_e2);
// if det is close to zero, ray is parallel
if (double_equal(0, det)) {
return;
}
double f = 1.0 / det;
TUPLES_Vector p1_to_origin;
TUPLES_subtract(&p1_to_origin, &local_ray->origin, &triangle->p1);
double u = f * TUPLES_dot(&p1_to_origin, &dir_cross_e2);
if (u < 0 || u > 1) {
return;
}
TUPLES_Vector origin_cross_e1;
TUPLES_cross(&origin_cross_e1, &p1_to_origin, &triangle->e1);
double v = f * TUPLES_dot(&local_ray->direction, &origin_cross_e1);
if (v < 0 || (u + v) > 1) {
return;
}
double t = f * TUPLES_dot(&triangle->e2, &origin_cross_e1);
RAY_add_intersection_tri(intersections, t, triangle, u, v);
}
void TRIANGLE_init_smooth_from_points(TRIANGLE_SmoothTriangle *triangle, const TUPLES_Point *p1, const TUPLES_Point *p2, const TUPLES_Point *p3,
const TUPLES_Vector *v1, const TUPLES_Vector *v2, const TUPLES_Vector *v3) {
assert(triangle);
assert(p1);
assert(p2);
assert(p3);
assert(v1);
assert(v2);
assert(v3);
SHAPE_init(&triangle->shape, &TRIANGLE_smooth_vtable);
init_base_triangle_info(&triangle->tri, p1->x, p1->y, p1->z, p2->x, p2->y, p2->z, p3->x, p3->y, p3->z);
TUPLES_copy(&triangle->n1, v1);
TUPLES_copy(&triangle->n2, v2);
TUPLES_copy(&triangle->n3, v3);
}
TRIANGLE_SmoothTriangle *TRIANGLE_new_smooth_from_points(const TUPLES_Point *p1, const TUPLES_Point *p2, const TUPLES_Point *p3, const TUPLES_Vector *v1,
const TUPLES_Vector *v2, const TUPLES_Vector *v3) {
assert(p1);
assert(p2);
assert(p3);
assert(v1);
assert(v2);
assert(v3);
TRIANGLE_SmoothTriangle *st = malloc(sizeof(TRIANGLE_SmoothTriangle));
if (!st) {
Throw(E_MALLOC_FAILED);
}
TRIANGLE_init_smooth_from_points(st, p1, p2, p3, v1, v2, v3);
return st;
}