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))
/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 */
/* */
/* ************************************************************************** */
# 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;
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);
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);
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(
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* circumsphere.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* 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 <math.h>
+
+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);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* cylinder.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* 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));
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* intersect.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* 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);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* object_color.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* 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);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* plane.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* 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));
+}
/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 */
/* */
/* ************************************************************************** */
#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
-
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;
{
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;
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* scene_helpers.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* 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);
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* sphere.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: ljiriste <ljiriste@student.42prague.com> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* 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);
+}