diff --git a/miniRT.h b/miniRT.h index dbbad10..3277896 100644 --- a/miniRT.h +++ b/miniRT.h @@ -6,7 +6,7 @@ /* By: yantoine +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/13 20:02:36 by yantoine #+# #+# */ -/* Updated: 2025/02/17 18:19:10 by yantoine ### ########.fr */ +/* Updated: 2025/02/17 18:58:31 by yantoine ### ########.fr */ /* */ /* ************************************************************************** */ @@ -176,4 +176,10 @@ inline char **get_tokens_secure(t_scene scene, const int numObject, const int nu // Check inline int check_tokens(char **tokens, const int to_test, int expected); inline void check_if_max(t_scene scene, const int to_test, const int max); + +// Intersection +float intersectCylinder(Ray ray, Cylinder cy, t_vec3 *hitNormal); +float intersectPlane(Ray ray, Plane p, t_vec3 *hitNormal); +float intersectSphere(Ray ray, Sphere s, t_vec3 *hitNormal); +bool isInShadow(t_vec3 hitPoint, t_vec3 lightPos); #endif diff --git a/parsing_cylinder.c b/parsing_cylinder.c index f5c08b4..cdf4b87 100644 --- a/parsing_cylinder.c +++ b/parsing_cylinder.c @@ -6,7 +6,7 @@ /* By: yantoine +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/02/15 19:54:13 by yantoine #+# #+# */ -/* Updated: 2025/02/17 18:21:13 by yantoine ### ########.fr */ +/* Updated: 2025/02/17 18:55:52 by yantoine ### ########.fr */ /* */ /* ************************************************************************** */ @@ -106,100 +106,4 @@ t_scene parsing_cylinder(const char *line, t_scene scene) return (scene); } -// Initialise les variables de calcul et les coefficients du polynôme d'intersection -static int init_intersection(Ray ray, Cylinder cy, t_calc *calc) { - calc->d = ray.dir; - calc->oc = vec3_sub(ray.origin, cy.center); - calc->v = cy.axis; - calc->d_dot_v = vec3_dot(calc->d, calc->v); - calc->oc_dot_v = vec3_dot(calc->oc, calc->v); - calc->d_perp = vec3_sub(calc->d, vec3_scale(calc->v, calc->d_dot_v)); - calc->oc_perp = vec3_sub(calc->oc, vec3_scale(calc->v, calc->oc_dot_v)); - calc->a = vec3_dot(calc->d_perp, calc->d_perp); - calc->b = 2 * vec3_dot(calc->d_perp, calc->oc_perp); - calc->c = vec3_dot(calc->oc_perp, calc->oc_perp) - cy.radius * cy.radius; - calc->disc = calc->b * calc->b - 4 * calc->a * calc->c; - if (calc->disc < 0) - return -1; - calc->sqrtDisc = sqrtf(calc->disc); - calc->t0 = (-calc->b - calc->sqrtDisc) / (2 * calc->a); - calc->t1 = (-calc->b + calc->sqrtDisc) / (2 * calc->a); - return 0; -} - -// Calcule l'intersection sur la surface latérale du cylindre -static void compute_side_intersection(Ray ray, Cylinder cy, t_calc *calc) { - calc->t_side = -1; - if (calc->t0 > 1e-3f) { - calc->y = calc->oc_dot_v + calc->t0 * calc->d_dot_v; - if (fabs(calc->y) <= cy.height / 2.0f) - calc->t_side = calc->t0; - } - if (calc->t_side < 0 && calc->t1 > 1e-3f) { - calc->y = calc->oc_dot_v + calc->t1 * calc->d_dot_v; - if (fabs(calc->y) <= cy.height / 2.0f) - calc->t_side = calc->t1; - } -} - -// Calcule l'intersection sur les capuchons supérieur et inférieur -static void compute_cap_intersection(Ray ray, Cylinder cy, t_calc *calc) { - calc->t_cap = -1; - if (fabs(calc->d_dot_v) > 1e-6f) { - calc->t_bot = ((-cy.height / 2.0f) - calc->oc_dot_v) / calc->d_dot_v; - if (calc->t_bot > 1e-3f) { - calc->p = vec3_add(ray.origin, vec3_scale(calc->d, calc->t_bot)); - calc->cp = vec3_sub(calc->p, cy.center); - calc->dist = vec3_length(vec3_sub(calc->cp, vec3_scale(calc->v, vec3_dot(calc->cp, calc->v)))); - if (calc->dist <= cy.radius) - calc->t_cap = calc->t_bot; - } - calc->t_top = ((cy.height / 2.0f) - calc->oc_dot_v) / calc->d_dot_v; - if (calc->t_top > 1e-3f) { - calc->p = vec3_add(ray.origin, vec3_scale(calc->d, calc->t_top)); - calc->cp = vec3_sub(calc->p, cy.center); - calc->dist = vec3_length(vec3_sub(calc->cp, vec3_scale(calc->v, vec3_dot(calc->cp, calc->v)))); - if (calc->dist <= cy.radius && (calc->t_cap < 0 || calc->t_top < calc->t_cap)) - calc->t_cap = calc->t_top; - } - } -} - -// Sélectionne l'intersection la plus proche entre la surface latérale et les capuchons -static float select_final_intersection(t_calc *calc) { - if (calc->t_side > 1e-3f && calc->t_cap > 1e-3f) - calc->t_final = (calc->t_side < calc->t_cap) ? calc->t_side : calc->t_cap; - else if (calc->t_side > 1e-3f) - calc->t_final = calc->t_side; - else - calc->t_final = calc->t_cap; - return (calc->t_final > 1e-3f) ? calc->t_final : -1; -} - -// Calcule la normale au point d'intersection -static void compute_hit_normal(Ray ray, Cylinder cy, t_calc *calc, t_vec3 *hitNormal) { - calc->hitPoint = vec3_add(ray.origin, vec3_scale(calc->d, calc->t_final)); - calc->cp = vec3_sub(calc->hitPoint, cy.center); - calc->proj = vec3_dot(calc->cp, calc->v); - if (fabs(calc->proj) < cy.height / 2.0f - 1e-3f) { - calc->n = vec3_sub(calc->cp, vec3_scale(calc->v, calc->proj)); - *hitNormal = vec3_normalize(calc->n); - } else { - *hitNormal = (calc->proj > 0) ? calc->v : vec3_scale(calc->v, -1); - } -} - -// Fonction principale d'intersection du cylindre -float intersectCylinder(Ray ray, Cylinder cy, t_vec3 *hitNormal) { - t_calc calc; - if (init_intersection(ray, cy, &calc) < 0) - return -1; - compute_side_intersection(ray, cy, &calc); - compute_cap_intersection(ray, cy, &calc); - if (select_final_intersection(&calc) < 0) - return -1; - compute_hit_normal(ray, cy, &calc, hitNormal); - return calc.t_final; -} - diff --git a/parsing_cylinder_utils.c b/parsing_cylinder_utils.c new file mode 100644 index 0000000..5312ee1 --- /dev/null +++ b/parsing_cylinder_utils.c @@ -0,0 +1,111 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parsing_cylinder_utils.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: yantoine +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/17 18:54:45 by yantoine #+# #+# */ +/* Updated: 2025/02/17 18:54:46 by yantoine ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "miniRT.h" + +// Initialise les variables de calcul et les coefficients du polynôme d'intersection +static int init_intersection(Ray ray, Cylinder cy, t_calc *calc) { + calc->d = ray.dir; + calc->oc = vec3_sub(ray.origin, cy.center); + calc->v = cy.axis; + calc->d_dot_v = vec3_dot(calc->d, calc->v); + calc->oc_dot_v = vec3_dot(calc->oc, calc->v); + calc->d_perp = vec3_sub(calc->d, vec3_scale(calc->v, calc->d_dot_v)); + calc->oc_perp = vec3_sub(calc->oc, vec3_scale(calc->v, calc->oc_dot_v)); + calc->a = vec3_dot(calc->d_perp, calc->d_perp); + calc->b = 2 * vec3_dot(calc->d_perp, calc->oc_perp); + calc->c = vec3_dot(calc->oc_perp, calc->oc_perp) - cy.radius * cy.radius; + calc->disc = calc->b * calc->b - 4 * calc->a * calc->c; + if (calc->disc < 0) + return -1; + calc->sqrtDisc = sqrtf(calc->disc); + calc->t0 = (-calc->b - calc->sqrtDisc) / (2 * calc->a); + calc->t1 = (-calc->b + calc->sqrtDisc) / (2 * calc->a); + return 0; +} + +// Calcule l'intersection sur la surface latérale du cylindre +static void compute_side_intersection(Ray ray, Cylinder cy, t_calc *calc) { + calc->t_side = -1; + if (calc->t0 > 1e-3f) { + calc->y = calc->oc_dot_v + calc->t0 * calc->d_dot_v; + if (fabs(calc->y) <= cy.height / 2.0f) + calc->t_side = calc->t0; + } + if (calc->t_side < 0 && calc->t1 > 1e-3f) { + calc->y = calc->oc_dot_v + calc->t1 * calc->d_dot_v; + if (fabs(calc->y) <= cy.height / 2.0f) + calc->t_side = calc->t1; + } +} + +// Calcule l'intersection sur les capuchons supérieur et inférieur +static void compute_cap_intersection(Ray ray, Cylinder cy, t_calc *calc) { + calc->t_cap = -1; + if (fabs(calc->d_dot_v) > 1e-6f) { + calc->t_bot = ((-cy.height / 2.0f) - calc->oc_dot_v) / calc->d_dot_v; + if (calc->t_bot > 1e-3f) { + calc->p = vec3_add(ray.origin, vec3_scale(calc->d, calc->t_bot)); + calc->cp = vec3_sub(calc->p, cy.center); + calc->dist = vec3_length(vec3_sub(calc->cp, vec3_scale(calc->v, vec3_dot(calc->cp, calc->v)))); + if (calc->dist <= cy.radius) + calc->t_cap = calc->t_bot; + } + calc->t_top = ((cy.height / 2.0f) - calc->oc_dot_v) / calc->d_dot_v; + if (calc->t_top > 1e-3f) { + calc->p = vec3_add(ray.origin, vec3_scale(calc->d, calc->t_top)); + calc->cp = vec3_sub(calc->p, cy.center); + calc->dist = vec3_length(vec3_sub(calc->cp, vec3_scale(calc->v, vec3_dot(calc->cp, calc->v)))); + if (calc->dist <= cy.radius && (calc->t_cap < 0 || calc->t_top < calc->t_cap)) + calc->t_cap = calc->t_top; + } + } +} + +// Sélectionne l'intersection la plus proche entre la surface latérale et les capuchons +static float select_final_intersection(t_calc *calc) { + if (calc->t_side > 1e-3f && calc->t_cap > 1e-3f) + calc->t_final = (calc->t_side < calc->t_cap) ? calc->t_side : calc->t_cap; + else if (calc->t_side > 1e-3f) + calc->t_final = calc->t_side; + else + calc->t_final = calc->t_cap; + return (calc->t_final > 1e-3f) ? calc->t_final : -1; +} + +// Calcule la normale au point d'intersection +static void compute_hit_normal(Ray ray, Cylinder cy, t_calc *calc, t_vec3 *hitNormal) { + calc->hitPoint = vec3_add(ray.origin, vec3_scale(calc->d, calc->t_final)); + calc->cp = vec3_sub(calc->hitPoint, cy.center); + calc->proj = vec3_dot(calc->cp, calc->v); + if (fabs(calc->proj) < cy.height / 2.0f - 1e-3f) { + calc->n = vec3_sub(calc->cp, vec3_scale(calc->v, calc->proj)); + *hitNormal = vec3_normalize(calc->n); + } else { + *hitNormal = (calc->proj > 0) ? calc->v : vec3_scale(calc->v, -1); + } +} + +// Fonction principale d'intersection du cylindre +float intersectCylinder(Ray ray, Cylinder cy, t_vec3 *hitNormal) { + t_calc calc; + if (init_intersection(ray, cy, &calc) < 0) + return -1; + compute_side_intersection(ray, cy, &calc); + compute_cap_intersection(ray, cy, &calc); + if (select_final_intersection(&calc) < 0) + return -1; + compute_hit_normal(ray, cy, &calc, hitNormal); + return calc.t_final; +} + + diff --git a/shadows.c b/shadows.c new file mode 100644 index 0000000..3871d8f --- /dev/null +++ b/shadows.c @@ -0,0 +1,76 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* shadows.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: yantoine +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/17 18:58:42 by yantoine #+# #+# */ +/* Updated: 2025/02/17 19:03:01 by yantoine ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "miniRT.h" + +// Vérifie les intersections avec les sphères +static bool checkShadowSphere(const Ray shadowRay, float maxT, float epsilon) { + int i = 0; + t_vec3 dummy; + float t; + while (i < numSpheres) { + t = intersectSphere(shadowRay, spheres[i], &dummy); + if (t > epsilon && t < maxT) + return true; + i++; + } + return false; +} + +// Vérifie les intersections avec les plans +static bool checkShadowPlane(const Ray shadowRay, float maxT, float epsilon) { + int i = 0; + t_vec3 dummy; + float t; + while (i < numPlanes) { + t = intersectPlane(shadowRay, planes[i], &dummy); + if (t > epsilon && t < maxT) + return true; + i++; + } + return false; +} + +// Vérifie les intersections avec les cylindres +static bool checkShadowCylinder(const Ray shadowRay, float maxT, float epsilon) { + int i = 0; + t_vec3 dummy; + float t; + while (i < numCylinders) { + t = intersectCylinder(shadowRay, cylinders[i], &dummy); + if (t > epsilon && t < maxT) + return true; + i++; + } + return false; +} + +// Fonction principale qui détermine si le point est dans l'ombre +bool isInShadow(t_vec3 hitPoint, t_vec3 lightPos) { + const float epsilon = 1e-3f; + t_vec3 toLight = vec3_sub(lightPos, hitPoint); + float maxT = vec3_length(toLight); + t_vec3 L = vec3_normalize(toLight); + Ray shadowRay; + shadowRay.origin = vec3_add(hitPoint, vec3_scale(L, epsilon)); + shadowRay.direction = L; + + if (checkShadowSphere(shadowRay, maxT, epsilon)) + return true; + if (checkShadowPlane(shadowRay, maxT, epsilon)) + return true; + if (checkShadowCylinder(shadowRay, maxT, epsilon)) + return true; + + return false; +} + diff --git a/tags b/tags index 8d4adbb..ad8c37f 100644 --- a/tags +++ b/tags @@ -89,6 +89,7 @@ b miniRT.h /^ float b;$/;" m struct:s_calc typeref:typename:float better_ray_tracer README.md /^# better_ray_tracer/;" c brightness miniRT.h /^ float brightness;$/;" m struct:s_light typeref:typename:float c miniRT.h /^ float c;$/;" m struct:s_calc typeref:typename:float +calcLighting trace.c /^t_vec3 calcLighting(t_vec3 hitPoint, t_vec3 hitNormal, t_vec3 objColor) {$/;" f typeref:typename:t_vec3 camDir miniRT.h /^ t_vec3 camDir;$/;" m struct:s_camera typeref:typename:t_vec3 camDir raytracer_formatted.c /^t_vec3 camDir = {0.0f, 0.0f, -1.0f};$/;" v typeref:typename:t_vec3 camPos miniRT.h /^ t_vec3 camPos;$/;" m struct:s_camera typeref:typename:t_vec3 @@ -96,15 +97,18 @@ camPos raytracer_formatted.c /^t_vec3 camPos = {0.0f, 0.0f, 0.0f};$/;" v typ camera miniRT.h /^ t_camera camera;$/;" m struct:s_scene typeref:typename:t_camera center miniRT.h /^ t_vec3 center;$/;" m struct:s_cylinder typeref:typename:t_vec3 center miniRT.h /^ t_vec3 center;$/;" m struct:s_sphere typeref:typename:t_vec3 +checkShadowCylinder shadows.c /^static bool checkShadowCylinder(const Ray shadowRay, float maxT, float epsilon) {$/;" f typeref:typename:bool file: +checkShadowPlane shadows.c /^static bool checkShadowPlane(const Ray shadowRay, float maxT, float epsilon) {$/;" f typeref:typename:bool file: +checkShadowSphere shadows.c /^static bool checkShadowSphere(const Ray shadowRay, float maxT, float epsilon) {$/;" f typeref:typename:bool file: check_if_max check.c /^inline void check_if_max(t_scene scene, const int to_test, const int max)$/;" f typeref:typename:void check_tokens check.c /^inline int check_tokens(char **tokens, int expected)$/;" f typeref:typename:int color miniRT.h /^ t_vec3 color;$/;" m struct:s_cylinder typeref:typename:t_vec3 color miniRT.h /^ t_vec3 color;$/;" m struct:s_light typeref:typename:t_vec3 color miniRT.h /^ t_vec3 color;$/;" m struct:s_plane typeref:typename:t_vec3 color miniRT.h /^ t_vec3 color;$/;" m struct:s_sphere typeref:typename:t_vec3 -compute_cap_intersection parsing_cylinder.c /^static void compute_cap_intersection(Ray ray, Cylinder cy, t_calc *calc) {$/;" f typeref:typename:void file: -compute_hit_normal parsing_cylinder.c /^static void compute_hit_normal(Ray ray, Cylinder cy, t_calc *calc, t_vec3 *hitNormal) {$/;" f typeref:typename:void file: -compute_side_intersection parsing_cylinder.c /^static void compute_side_intersection(Ray ray, Cylinder cy, t_calc *calc) {$/;" f typeref:typename:void file: +compute_cap_intersection parsing_cylinder_utils.c /^static void compute_cap_intersection(Ray ray, Cylinder cy, t_calc *calc) {$/;" f typeref:typename:void file: +compute_hit_normal parsing_cylinder_utils.c /^static void compute_hit_normal(Ray ray, Cylinder cy, t_calc *calc, t_vec3 *hitNormal) {$/;" f typeref:typename:void file: +compute_side_intersection parsing_cylinder_utils.c /^static void compute_side_intersection(Ray ray, Cylinder cy, t_calc *calc) {$/;" f typeref:typename:void file: cp miniRT.h /^ t_vec3 cp;$/;" m struct:s_calc typeref:typename:t_vec3 create_scene scene.c /^t_scene create_scene(void)$/;" f typeref:typename:t_scene cylinders miniRT.h /^ t_cylinder cylinders[MAX_CYLINDERS];$/;" m struct:s_scene typeref:typename:t_cylinder[] @@ -120,14 +124,16 @@ fov raytracer_formatted.c /^float fov = 90.0f;$/;" v typeref:typename:float get_tokens_secure parsing_utils.c /^inline char **get_tokens_secure(t_scene scene, const int numObject, const int numObjectMax, cons/;" f typeref:typename:char ** height miniRT.h /^ float height;$/;" m struct:s_cylinder typeref:typename:float hitPoint miniRT.h /^ t_vec3 hitPoint;$/;" m struct:s_calc typeref:typename:t_vec3 -init_intersection parsing_cylinder.c /^static int init_intersection(Ray ray, Cylinder cy, t_calc *calc) {$/;" f typeref:typename:int file: -intersectCylinder parsing_cylinder.c /^float intersectCylinder(Ray ray, Cylinder cy, t_vec3 *hitNormal) {$/;" f typeref:typename:float +init_intersection parsing_cylinder_utils.c /^static int init_intersection(Ray ray, Cylinder cy, t_calc *calc) {$/;" f typeref:typename:int file: +intersectCylinder parsing_cylinder_utils.c /^float intersectCylinder(Ray ray, Cylinder cy, t_vec3 *hitNormal) {$/;" f typeref:typename:float intersectCylinder raytracer_formatted.c /^float intersectCylinder(Ray ray, Cylinder cy, t_vec3 *hitNormal)$/;" f typeref:typename:float +intersectObjects trace.c /^bool intersectObjects(Ray ray, float *tMin, t_vec3 *hitNormal, t_vec3 *objColor) {$/;" f typeref:typename:bool intersectPlane parsing_plane.c /^float intersectPlane(Ray ray, Plane p, t_vec3 *hitNormal)$/;" f typeref:typename:float intersectPlane raytracer_formatted.c /^float intersectPlane(Ray ray, Plane p, t_vec3 *hitNormal)$/;" f typeref:typename:float intersectSphere parsing_sphere.c /^float intersectSphere(Ray ray, Sphere s, t_vec3 *hitNormal)$/;" f typeref:typename:float intersectSphere raytracer_formatted.c /^float intersectSphere(Ray ray, Sphere s, t_vec3 *hitNormal)$/;" f typeref:typename:float isInShadow raytracer_formatted.c /^bool isInShadow(t_vec3 hitPoint, t_vec3 lightPos)$/;" f typeref:typename:bool +isInShadow shadows.c /^bool isInShadow(t_vec3 hitPoint, t_vec3 lightPos) {$/;" f typeref:typename:bool lights miniRT.h /^ t_light lights[MAX_LIGHTS];$/;" m struct:s_scene typeref:typename:t_light[] line_if_exit miniRT.h /^ const char *line_if_exit;$/;" m struct:s_scene typeref:typename:const char * load_config config.c /^t_scene load_config(const char *filename)$/;" f typeref:typename:t_scene @@ -175,7 +181,7 @@ s_ray miniRT.h /^typedef struct s_ray$/;" s s_scene miniRT.h /^typedef struct s_scene$/;" s s_sphere miniRT.h /^typedef struct s_sphere$/;" s s_vec3 miniRT.h /^typedef struct s_vec3$/;" s -select_final_intersection parsing_cylinder.c /^static float select_final_intersection(t_calc *calc) {$/;" f typeref:typename:float file: +select_final_intersection parsing_cylinder_utils.c /^static float select_final_intersection(t_calc *calc) {$/;" f typeref:typename:float file: spheres miniRT.h /^ t_sphere spheres[MAX_SPHERES];$/;" m struct:s_scene typeref:typename:t_sphere[] sqrtDisc miniRT.h /^ float sqrtDisc;$/;" m struct:s_calc typeref:typename:float t miniRT.h /^ float t;$/;" m struct:s_calc typeref:typename:float @@ -198,6 +204,7 @@ t_top miniRT.h /^ float t_top;$/;" m struct:s_calc typeref:typename:float t_vec3 miniRT.h /^} t_vec3;$/;" t typeref:struct:s_vec3 token_if_exit miniRT.h /^ const char **token_if_exit;$/;" m struct:s_scene typeref:typename:const char ** trace raytracer_formatted.c /^t_vec3 trace(Ray ray)$/;" f typeref:typename:t_vec3 +trace trace.c /^t_vec3 trace(Ray ray) {$/;" f typeref:typename:t_vec3 v miniRT.h /^ t_vec3 v;$/;" m struct:s_calc typeref:typename:t_vec3 vec3_add calcul_de_vecteur.c /^t_vec3 vec3_add(t_vec3 a, t_vec3 b)$/;" f typeref:typename:t_vec3 vec3_cross calcul_de_vecteur.c /^t_vec3 vec3_cross(t_vec3 a, t_vec3 b)$/;" f typeref:typename:t_vec3 diff --git a/trace.c b/trace.c new file mode 100644 index 0000000..dc6dc86 --- /dev/null +++ b/trace.c @@ -0,0 +1,79 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* trace.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: yantoine +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/02/17 19:07:07 by yantoine #+# #+# */ +/* Updated: 2025/02/17 19:10:35 by yantoine ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "miniRT.h" + +#include "miniRT.h" + +// Renvoie true si le rayon intersecte un objet, et met à jour tMin, hitNormal et objColor +bool intersectObjects(Ray ray, float *tMin, t_vec3 *hitNormal, t_vec3 *objColor) { + bool hit = false; + float t; + t_vec3 n; + int i = 0; + while (i < numSpheres) { + t = intersectSphere(ray, spheres[i], &n); + if (t > 1e-3f && t < *tMin) { *tMin = t; *hitNormal = n; *objColor = spheres[i].color; hit = true; } + i++; + } + i = 0; + while (i < numPlanes) { + t = intersectPlane(ray, planes[i], &n); + if (t > 1e-3f && t < *tMin) { *tMin = t; *hitNormal = n; *objColor = planes[i].color; hit = true; } + i++; + } + i = 0; + while (i < numCylinders) { + t = intersectCylinder(ray, cylinders[i], &n); + if (t > 1e-3f && t < *tMin) { *tMin = t; *hitNormal = n; *objColor = cylinders[i].color; hit = true; } + i++; + } + return hit; +} + +// Calcule l'éclairage (ambiant, diffus et spéculaire) sur un point d'impact +t_vec3 calcLighting(t_vec3 hitPoint, t_vec3 hitNormal, t_vec3 objColor) { + t_vec3 color = vec3_scale(objColor, ambient_ratio); + int i = 0; + while (i < numLights) { + Light light = lights[i]; + t_vec3 L = vec3_normalize(vec3_sub(light.pos, hitPoint)); + if (!isInShadow(hitPoint, light.pos)) { + float diff = fmaxf(0.0f, vec3_dot(hitNormal, L)); + t_vec3 viewDir = vec3_normalize(vec3_sub(camPos, hitPoint)); + t_vec3 halfDir = vec3_normalize(vec3_add(L, viewDir)); + float spec = powf(fmaxf(0.0f, vec3_dot(hitNormal, halfDir)), 32.0f); + color = vec3_add(color, vec3_scale(vec3_mul(objColor, light.color), + diff * light.brightness)); + color = vec3_add(color, vec3_scale((t_vec3){1, 1, 1}, + spec * light.brightness)); + } + i++; + } + if (color.x > 1.0f) color.x = 1.0f; + if (color.y > 1.0f) color.y = 1.0f; + if (color.z > 1.0f) color.z = 1.0f; + return color; +} + +// Fonction principale de lancer de rayon (trace) +t_vec3 trace(Ray ray) { + float tMin = 1e9; + t_vec3 hitNormal = {0, 0, 0}; + t_vec3 objColor = {0, 0, 0}; + if (intersectObjects(ray, &tMin, &hitNormal, &objColor)) { + t_vec3 hitPoint = vec3_add(ray.origin, vec3_scale(ray.dir, tMin)); + return calcLighting(hitPoint, hitNormal, objColor); + } + return (t_vec3){0.2f, 0.7f, 1.0f}; // Couleur de fond (ciel) +} +