Implement most of ray intersection detection
authorLukas Jiriste <ljiriste@student.42prague.com>
Thu, 21 Nov 2024 16:00:49 +0000 (17:00 +0100)
committerLukas Jiriste <ljiriste@student.42prague.com>
Sat, 23 Nov 2024 11:05:51 +0000 (12:05 +0100)
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
inc/miniRT.h
src/main.c
src/scene.c [new file with mode: 0644]

index 8299feffdcb760871c2c46bef6c5b81e86afc8c2..cb2f06855ef2e2b8d90eb6a69120ce88baee07bf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,6 +21,7 @@ INCLUDE := $(addprefix -I, $(INCDIR))
 SRCDIR := src
 
 SOURCES :=     main.c                          \
+                       scene.c                         \
 
 SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES))
 
index 40e650f2e36c7aac23ad14e4461981471e14d812..318eb3a18079912899d6cd38264cce56907a86f7 100644 (file)
@@ -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
index 9144af538d1b289909cc0473722c1595841194ad..a43f1c864247c864245592e14955ba4e5c522fa9 100644 (file)
@@ -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 (file)
index 0000000..e5def95
--- /dev/null
@@ -0,0 +1,190 @@
+#include "miniRT.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
+
+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);
+}