From 47fcd8a11e777c9c19075a8203d79b95a2a2c762 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Tue, 23 Sep 2025 15:36:08 +0100 Subject: [PATCH] Create obj module for scene objects --- CMakeLists.txt | 1 + demo.c | 36 ++++++++++-------------------------- include/obj.h | 35 +++++++++++++++++++++++++++++++++++ include/ray.h | 10 ++++++++++ src/obj.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 26 deletions(-) create mode 100644 include/obj.h create mode 100644 include/ray.h create mode 100644 src/obj.c diff --git a/CMakeLists.txt b/CMakeLists.txt index bd5e3ab..e061c73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ endmacro() add_library(batomorph src/ff.c + src/obj.c src/vec3.c ) configure_target(batomorph) diff --git a/demo.c b/demo.c index 4eb2bac..af02ceb 100644 --- a/demo.c +++ b/demo.c @@ -1,4 +1,6 @@ #include "ff.h" +#include "obj.h" +#include "ray.h" #include "vec3.h" #include @@ -14,9 +16,7 @@ #define FOCLEN 1.0 -typedef struct { - vec3_t orig, dir; -} ray_t; +#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) typedef struct { vec3_t centre; @@ -34,35 +34,19 @@ static const vec3_t vp_v = { 0, -VP_H, 0 }; static const vec3_t pix_x_step = { VP_W / W, 0, 0 }; static const vec3_t pix_y_step = { 0, -VP_H / H, 0 }; -static const sphere_t obj = { - .centre = { 1.0, 0.0, -3.0 }, - .rad = 1.0, +static const obj_t scene[] = { + SPHERE(1.0, 0.0, -3.0, 1.0), + SPHERE(-2.0, 0.0, -5.0, 1.0), }; static pix_t pix[W * H]; -static double intersect(sphere_t sphere, ray_t ray) -{ - const vec3_t disp = vec3_sub(sphere.centre, ray.orig); - - const double a = vec3_dot(ray.dir, ray.dir); - const double b = -2.0 * vec3_dot(ray.dir, disp); - const double c = vec3_dot(disp, disp) - sphere.rad * sphere.rad; - - const double discriminant = b * b - 4 * a * c; - if (discriminant < 0) - return -1.0; - else - return (-b - sqrt(discriminant)) / (2.0 * a); -} - static vec3_t raycol(ray_t ray) { - const double t = intersect(obj, ray); - if (t > 0.0) { - const vec3_t p = vec3_add(ray.orig, vec3_scale(ray.dir, t)); - const vec3_t normal = vec3_unit(vec3_sub(p, obj.centre)); - return vec3_scale(vec3_add(normal, white), 0.5); + hit_t hit; + for (unsigned i = 0; i < NELEMS(scene); ++i) { + if (scene[i].intersect(scene[i].params, ray, &hit)) + return vec3_scale(vec3_add(hit.normal, white), 0.5); } const double a = (ray.dir.y + 1.0) / 2.0; diff --git a/include/obj.h b/include/obj.h new file mode 100644 index 0000000..5835d7d --- /dev/null +++ b/include/obj.h @@ -0,0 +1,35 @@ +#ifndef OBJ_H +#define OBJ_H + +#include "ray.h" + +#define SPHERE(x, y, z, r) \ + { \ + .intersect = intersect_sphere, \ + .params = { \ + .sphere = { .centre = { x, y, z }, .radius = r }, \ + }, \ + } + +typedef struct { + vec3_t point, normal; + double t; +} hit_t; + +typedef struct { + vec3_t centre; + double radius; +} sphere_params_t; + +typedef union { + sphere_params_t sphere; +} obj_params_t; + +typedef struct { + bool (*intersect)(obj_params_t params, ray_t ray, hit_t *hit_out); + obj_params_t params; +} obj_t; + +bool intersect_sphere(obj_params_t params, ray_t ray, hit_t *hit_out); + +#endif diff --git a/include/ray.h b/include/ray.h new file mode 100644 index 0000000..775e774 --- /dev/null +++ b/include/ray.h @@ -0,0 +1,10 @@ +#ifndef RAY_H +#define RAY_H + +#include "vec3.h" + +typedef struct { + vec3_t orig, dir; +} ray_t; + +#endif diff --git a/src/obj.c b/src/obj.c new file mode 100644 index 0000000..520c58d --- /dev/null +++ b/src/obj.c @@ -0,0 +1,29 @@ +#include "obj.h" + +#include + +bool intersect_sphere(obj_params_t params, ray_t ray, hit_t *hit_out) +{ + const vec3_t centre = params.sphere.centre; + const double r = params.sphere.radius; + const vec3_t disp = vec3_sub(centre, ray.orig); + + const double a = vec3_dot(ray.dir, ray.dir); + const double b = -2.0 * vec3_dot(ray.dir, disp); + const double c = vec3_dot(disp, disp) - r * r; + + const double discriminant = b * b - 4 * a * c; + if (discriminant < 0) + return false; + + const double t = (-b - sqrt(discriminant)) / (2.0 * a); + const vec3_t point = vec3_add(ray.orig, vec3_scale(ray.dir, t)); + const vec3_t normal = vec3_unit(vec3_sub(point, centre)); + + if (hit_out != nullptr) { + hit_out->point = point; + hit_out->normal = normal; + hit_out->t = t; + } + return true; +}