From b24ac9a0cef1c10824061786f945db5f3246c9c7 Mon Sep 17 00:00:00 2001 From: Lukas Jiriste Date: Thu, 21 Nov 2024 17:00:49 +0100 Subject: [PATCH] Implement most of ray intersection detection Implement finding the intersection of ray with plane and sphere and use the intersection closest intersection to camera for color finding. Cylinder will be implemented at another time. Also change what qualifies as an object; Now objects have to interact with light. Light sources and cameras are not objects anymore. --- Makefile | 1 + inc/miniRT.h | 17 +++-- src/main.c | 4 +- src/scene.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 src/scene.c diff --git a/Makefile b/Makefile index 8299fef..cb2f068 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ INCLUDE := $(addprefix -I, $(INCDIR)) SRCDIR := src SOURCES := main.c \ + scene.c \ SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES)) diff --git a/inc/miniRT.h b/inc/miniRT.h index 40e650f..318eb3a 100644 --- a/inc/miniRT.h +++ b/inc/miniRT.h @@ -62,8 +62,6 @@ union u_object_union t_sphere sphere; t_plane plane; t_cylinder cylinder; - t_light light; - t_camera camera; }; enum e_object_type @@ -71,8 +69,6 @@ enum e_object_type SPHERE, PLANE, CYLINDER, - LIGHT, - CAMERA, }; typedef struct s_object @@ -91,9 +87,17 @@ typedef struct s_scene { t_ambient_light ambient_light; t_vec objects; + t_vec lights; + t_vec cameras; t_camera *current_camera; } t_scene; +typedef struct s_ray +{ + t_vec3 start; + t_vec3 direction; +} t_ray; + typedef struct s_img { void *img; @@ -113,5 +117,10 @@ typedef struct s_session t_scene scene; } t_session; +t_ray get_camera_ray(int x, int y, const t_session *session); +t_color get_object_color(const t_ray *ray, const t_object *object); +double get_intersection_arg_cylinder(const t_ray *ray, + const t_cylinder *cylinder); +t_color trace_ray(const t_ray *ray, const t_scene *scene); #endif // MINIRT_H diff --git a/src/main.c b/src/main.c index 9144af5..a43f1c8 100644 --- a/src/main.c +++ b/src/main.c @@ -113,6 +113,7 @@ void draw(t_session *s) int x; int y; double param; + t_ray ray; x = 0; while (x < s->img.width) @@ -120,7 +121,8 @@ void draw(t_session *s) y = 0; while (y < s->img.height) { - ft_putpx_img(&s->img, x, y, trace_ray(x, y, &s->scene)); + ray = get_camera_ray(x, y, s); + ft_putpx_img(&s->img, x, y, trace_ray(&ray, &s->scene)); ++y; } ++x; diff --git a/src/scene.c b/src/scene.c new file mode 100644 index 0000000..e5def95 --- /dev/null +++ b/src/scene.c @@ -0,0 +1,190 @@ +#include "miniRT.h" +#include "libft.h" +#include + +#ifndef INFINITY +# error "This platform does not support INFINITY macro!" +#endif // INFINITY + +#ifndef NAN +# error "This platform does not support NAN macro!" +#endif // NAN + +static const t_color DEFAULT_COLOR = {0, 0, 0}; + +static int is_bounded(const t_object *object) +{ + enum e_object_type type; + + type = object->type; + return (type == PLANE); +} + +double get_cylinder_circumsphere_radius(const t_cylinder *cylinder) +{ + double base_radius; + double height; + + base_radius = cylinder->radius; + height = cylinder->height; + return (sqrt(base_radius * base_radius + height * height / 4)); +} + +t_vec3 vec_add(t_vec3 v, t_vec3 u) +{ + t_vec3 res; + + res.x = v.x + u.x; + res.y = v.y + u.y; + res.z = v.z + u.z; + return (res); +} + +t_vec3 vec_diff(t_vec3 v, t_vec3 u) +{ + t_vec3 res; + + res.x = v.x - u.x; + res.y = v.y - u.y; + res.z = v.z - u.z; + return (res); +} + +t_vec3 vec_real_mul(t_vec3 vec, double real) +{ + t_vec3 res; + + res.x = real * vec.x; + res.y = real * vec.y; + res.z = real * vec.z; + return (res); +} + +double vec_scalar_mul(t_vec3 v, t_vec3 u) +{ + return (v.x * u.x + v.y * u.y + v.z * u.z); +} + +double vec_norm(t_vec3 vec) +{ + return (sqrt(vec_scalar_mul(vec, vec))); +} + +double dist_point_from_line(const t_ray *ray, t_vec3 point) +{ + t_vec3 start; + t_vec3 projection; + + start = vec_diff(point, ray->start); + projection = vec_real_mul(ray->direction, + vec_scalar_mul(ray->direction, start)); + return (vec_norm(projection)); +} + +int is_behind_ray(const t_ray *ray, t_vec3 point) +{ + return (0 > vec_scalar_mul(ray->direction, vec_diff(point, ray->start))); +} + +int intersects_circumsphere(const t_ray *ray, const t_object *object) +{ + double radius; + t_vec3 center; + double distance; + + if (object->type == SPHERE) + { + radius = object->object.sphere.radius; + center = object->object.sphere.center; + } + else if (object->type == CYLINDER) + { + radius = get_cylinder_circumsphere_radius(&object->object.cylinder); + center = object->object.cylinder.center; + } + if (is_behind_ray(ray, center)) + return (0); + distance = dist_point_from_line(ray, center); + return (distance < radius); +} + +double get_intersection_arg_plane(const t_ray *ray, const t_plane *plane) +{ + t_vec3 start; + + start = vec_diff(plane->point, ray->start); + return (vec_scalar_mul(plane->normal, start) + / vec_scalar_mul(plane->normal, ray->direction)); +} + +double get_intersection_arg_nonbounded(const t_ray *ray, const t_object *object) +{ + if (object->type == PLANE) + return (get_intersection_arg_plane(ray, &object->object.plane)); + else + return (NAN); +} + +double get_intersection_arg_sphere(const t_ray *ray, const t_sphere *sphere) +{ + t_vec3 start; + double a; + double b; + double c; + double det; + + start = vec_diff(ray->start, sphere->center); + a = vec_scalar_mul(ray->direction, ray->direction); + b = 2 * vec_scalar_mul(ray->direction, start); + c = vec_scalar_mul(start, start) - sphere->radius * sphere->radius; + det = b * b - 4 * a * c; + if (det < 0) + return (NAN); + return ((-b - sqrt(det)) / (2 * a)); +} + +double get_intersection_arg_bounded(const t_ray *ray, const t_object *object) +{ + if (object->type == SPHERE) + return (get_intersection_arg_sphere(ray, &object->object.sphere)); + else if (object->type == CYLINDER) + return (get_intersection_arg_cylinder(ray, &object->object.cylinder)); + else + return (NAN); +} + +double get_intersection_arg(const t_ray *ray, const t_object *object) +{ + if (!is_bounded(object)) + return (get_intersection_arg_nonbounded(ray, object)); + else if (!intersects_circumsphere(ray, object)) + return (NAN); + else + return (get_intersection_arg_bounded(ray, object)); +} + +t_color trace_ray(const t_ray *ray, const t_scene *scene) +{ + size_t i; + const t_object *object_found; + double distance_found; + double distance; + + object_found = NULL; + distance_found = INFINITY; + i = 0; + while (i < scene->objects.size) + { + distance = get_intersection_arg(ray, ft_vec_caccess(&scene->objects, i)); + if (0 < distance && distance < distance_found) + { + distance_found = distance; + object_found = ft_vec_caccess(&scene->objects, i); + } + ++i; + } + if (object_found) + return (get_object_color(ray, object_found)); + else + return (DEFAULT_COLOR); +} -- 2.30.2