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));
}
-double get_intersection_arg_nonbounded(const t_ray *ray, const t_object *object)
+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)
- return (get_intersection_arg_plane(ray, &object->object.plane));
- else
- return (NAN);
+ {
+ 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)));
}
-double get_intersection_arg_cylinder_base
+t_vec get_intersection_arg_cylinder_base
(const t_ray *ray, const t_cylinder *cylinder)
{
- double res;
+ 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;
- res = get_intersection_arg_plane(ray, &base);
- if (vec_norm(vec_diff(base.point, ray_point(ray, res))) <= cylinder->radius
+ arg = get_intersection_arg_plane(ray, &base);
+ if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius
&& vec_scalar_mul(ray->direction, vec_diff(cylinder->center, base.point)) > 0)
- return (res);
+ ft_vec_append(&res, &arg);
base.point = vec_diff(cylinder->center, vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
- res = get_intersection_arg_plane(ray, &base);
- if (vec_norm(vec_diff(base.point, ray_point(ray, res))) <= cylinder->radius
+ arg = get_intersection_arg_plane(ray, &base);
+ if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius
&& vec_scalar_mul(ray->direction, vec_diff(cylinder->center, base.point)) > 0)
- return (res);
- return (NAN);
+ ft_vec_append(&res, &arg);
+ return (res);
}
t_pair solve_quadratic(double a, double b, double c)
return (res);
}
-double get_intersection_arg_cylinder_around
+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),
intersect = ray_point(ray, args.first);
if (fabs(vec_scalar_mul(cylinder->rot_axis, vec_diff(intersect, cylinder->center))) < cylinder->height / 2
&& vec_scalar_mul(vec_vec_mul(cylinder->rot_axis, ray->direction), vec_vec_mul(cylinder->rot_axis, vec_diff(cylinder->center, intersect))) > 0)
- return (args.first);
+ 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
&& vec_scalar_mul(vec_vec_mul(cylinder->rot_axis, ray->direction), vec_vec_mul(cylinder->rot_axis, vec_diff(cylinder->center, intersect))) > 0)
- return (args.second);
- return (NAN);
+ ft_vec_append(&res, &args.second);
+ return (res);
}
-double get_intersection_arg_cylinder
+t_vec get_intersection_arg_cylinder
(const t_ray *ray, const t_cylinder *cylinder)
{
- double res;
+ size_t i;
+ t_vec res;
+ t_vec res2;
+ const double *el;
res = get_intersection_arg_cylinder_base(ray, cylinder);
- if (isnan(res))
- res = get_intersection_arg_cylinder_around(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);
}
-double get_intersection_arg_sphere(const t_ray *ray, const t_sphere *sphere)
+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 (intersection_args.first > 0)
- return (intersection_args.first);
- else if (intersection_args.second > 0)
- return (intersection_args.second);
- else
- return (NAN);
+ 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);
}
-double get_intersection_arg_bounded(const t_ray *ray, const t_object *object)
+t_vec get_intersection_arg_bounded(const t_ray *ray, const t_object *object)
{
+ t_vec res;
+
if (object->type == SPHERE)
- return (get_intersection_arg_sphere(ray, &object->object.sphere));
+ res = get_intersection_arg_sphere(ray, &object->object.sphere);
else if (object->type == CYLINDER)
- return (get_intersection_arg_cylinder(ray, &object->object.cylinder));
+ res = get_intersection_arg_cylinder(ray, &object->object.cylinder);
else
- return (NAN);
+ ft_vec_init(&res, sizeof(double));
+ return (res);
}
-double get_intersection_arg(const t_ray *ray, const t_object *object)
+t_vec get_intersection_args(const t_ray *ray, const t_object *object)
{
+ t_vec res;
+
if (!is_bounded(object))
- return (get_intersection_arg_nonbounded(ray, object));
- else if (!intersects_circumsphere(ray, object))
- return (NAN);
+ res = get_intersection_arg_nonbounded(ray, object);
+ else if (intersects_circumsphere(ray, object))
+ res = get_intersection_arg_bounded(ray, object);
else
- return (get_intersection_arg_bounded(ray, object));
+ 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);
}
-const t_object *find_nearest_object(const t_ray *ray, const t_vec *objects,
- const t_object *ignored, double ignored_dist)
+double get_self_obstruction_limit(const t_object *object)
+{
+ return (get_circumsphere(object).radius * SELF_OBSTRUCTION_MULTIPLIER);
+}
+
+typedef struct s_obstruction
+{
+ const t_object *object;
+ double distance;
+} t_obstruction;
+
+t_obstruction find_nearest_obstruction(const t_ray *ray, const t_vec *objects,
+ const t_object *ignored)
{
size_t i;
- const t_object *object_found;
+ size_t j;
+ t_obstruction obstruction_found;
const t_object *object;
- double distance_found;
double distance;
+ double ignored_dist;
+ t_vec distances;
- object_found = NULL;
- distance_found = INFINITY;
+ if (ignored)
+ ignored_dist = get_self_obstruction_limit(ignored);
+ obstruction_found.object = NULL;
+ obstruction_found.distance = INFINITY;
i = 0;
while (i < objects->size)
{
object = ft_vec_caccess(objects, i++);
- distance = get_intersection_arg(ray, object);
- if (object == ignored && distance > 0 && distance < ignored_dist)
- continue ;
- if (0 < distance && distance < distance_found)
+ distances = get_intersection_args(ray, object);
+ j = 0;
+ while (j < distances.size)
{
- distance_found = distance;
- object_found = object;
+ 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;
+ }
}
+ ft_vec_free(&distances, NULL);
}
- return (object_found);
+ return (obstruction_found);
}
t_color get_ambient_color(const t_object *object, const t_ambient_light *amb)
return ((t_vec3){.x = 0, .y = 0, .z = 0});
}
-double get_self_obstruction_limit(const t_object *object)
-{
- return (get_circumsphere(object).radius * SELF_OBSTRUCTION_MULTIPLIER);
-}
-
t_color get_light_contribution(t_ray normal, const t_object *object, const t_light *light, const t_scene *scene)
{
t_ray new_ray;
- const t_object *obstruction;
+ t_obstruction obstruction;
double angle_multiplier;
double distance;
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_object(&new_ray, &scene->objects, object, get_self_obstruction_limit(object));
+ 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
- || distance < get_intersection_arg(&new_ray, obstruction)
- || get_intersection_arg(&new_ray, obstruction) < 0))
+ 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));
size_t i;
result = (t_color){.x = 0, .y = 0, .z = 0};
- normal_at_intersect.start = ray_point(ray, get_intersection_arg(ray, object));
+ 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);
{
const t_object *object_found;
- object_found = find_nearest_object(ray, &scene->objects, NULL, 0);
+ object_found = find_nearest_obstruction(ray, &scene->objects, NULL).object;
if (object_found)
return (get_object_color(ray, object_found, scene));
else