From 8b9ac284029e6c92943f99db9eb276cf35168813 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sat, 3 Feb 2024 19:36:41 +0000 Subject: [PATCH] Implement diffuse lighting --- src/raytracer/main.c | 114 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 4 deletions(-) diff --git a/src/raytracer/main.c b/src/raytracer/main.c index 6cb6a77..0c4847b 100644 --- a/src/raytracer/main.c +++ b/src/raytracer/main.c @@ -15,9 +15,28 @@ typedef struct { colour_t colour; } sphere_t; +typedef enum { + LIGHT_TYPE_POINT, + LIGHT_TYPE_DIRECTIONAL, + LIGHT_TYPE_AMBIENT, + + COUNT_LIGHT_TYPE, +} light_type_t; + +typedef struct { + light_type_t type; + f32 intensity; + union { + vec3f_t position; + vec3f_t direction; + }; +} light_t; + typedef struct { sphere_t *spheres; - u32 count; + light_t *lights; + u32 spheres_count; + u32 lights_count; } scene_t; typedef struct { @@ -29,6 +48,9 @@ solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction, sphere_t sphere); colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max, const scene_t *scene, colour_t default_colour); +f32 compute_lighting(vec3f_t P, vec3f_t N, const scene_t *scene); +f32 light_diffuse(f32 light_intensity, vec3f_t light_direction, + vec3f_t surface_normal); i32 main(i32 argc, char *argv[]) { colour_t bg = @@ -67,11 +89,37 @@ i32 main(i32 argc, char *argv[]) { (colour_t){ .rgba.r = 171, .rgba.g = 52, .rgba.b = 40, .rgba.a = 255}, }, + (sphere_t){ + .radius = 5000.0f, + .centre = (vec3f_t){.x = 0.0f, .y = -5001.0f, .z = 0.0f}, + .colour = + (colour_t){ + .rgba.r = 255, .rgba.g = 255, .rgba.b = 0, .rgba.a = 255}, + }, + }; + + light_t lights[] = { + (light_t){ + .type = LIGHT_TYPE_AMBIENT, + .intensity = 0.2f, + }, + (light_t){ + .type = LIGHT_TYPE_POINT, + .intensity = 0.6f, + .position = (vec3f_t){.x = 2.0f, .y = 1.0f, .z = 0.0f}, + }, + (light_t){ + .type = LIGHT_TYPE_DIRECTIONAL, + .intensity = 0.2f, + .direction = (vec3f_t){.x = 1.0f, .y = 4.0f, .z = 4.0f}, + }, }; scene_t scene = { .spheres = spheres, - .count = ARR_LEN(spheres), + .lights = lights, + .spheres_count = ARR_LEN(spheres), + .lights_count = ARR_LEN(lights), }; i32 w_min = ((i32)window.half_width) * -1; @@ -131,7 +179,7 @@ colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max, f32 closest_t = INFINITY; sphere_t *closest_sphere = NULL; - for (u32 i = 0; i < scene->count; ++i) { + for (u32 i = 0; i < scene->spheres_count; ++i) { solutions_t solutions = ray_intersects_sphere(origin, direction, scene->spheres[i]); @@ -152,5 +200,63 @@ colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max, return default_colour; } - return closest_sphere->colour; + vec3f_t P = + vec_add(vec3f_t, origin, vec_mul_num(vec3f_t, direction, closest_t)); + vec3f_t N = vec_sub(vec3f_t, P, closest_sphere->centre); + N = vec_div_num(vec3f_t, N, vec_magnitude(vec3f_t, N)); + + f32 light = compute_lighting(P, N, scene); + + return (colour_t){.rgba.r = closest_sphere->colour.rgba.r * light, + .rgba.g = closest_sphere->colour.rgba.g * light, + .rgba.b = closest_sphere->colour.rgba.b * light, + .rgba.a = closest_sphere->colour.rgba.a}; +} + +f32 compute_lighting(vec3f_t P, vec3f_t N, const scene_t *scene) { + f32 I = 0.0f; + light_t light = {0}; + + for (u32 i = 0; i < scene->lights_count; ++i) { + light = scene->lights[i]; + + if (light.type == LIGHT_TYPE_AMBIENT) { + I += light.intensity; + } else { + vec3f_t L = {0}; + + switch (light.type) { + case LIGHT_TYPE_POINT: + L = vec_sub(vec3f_t, light.position, P); + break; + case LIGHT_TYPE_DIRECTIONAL: + L = light.direction; + break; + default: + break; + } + + I += light_diffuse(light.intensity, L, N); + } + } + + return I; +} + +f32 light_diffuse(f32 light_intensity, vec3f_t light_direction, + vec3f_t surface_normal) { + f32 dot_product = vec_dot(vec3f_t, light_direction, surface_normal); + + if (dot_product < 0.0f) { + return 0.0f; + } + + f32 divisor = vec_magnitude(vec3f_t, light_direction) * + vec_magnitude(vec3f_t, surface_normal); + + if (divisor == 0.0f) { + return 0.0f; + } + + return light_intensity * dot_product / divisor; }