From a8bc305a20981167763e6d13aa5afde896aebd81 Mon Sep 17 00:00:00 2001 From: Lukas Jiriste Date: Tue, 26 Nov 2024 19:55:06 +0100 Subject: [PATCH] Implement Lambertian diffuse lighting (kind of) This implementation has its problems. The one I can think of now is that planes are only reflecting, when their normal points in the direction of the light. --- src/scene.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/src/scene.c b/src/scene.c index 841af39..02105b5 100644 --- a/src/scene.c +++ b/src/scene.c @@ -42,6 +42,12 @@ double dist_point_from_line(const t_ray *ray, t_vec3 point) 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))); @@ -231,28 +237,80 @@ t_color get_ambient_color(const t_object *object, const t_ambient_light *amb) 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)); + 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_vec3 point, const t_object *object, const t_light *light, const t_scene *scene) +{ + t_ray new_ray; + const t_object *obstruction; + t_vec3 normal; + double angle_multiplier; + + new_ray.start = point; + new_ray.direction = vec_diff(light->position, new_ray.start); + obstruction = find_nearest_object(&new_ray, &scene->objects); + normal = get_object_normal(object, point); + angle_multiplier = vec_scalar_mul(normal, new_ray.direction) + / (vec_norm(normal) * vec_norm(new_ray.direction)); + if (angle_multiplier > 0 && (!obstruction + || 1 < get_intersection_arg(&new_ray, obstruction) + || get_intersection_arg(&new_ray, obstruction) < 0)) + return (vec_real_mul( + vec_elwise_mul(light->color, object->object.plane.color), + light->brightness * angle_multiplier)); + else + return ((t_color){.x = 0, .y = 0, .z = 0}); +} + t_color get_object_color(const t_ray *ray, const t_object *object, const t_scene *scene) { t_color result; const t_light *light; size_t i; - t_ray new_ray; - const t_object *obstruction; result = (t_color){.x = 0, .y = 0, .z = 0}; i = 0; while (i < scene->lights.size) { light = ft_vec_caccess(&scene->lights, i); - new_ray.start = vec_add(ray->start, vec_real_mul(ray->direction, - get_intersection_arg(ray, object))); - new_ray.direction = vec_diff(light->position, new_ray.start); - obstruction = find_nearest_object(&new_ray, &scene->objects); - if (!obstruction || 1 < get_intersection_arg(&new_ray, obstruction) - || get_intersection_arg(&new_ray, obstruction) < 0) - result = vec_add(result, vec_real_mul(vec_elwise_mul(light->color, - object->object.plane.color), light->brightness)); + result = vec_add(result, get_light_contribution( + ray_point(ray, get_intersection_arg(ray, object)), + object, light, scene)); ++i; } result = vec_add(result, get_ambient_color(object, &scene->ambient_light)); -- 2.30.2