From: Lukas Jiriste Date: Tue, 14 Jan 2025 15:45:21 +0000 (+0100) Subject: Make scene.c completely Norm compliant X-Git-Url: https://git.ljiriste.work/?a=commitdiff_plain;h=b822af215adcb6801931d6247b29f5c15ad39afd;p=42%2FminiRT.git Make scene.c completely Norm compliant --- diff --git a/Makefile b/Makefile index 7ad1e6b..8363fde 100644 --- a/Makefile +++ b/Makefile @@ -21,13 +21,20 @@ INCLUDE := $(addprefix -I, $(INCDIR)) SRCDIR := src SOURCES := main.c \ - scene.c \ manipulation.c \ tokenize.c \ parse.c \ parse_rt.c \ parse_small.c \ parse_elements.c \ + scene.c \ + scene_helpers.c \ + intersect.c \ + circumsphere.c \ + cylinder.c \ + sphere.c \ + plane.c \ + object_color.c \ vec3.c \ SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES)) diff --git a/inc/miniRT.h b/inc/miniRT.h index 6144fd9..28532a5 100644 --- a/inc/miniRT.h +++ b/inc/miniRT.h @@ -6,7 +6,7 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/01/13 19:51:09 by ljiriste #+# #+# */ -/* Updated: 2025/01/14 15:13:53 by ljiriste ### ########.fr */ +/* Updated: 2025/01/14 16:44:53 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,6 +15,15 @@ # include "vec3.h" # include "libft.h" +# include "math.h" + +# ifndef INFINITY +# error "This platform does not support INFINITY macro!" +# endif // INFINITY + +# ifndef NAN +# error "This platform does not support NAN macro!" +# endif // NAN typedef t_vec3 t_color; @@ -154,6 +163,8 @@ double node_to_double(const t_parse_tree_node *double_node); t_color node_to_linear_rgb(const t_parse_tree_node *rgb_node); t_vec3 node_to_vec3(const t_parse_tree_node *vec3_node); +int parse_rt_file(const char *filename, t_scene *scene); +int parse_args(int argc, char **argv, t_session *s); int add_light(const t_parse_tree_node *light_node, t_vec *lights); int add_camera( const t_parse_tree_node *camera_node, t_vec *cameras); @@ -163,7 +174,11 @@ int add_sphere( int add_cylinder( const t_parse_tree_node *cylinder_node, t_vec *objects); -int parse_rt_file(const char *filename, t_scene *scene); +double dist_point_from_line(const t_ray *ray, t_vec3 point); +double dist_point_from_plane(const t_plane *plane, t_vec3 point); +int is_behind_ray(const t_ray *ray, t_vec3 point); +t_vec3 ray_point(const t_ray *ray, double arg); +t_pair solve_quadratic(double a, double b, double c); t_color trace_ray(const t_ray *ray, t_scene *scene); t_color color_srgb_to_lin(t_color_srgb srgb); @@ -171,7 +186,22 @@ t_color color_srgb_to_lin(t_color_srgb srgb); t_obstruction find_nearest_obstruction( const t_ray *ray, t_vec *objects, const t_object *ignored); -int parse_args(int argc, char **argv, t_session *s); +t_sphere get_circumsphere(const t_object *object); +int intersects_circumsphere( + const t_ray *ray, const t_object *object); +t_vec3 get_cylinder_normal(t_vec3 point, const t_cylinder *cylinder); +t_vec get_intersection_arg_cylinder( + const t_ray *ray, const t_cylinder *cylinder); +t_vec get_intersection_arg_sphere( + const t_ray *ray, const t_sphere *sphere); +double get_intersection_arg_plane( + const t_ray *ray, const t_plane *plane); +t_vec get_intersection_args(const t_ray *ray, const t_object *object); +double get_intersection_arg_min( + const t_ray *ray, const t_object *object); + +t_color get_object_color(const t_ray *ray, const t_object *object, + t_scene *scene); int rotate(t_element *element, t_vec3 rot_axis, double angle); void translate( diff --git a/src/circumsphere.c b/src/circumsphere.c new file mode 100644 index 0000000..11b379c --- /dev/null +++ b/src/circumsphere.c @@ -0,0 +1,63 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* circumsphere.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/14 15:55:54 by ljiriste #+# #+# */ +/* Updated: 2025/01/14 16:07:27 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "vec3.h" +#include "miniRT.h" +#include "libft.h" +#include + +static 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_sphere get_circumsphere(const t_object *object) +{ + t_sphere circumsphere; + + if (object->type == SPHERE) + { + circumsphere.radius = object->object.sphere.radius; + circumsphere.center = object->object.sphere.center; + } + else if (object->type == CYLINDER) + { + circumsphere.radius + = get_cylinder_circumsphere_radius(&object->object.cylinder); + circumsphere.center = object->object.cylinder.center; + } + else if (object->type == PLANE) + { + circumsphere.radius = INFINITY; + circumsphere.center = object->object.plane.point; + } + return (circumsphere); +} + +int intersects_circumsphere(const t_ray *ray, const t_object *object) +{ + t_sphere circumsphere; + double distance; + + circumsphere = get_circumsphere(object); + if (is_behind_ray(ray, vec_add( + circumsphere.center, + vec_real_mul(ray->direction, circumsphere.radius)))) + return (0); + distance = dist_point_from_line(ray, circumsphere.center); + return (distance < circumsphere.radius); +} diff --git a/src/cylinder.c b/src/cylinder.c new file mode 100644 index 0000000..d92a8d7 --- /dev/null +++ b/src/cylinder.c @@ -0,0 +1,113 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cylinder.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/14 15:42:58 by ljiriste #+# #+# */ +/* Updated: 2025/01/14 16:08:21 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "vec3.h" +#include "miniRT.h" +#include "libft.h" + +static t_vec get_intersection_arg_cylinder_base( + const t_ray *ray, const t_cylinder *cylinder) +{ + t_vec res; + double arg; + t_plane base; + + ft_vec_init(&res, sizeof(double)); + base.point = vec_add( + cylinder->center, + vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); + base.normal = cylinder->rot_axis; + arg = get_intersection_arg_plane(ray, &base); + if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius) + ft_vec_append(&res, &arg); + base.point = vec_diff( + cylinder->center, + vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); + arg = get_intersection_arg_plane(ray, &base); + if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius) + ft_vec_append(&res, &arg); + return (res); +} + +static t_vec get_intersection_arg_cylinder_around( + const t_ray *ray, const t_cylinder *cylinder) +{ + t_vec res; + t_pair args; + t_vec3 v; + t_vec3 u; + t_vec3 intersect; + + ft_vec_init(&res, sizeof(double)); + v = vec_vec_mul(cylinder->rot_axis, ray->direction); + u = vec_vec_mul(cylinder->rot_axis, vec_diff(ray->start, cylinder->center)); + args = solve_quadratic(vec_scalar_mul(v, v), 2 * vec_scalar_mul(v, u), + vec_scalar_mul(u, u) - cylinder->radius * cylinder->radius); + intersect = ray_point(ray, args.first); + if (fabs(vec_scalar_mul( + cylinder->rot_axis, vec_diff(intersect, cylinder->center))) + < cylinder->height / 2) + ft_vec_append(&res, &args.first); + intersect = ray_point(ray, args.second); + if (fabs(vec_scalar_mul( + cylinder->rot_axis, vec_diff(intersect, cylinder->center))) + < cylinder->height / 2) + ft_vec_append(&res, &args.second); + return (res); +} + +t_vec get_intersection_arg_cylinder( + const t_ray *ray, const t_cylinder *cylinder) +{ + size_t i; + t_vec res; + t_vec res2; + const double *el; + + res = get_intersection_arg_cylinder_base(ray, cylinder); + res2 = get_intersection_arg_cylinder_around(ray, cylinder); + i = 0; + while (i < res2.size) + { + el = ft_vec_caccess(&res2, i); + ft_vec_append(&res, el); + ++i; + } + ft_vec_free(&res2, NULL); + return (res); +} + +t_vec3 get_cylinder_normal(t_vec3 point, const t_cylinder *cylinder) +{ + t_vec3 radial_vec; + double dist_from_round; + double dist_from_top; + double dist_from_bottom; + t_plane base; + + radial_vec = vec_vec_mul(cylinder->rot_axis, + vec_diff(point, cylinder->center)); + radial_vec = vec_vec_mul(radial_vec, cylinder->rot_axis); + dist_from_round = fabs(vec_norm(radial_vec) - cylinder->radius); + base.normal = cylinder->rot_axis; + base.point = vec_add(cylinder->center, + vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); + dist_from_top = dist_point_from_plane(&base, point); + base.point = vec_diff(cylinder->center, + vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); + dist_from_bottom = dist_point_from_plane(&base, point); + if (dist_from_round < dist_from_top && dist_from_round < dist_from_bottom) + return (radial_vec); + if (dist_from_top < dist_from_bottom) + return (cylinder->rot_axis); + return (vec_real_mul(cylinder->rot_axis, -1)); +} diff --git a/src/intersect.c b/src/intersect.c new file mode 100644 index 0000000..f047934 --- /dev/null +++ b/src/intersect.c @@ -0,0 +1,85 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* intersect.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/14 15:58:23 by ljiriste #+# #+# */ +/* Updated: 2025/01/14 16:04:08 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "vec3.h" +#include "miniRT.h" +#include "libft.h" + +static int is_bounded(const t_object *object) +{ + enum e_object_type type; + + type = object->type; + return (type != PLANE); +} + +static t_vec get_intersection_arg_nonbounded( + const t_ray *ray, const t_object *object) +{ + t_vec res; + double tmp; + + ft_vec_init(&res, sizeof(double)); + if (object->type == PLANE) + { + tmp = get_intersection_arg_plane(ray, &object->object.plane); + ft_vec_append(&res, &tmp); + } + return (res); +} + +static t_vec get_intersection_arg_bounded( + const t_ray *ray, const t_object *object) +{ + t_vec res; + + if (object->type == SPHERE) + res = get_intersection_arg_sphere(ray, &object->object.sphere); + else if (object->type == CYLINDER) + res = get_intersection_arg_cylinder(ray, &object->object.cylinder); + else + ft_vec_init(&res, sizeof(double)); + return (res); +} + +t_vec get_intersection_args(const t_ray *ray, const t_object *object) +{ + t_vec res; + + if (!is_bounded(object)) + res = get_intersection_arg_nonbounded(ray, object); + else if (intersects_circumsphere(ray, object)) + res = get_intersection_arg_bounded(ray, object); + else + ft_vec_init(&res, sizeof(double)); + return (res); +} + +double get_intersection_arg_min(const t_ray *ray, const t_object *object) +{ + t_vec args; + double arg; + double res; + size_t i; + + args = get_intersection_args(ray, object); + res = INFINITY; + i = 0; + while (i < args.size) + { + arg = *(const double *)ft_vec_caccess(&args, i++); + if (arg > 0 && arg < res) + res = arg; + } + ft_vec_free(&args, NULL); + return (res); +} diff --git a/src/object_color.c b/src/object_color.c new file mode 100644 index 0000000..7594c73 --- /dev/null +++ b/src/object_color.c @@ -0,0 +1,89 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* object_color.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/14 16:00:18 by ljiriste #+# #+# */ +/* Updated: 2025/01/14 16:15:13 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "vec3.h" +#include "miniRT.h" +#include "libft.h" + +static t_vec3 get_object_normal(const t_object *object, t_vec3 point) +{ + if (object->type == PLANE) + return (object->object.plane.normal); + if (object->type == SPHERE) + return (vec_diff(point, object->object.sphere.center)); + if (object->type == CYLINDER) + return (get_cylinder_normal(point, &object->object.cylinder)); + return ((t_vec3){.x = 0, .y = 0, .z = 0}); +} + +static t_color get_ambient_color( + const t_object *object, const t_ambient_light *amb) +{ + return (vec_real_mul( + vec_elwise_mul(amb->color, object->object.plane.color), + amb->brightness)); +} + +static t_color get_light_contribution(t_ray normal, const t_object *object, + const t_light *light, t_scene *scene) +{ + t_ray new_ray; + t_obstruction obstruction; + double angle_multiplier; + double distance; + + new_ray.start = normal.start; + new_ray.direction = vec_diff(light->position, new_ray.start); + distance = vec_norm(new_ray.direction); + new_ray.direction = vec_real_mul(new_ray.direction, 1 / distance); + obstruction = find_nearest_obstruction(&new_ray, &scene->objects, object); + angle_multiplier = vec_scalar_mul(normal.direction, new_ray.direction) + / (vec_norm(normal.direction) * vec_norm(new_ray.direction)); + if (object->type == PLANE) + angle_multiplier = fabs(angle_multiplier); + if (angle_multiplier > 0 && (!obstruction.object + || distance < obstruction.distance + ||obstruction.distance < 0)) + return (vec_real_mul( + vec_elwise_mul(light->color, object->object.plane.color), + light->brightness * angle_multiplier / distance / distance)); + else + return ((t_color){.x = 0, .y = 0, .z = 0}); +} + +t_color get_object_color(const t_ray *ray, const t_object *object, + t_scene *scene) +{ + t_color result; + t_ray object_normal; + const t_light *light; + size_t i; + + result = (t_color){.x = 0, .y = 0, .z = 0}; + object_normal.start = ray_point(ray, get_intersection_arg_min(ray, object)); + object_normal.direction = get_object_normal(object, object_normal.start); + if (vec_scalar_mul(object_normal.direction, ray->direction) > 0) + object_normal.direction = vec_real_mul(object_normal.direction, -1); + i = 0; + while (i < scene->lights.size) + { + light = &((const t_element *) + ft_vec_caccess(&scene->lights, i++))->object.light; + if (vec_scalar_mul(object_normal.direction, + vec_diff(light->position, object_normal.start)) > 0) + result = vec_add(result, get_light_contribution( + object_normal, + object, light, scene)); + } + result = vec_add(result, get_ambient_color(object, &scene->ambient_light)); + return (result); +} diff --git a/src/plane.c b/src/plane.c new file mode 100644 index 0000000..f6bd22f --- /dev/null +++ b/src/plane.c @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* plane.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/14 15:50:09 by ljiriste #+# #+# */ +/* Updated: 2025/01/14 15:50:25 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "vec3.h" +#include "miniRT.h" +#include "libft.h" + +double get_intersection_arg_plane(const t_ray *ray, const t_plane *plane) +{ + t_vec3 start; + t_vec res; + + ft_vec_init(&res, sizeof(double)); + start = vec_diff(plane->point, ray->start); + return (vec_scalar_mul(plane->normal, start) + / vec_scalar_mul(plane->normal, ray->direction)); +} diff --git a/src/scene.c b/src/scene.c index 15f6988..8b4d260 100644 --- a/src/scene.c +++ b/src/scene.c @@ -6,7 +6,7 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/01/13 19:41:36 by ljiriste #+# #+# */ -/* Updated: 2025/01/13 19:43:04 by ljiriste ### ########.fr */ +/* Updated: 2025/01/14 16:15:13 by ljiriste ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,299 +15,46 @@ #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 g_default_color = {0, 0, 0}; static const double g_self_obstruction_multiplier = 1e-8; -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)); -} - -double dist_point_from_line(const t_ray *ray, t_vec3 point) -{ - t_vec3 start; - t_vec3 projection; - - start = vec_diff(ray->start, point); - projection = vec_real_mul(ray->direction, - vec_scalar_mul(ray->direction, start)); - return (vec_norm(vec_diff(start, projection))); -} - -double dist_point_from_plane(const t_plane *plane, t_vec3 point) -{ - return (fabs(vec_scalar_mul(plane->normal, - vec_diff(point, plane->point)))); -} - -int is_behind_ray(const t_ray *ray, t_vec3 point) -{ - return (0 > vec_scalar_mul(ray->direction, vec_diff(point, ray->start))); -} - -t_sphere get_circumsphere(const t_object *object) -{ - t_sphere circumsphere; - - if (object->type == SPHERE) - { - circumsphere.radius = object->object.sphere.radius; - circumsphere.center = object->object.sphere.center; - } - else if (object->type == CYLINDER) - { - circumsphere.radius - = get_cylinder_circumsphere_radius(&object->object.cylinder); - circumsphere.center = object->object.cylinder.center; - } - else if (object->type == PLANE) - { - circumsphere.radius = INFINITY; - circumsphere.center = object->object.plane.point; - } - return (circumsphere); -} - -int intersects_circumsphere(const t_ray *ray, const t_object *object) -{ - t_sphere circumsphere; - double distance; - - circumsphere = get_circumsphere(object); - if (is_behind_ray(ray, vec_add( - circumsphere.center, - vec_real_mul(ray->direction, circumsphere.radius)))) - return (0); - distance = dist_point_from_line(ray, circumsphere.center); - return (distance < circumsphere.radius); -} - -double get_intersection_arg_plane(const t_ray *ray, const t_plane *plane) -{ - t_vec3 start; - t_vec res; - - ft_vec_init(&res, sizeof(double)); - start = vec_diff(plane->point, ray->start); - return (vec_scalar_mul(plane->normal, start) - / vec_scalar_mul(plane->normal, ray->direction)); -} - -t_vec get_intersection_arg_nonbounded( - const t_ray *ray, const t_object *object) -{ - t_vec res; - double tmp; - - ft_vec_init(&res, sizeof(double)); - if (object->type == PLANE) - { - tmp = get_intersection_arg_plane(ray, &object->object.plane); - ft_vec_append(&res, &tmp); - } - return (res); -} - -t_vec3 ray_point(const t_ray *ray, double arg) -{ - return (vec_add(ray->start, vec_real_mul(ray->direction, arg))); -} - -t_vec get_intersection_arg_cylinder_base( - const t_ray *ray, const t_cylinder *cylinder) -{ - t_vec res; - double arg; - t_plane base; - - ft_vec_init(&res, sizeof(double)); - base.point = vec_add( - cylinder->center, - vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); - base.normal = cylinder->rot_axis; - arg = get_intersection_arg_plane(ray, &base); - if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius) - ft_vec_append(&res, &arg); - base.point = vec_diff( - cylinder->center, - vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); - arg = get_intersection_arg_plane(ray, &base); - if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius) - ft_vec_append(&res, &arg); - return (res); -} - -t_pair solve_quadratic(double a, double b, double c) -{ - t_pair res; - double det; - - det = b * b - 4 * a * c; - if (det < 0) - { - res.first = NAN; - res.second = NAN; - return (res); - } - det = sqrt(det); - res.first = (-b - det) / (2 * a); - res.second = (-b + det) / (2 * a); - return (res); -} - -t_vec get_intersection_arg_cylinder_around( - const t_ray *ray, const t_cylinder *cylinder) -{ - t_vec res; - t_pair args; - t_vec3 v; - t_vec3 u; - t_vec3 intersect; - - ft_vec_init(&res, sizeof(double)); - v = vec_vec_mul(cylinder->rot_axis, ray->direction); - u = vec_vec_mul(cylinder->rot_axis, vec_diff(ray->start, cylinder->center)); - args = solve_quadratic(vec_scalar_mul(v, v), 2 * vec_scalar_mul(v, u), - vec_scalar_mul(u, u) - cylinder->radius * cylinder->radius); - intersect = ray_point(ray, args.first); - if (fabs(vec_scalar_mul( - cylinder->rot_axis, vec_diff(intersect, cylinder->center))) - < cylinder->height / 2) - ft_vec_append(&res, &args.first); - intersect = ray_point(ray, args.second); - if (fabs(vec_scalar_mul( - cylinder->rot_axis, vec_diff(intersect, cylinder->center))) - < cylinder->height / 2) - ft_vec_append(&res, &args.second); - return (res); -} - -t_vec get_intersection_arg_cylinder( - const t_ray *ray, const t_cylinder *cylinder) -{ - size_t i; - t_vec res; - t_vec res2; - const double *el; - - res = get_intersection_arg_cylinder_base(ray, cylinder); - res2 = get_intersection_arg_cylinder_around(ray, cylinder); - i = 0; - while (i < res2.size) - { - el = ft_vec_caccess(&res2, i); - ft_vec_append(&res, el); - ++i; - } - ft_vec_free(&res2, NULL); - return (res); -} - -t_vec get_intersection_arg_sphere(const t_ray *ray, const t_sphere *sphere) -{ - t_vec3 start; - t_pair intersection_args; - t_vec res; - - ft_vec_init(&res, sizeof(double)); - start = vec_diff(ray->start, sphere->center); - intersection_args = solve_quadratic( - vec_scalar_mul(ray->direction, ray->direction), - 2 * vec_scalar_mul(ray->direction, start), - vec_scalar_mul(start, start) - sphere->radius * sphere->radius); - if (!isnan(intersection_args.first)) - ft_vec_append(&res, &intersection_args.first); - if (!isnan(intersection_args.second)) - ft_vec_append(&res, &intersection_args.second); - return (res); -} - -t_vec get_intersection_arg_bounded(const t_ray *ray, const t_object *object) -{ - t_vec res; - - if (object->type == SPHERE) - res = get_intersection_arg_sphere(ray, &object->object.sphere); - else if (object->type == CYLINDER) - res = get_intersection_arg_cylinder(ray, &object->object.cylinder); - else - ft_vec_init(&res, sizeof(double)); - return (res); -} - -t_vec get_intersection_args(const t_ray *ray, const t_object *object) +double get_self_obstruction_limit(const t_object *object) { - t_vec res; - - if (!is_bounded(object)) - res = get_intersection_arg_nonbounded(ray, object); - else if (intersects_circumsphere(ray, object)) - res = get_intersection_arg_bounded(ray, object); - else - ft_vec_init(&res, sizeof(double)); - return (res); + return (get_circumsphere(object).radius * g_self_obstruction_multiplier); } -double get_intersection_arg_min(const t_ray *ray, const t_object *object) +void update_nearest(t_obstruction *obstruction, t_vec *distances, + t_object *object, const t_object *ignored) { - t_vec args; - double arg; - double res; - size_t i; + size_t j; + double ignored_dist; + double distance; - args = get_intersection_args(ray, object); - res = INFINITY; - i = 0; - while (i < args.size) + if (ignored) + ignored_dist = get_self_obstruction_limit(ignored); + j = 0; + while (j < distances->size) { - arg = *(const double *)ft_vec_caccess(&args, i++); - if (arg > 0 && arg < res) - res = arg; + distance = *(const double *)ft_vec_caccess(distances, j++); + if (object == ignored && distance > 0 && distance < ignored_dist) + continue ; + if (0 < distance && distance < obstruction->distance) + { + obstruction->distance = distance; + obstruction->object = object; + } } - ft_vec_free(&args, NULL); - return (res); -} - -double get_self_obstruction_limit(const t_object *object) -{ - return (get_circumsphere(object).radius * g_self_obstruction_multiplier); } t_obstruction find_nearest_obstruction(const t_ray *ray, t_vec *objects, const t_object *ignored) { size_t i; - size_t j; t_obstruction obstruction_found; t_object *object; - double distance; - double ignored_dist; t_vec distances; - if (ignored) - ignored_dist = get_self_obstruction_limit(ignored); obstruction_found.object = NULL; obstruction_found.distance = INFINITY; i = 0; @@ -315,126 +62,12 @@ t_obstruction find_nearest_obstruction(const t_ray *ray, t_vec *objects, { object = ft_vec_access(objects, i++); distances = get_intersection_args(ray, object); - j = 0; - while (j < distances.size) - { - distance = *(const double *)ft_vec_caccess(&distances, j++); - if (object == ignored && distance > 0 && distance < ignored_dist) - continue ; - if (0 < distance && distance < obstruction_found.distance) - { - obstruction_found.distance = distance; - obstruction_found.object = object; - } - } + update_nearest(&obstruction_found, &distances, object, ignored); ft_vec_free(&distances, NULL); } return (obstruction_found); } -t_color get_ambient_color(const t_object *object, const t_ambient_light *amb) -{ - return (vec_real_mul( - vec_elwise_mul(amb->color, object->object.plane.color), - amb->brightness)); -} - -t_vec3 get_cylinder_normal(t_vec3 point, const t_cylinder *cylinder) -{ - t_vec3 radial_vec; - double dist_from_round; - double dist_from_top; - double dist_from_bottom; - t_plane base; - - radial_vec = vec_vec_mul(cylinder->rot_axis, - vec_diff(point, cylinder->center)); - radial_vec = vec_vec_mul(radial_vec, cylinder->rot_axis); - dist_from_round = fabs(vec_norm(radial_vec) - cylinder->radius); - base.normal = cylinder->rot_axis; - base.point = vec_add(cylinder->center, - vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); - dist_from_top = dist_point_from_plane(&base, point); - base.point = vec_diff(cylinder->center, - vec_real_mul(cylinder->rot_axis, cylinder->height / 2)); - dist_from_bottom = dist_point_from_plane(&base, point); - if (dist_from_round < dist_from_top && dist_from_round < dist_from_bottom) - return (radial_vec); - if (dist_from_top < dist_from_bottom) - return (cylinder->rot_axis); - return (vec_real_mul(cylinder->rot_axis, -1)); -} - -t_vec3 get_object_normal(const t_object *object, t_vec3 point) -{ - if (object->type == PLANE) - return (object->object.plane.normal); - if (object->type == SPHERE) - return (vec_diff(point, object->object.sphere.center)); - if (object->type == CYLINDER) - return (get_cylinder_normal(point, &object->object.cylinder)); - return ((t_vec3){.x = 0, .y = 0, .z = 0}); -} - -t_color get_light_contribution(t_ray normal, const t_object *object, - const t_light *light, t_scene *scene) -{ - t_ray new_ray; - t_obstruction obstruction; - double angle_multiplier; - double distance; - - new_ray.start = normal.start; - new_ray.direction = vec_diff(light->position, new_ray.start); - distance = vec_norm(new_ray.direction); - new_ray.direction = vec_real_mul(new_ray.direction, 1 / distance); - obstruction = find_nearest_obstruction(&new_ray, &scene->objects, object); - angle_multiplier = vec_scalar_mul(normal.direction, new_ray.direction) - / (vec_norm(normal.direction) * vec_norm(new_ray.direction)); - if (object->type == PLANE) - angle_multiplier = fabs(angle_multiplier); - if (angle_multiplier > 0 && (!obstruction.object - || distance < obstruction.distance - ||obstruction.distance < 0)) - return (vec_real_mul( - vec_elwise_mul(light->color, object->object.plane.color), - light->brightness * angle_multiplier / distance / distance)); - else - return ((t_color){.x = 0, .y = 0, .z = 0}); -} - -t_color get_object_color(const t_ray *ray, const t_object *object, - t_scene *scene) -{ - t_color result; - t_ray normal_at_intersect; - const t_light *light; - size_t i; - - result = (t_color){.x = 0, .y = 0, .z = 0}; - normal_at_intersect.start - = ray_point(ray, get_intersection_arg_min(ray, object)); - normal_at_intersect.direction - = get_object_normal(object, normal_at_intersect.start); - if (vec_scalar_mul(normal_at_intersect.direction, ray->direction) > 0) - normal_at_intersect.direction - = vec_real_mul(normal_at_intersect.direction, -1); - i = 0; - while (i < scene->lights.size) - { - light = &((const t_element *) - ft_vec_caccess(&scene->lights, i))->object.light; - if (vec_scalar_mul(normal_at_intersect.direction, - vec_diff(light->position, normal_at_intersect.start)) > 0) - result = vec_add(result, get_light_contribution( - normal_at_intersect, - object, light, scene)); - ++i; - } - result = vec_add(result, get_ambient_color(object, &scene->ambient_light)); - return (result); -} - t_color trace_ray(const t_ray *ray, t_scene *scene) { const t_object *object_found; diff --git a/src/scene_helpers.c b/src/scene_helpers.c new file mode 100644 index 0000000..de8e950 --- /dev/null +++ b/src/scene_helpers.c @@ -0,0 +1,59 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* scene_helpers.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/14 16:01:26 by ljiriste #+# #+# */ +/* Updated: 2025/01/14 16:02:10 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "vec3.h" +#include "miniRT.h" + +double dist_point_from_line(const t_ray *ray, t_vec3 point) +{ + t_vec3 start; + t_vec3 projection; + + start = vec_diff(ray->start, point); + projection = vec_real_mul(ray->direction, + vec_scalar_mul(ray->direction, start)); + return (vec_norm(vec_diff(start, projection))); +} + +double dist_point_from_plane(const t_plane *plane, t_vec3 point) +{ + return (fabs(vec_scalar_mul(plane->normal, + vec_diff(point, plane->point)))); +} + +int is_behind_ray(const t_ray *ray, t_vec3 point) +{ + return (0 > vec_scalar_mul(ray->direction, vec_diff(point, ray->start))); +} + +t_vec3 ray_point(const t_ray *ray, double arg) +{ + return (vec_add(ray->start, vec_real_mul(ray->direction, arg))); +} + +t_pair solve_quadratic(double a, double b, double c) +{ + t_pair res; + double det; + + det = b * b - 4 * a * c; + if (det < 0) + { + res.first = NAN; + res.second = NAN; + return (res); + } + det = sqrt(det); + res.first = (-b - det) / (2 * a); + res.second = (-b + det) / (2 * a); + return (res); +} diff --git a/src/sphere.c b/src/sphere.c new file mode 100644 index 0000000..a69f94b --- /dev/null +++ b/src/sphere.c @@ -0,0 +1,34 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* sphere.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ljiriste +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/01/14 15:49:12 by ljiriste #+# #+# */ +/* Updated: 2025/01/14 15:49:37 by ljiriste ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "vec3.h" +#include "miniRT.h" +#include "libft.h" + +t_vec get_intersection_arg_sphere(const t_ray *ray, const t_sphere *sphere) +{ + t_vec3 start; + t_pair intersection_args; + t_vec res; + + ft_vec_init(&res, sizeof(double)); + start = vec_diff(ray->start, sphere->center); + intersection_args = solve_quadratic( + vec_scalar_mul(ray->direction, ray->direction), + 2 * vec_scalar_mul(ray->direction, start), + vec_scalar_mul(start, start) - sphere->radius * sphere->radius); + if (!isnan(intersection_args.first)) + ft_vec_append(&res, &intersection_args.first); + if (!isnan(intersection_args.second)) + ft_vec_append(&res, &intersection_args.second); + return (res); +}