Implement specularity

This commit is contained in:
Abdelrahman Said 2024-02-03 22:09:12 +00:00
parent 8b9ac28402
commit 451aa48b3a

View File

@ -4,6 +4,7 @@
#include "window/window.h" #include "window/window.h"
#include <math.h> #include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -13,6 +14,7 @@ typedef struct {
f32 radius; f32 radius;
vec3f_t centre; vec3f_t centre;
colour_t colour; colour_t colour;
f32 specular;
} sphere_t; } sphere_t;
typedef enum { typedef enum {
@ -48,9 +50,16 @@ solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
sphere_t sphere); sphere_t sphere);
colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max, colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
const scene_t *scene, colour_t default_colour); const scene_t *scene, colour_t default_colour);
f32 compute_lighting(vec3f_t P, vec3f_t N, const scene_t *scene); f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,
vec3f_t view_vector, f32 specular_exponent,
const scene_t *scene);
f32 light_diffuse(f32 light_intensity, vec3f_t light_direction, f32 light_diffuse(f32 light_intensity, vec3f_t light_direction,
vec3f_t surface_normal); vec3f_t surface_normal);
f32 light_specular(f32 light_intensity, vec3f_t light_direction,
vec3f_t surface_normal, vec3f_t view_vector,
f32 specular_exponent);
f32 cos_angle_between_vectors(vec3f_t v1, vec3f_t v2);
f32 clamp(f32 value, f32 min, f32 max);
i32 main(i32 argc, char *argv[]) { i32 main(i32 argc, char *argv[]) {
colour_t bg = colour_t bg =
@ -74,6 +83,7 @@ i32 main(i32 argc, char *argv[]) {
.colour = .colour =
(colour_t){ (colour_t){
.rgba.r = 245, .rgba.g = 238, .rgba.b = 158, .rgba.a = 255}, .rgba.r = 245, .rgba.g = 238, .rgba.b = 158, .rgba.a = 255},
.specular = 500.0f,
}, },
(sphere_t){ (sphere_t){
.radius = 1.0f, .radius = 1.0f,
@ -81,6 +91,7 @@ i32 main(i32 argc, char *argv[]) {
.colour = .colour =
(colour_t){ (colour_t){
.rgba.r = 59, .rgba.g = 142, .rgba.b = 165, .rgba.a = 255}, .rgba.r = 59, .rgba.g = 142, .rgba.b = 165, .rgba.a = 255},
.specular = 10.0f,
}, },
(sphere_t){ (sphere_t){
.radius = 1.0f, .radius = 1.0f,
@ -88,6 +99,7 @@ i32 main(i32 argc, char *argv[]) {
.colour = .colour =
(colour_t){ (colour_t){
.rgba.r = 171, .rgba.g = 52, .rgba.b = 40, .rgba.a = 255}, .rgba.r = 171, .rgba.g = 52, .rgba.b = 40, .rgba.a = 255},
.specular = 500.0f,
}, },
(sphere_t){ (sphere_t){
.radius = 5000.0f, .radius = 5000.0f,
@ -95,6 +107,7 @@ i32 main(i32 argc, char *argv[]) {
.colour = .colour =
(colour_t){ (colour_t){
.rgba.r = 255, .rgba.g = 255, .rgba.b = 0, .rgba.a = 255}, .rgba.r = 255, .rgba.g = 255, .rgba.b = 0, .rgba.a = 255},
.specular = 1000.0f,
}, },
}; };
@ -200,20 +213,34 @@ colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
return default_colour; return default_colour;
} }
vec3f_t P = vec3f_t position =
vec_add(vec3f_t, origin, vec_mul_num(vec3f_t, direction, closest_t)); 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); vec3f_t surface_normal = vec_sub(vec3f_t, position, closest_sphere->centre);
surface_normal = vec_div_num(vec3f_t, surface_normal,
vec_magnitude(vec3f_t, surface_normal));
return (colour_t){.rgba.r = closest_sphere->colour.rgba.r * light, vec3f_t view_vector = vec_mul_num(vec3f_t, direction, -1.0f);
.rgba.g = closest_sphere->colour.rgba.g * light,
.rgba.b = closest_sphere->colour.rgba.b * light, f32 light = compute_lighting(position, surface_normal, view_vector,
closest_sphere->specular, scene);
f32 r = (f32)(closest_sphere->colour.rgba.r) * light;
r = clamp(r, 0.0f, (f32)UINT8_MAX);
f32 g = (f32)(closest_sphere->colour.rgba.g) * light;
g = clamp(g, 0.0f, (f32)UINT8_MAX);
f32 b = (f32)(closest_sphere->colour.rgba.b) * light;
b = clamp(b, 0.0f, (f32)UINT8_MAX);
return (colour_t){.rgba.r = (u8)r,
.rgba.g = (u8)g,
.rgba.b = (u8)b,
.rgba.a = closest_sphere->colour.rgba.a}; .rgba.a = closest_sphere->colour.rgba.a};
} }
f32 compute_lighting(vec3f_t P, vec3f_t N, const scene_t *scene) { f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,
vec3f_t view_vector, f32 specular_exponent,
const scene_t *scene) {
f32 I = 0.0f; f32 I = 0.0f;
light_t light = {0}; light_t light = {0};
@ -223,20 +250,25 @@ f32 compute_lighting(vec3f_t P, vec3f_t N, const scene_t *scene) {
if (light.type == LIGHT_TYPE_AMBIENT) { if (light.type == LIGHT_TYPE_AMBIENT) {
I += light.intensity; I += light.intensity;
} else { } else {
vec3f_t L = {0}; vec3f_t light_direction = {0};
switch (light.type) { switch (light.type) {
case LIGHT_TYPE_POINT: case LIGHT_TYPE_POINT:
L = vec_sub(vec3f_t, light.position, P); light_direction = vec_sub(vec3f_t, light.position, position);
break; break;
case LIGHT_TYPE_DIRECTIONAL: case LIGHT_TYPE_DIRECTIONAL:
L = light.direction; light_direction = light.direction;
break; break;
default: default:
break; break;
} }
I += light_diffuse(light.intensity, L, N); I += light_diffuse(light.intensity, light_direction, surface_normal);
if (specular_exponent != -1.0f) {
I += light_specular(light.intensity, light_direction, surface_normal,
view_vector, specular_exponent);
}
} }
} }
@ -245,18 +277,48 @@ f32 compute_lighting(vec3f_t P, vec3f_t N, const scene_t *scene) {
f32 light_diffuse(f32 light_intensity, vec3f_t light_direction, f32 light_diffuse(f32 light_intensity, vec3f_t light_direction,
vec3f_t surface_normal) { vec3f_t surface_normal) {
return light_intensity *
cos_angle_between_vectors(light_direction, surface_normal);
}
f32 light_specular(f32 light_intensity, vec3f_t light_direction,
vec3f_t surface_normal, vec3f_t view_vector,
f32 specular_exponent) {
vec3f_t _2N = vec_mul_num(vec3f_t, surface_normal, 2.0f);
f32 dot_product = vec_dot(vec3f_t, light_direction, surface_normal); f32 dot_product = vec_dot(vec3f_t, light_direction, surface_normal);
vec3f_t _2N_mul_dot = vec_mul_num(vec3f_t, _2N, dot_product);
vec3f_t R = vec_sub(vec3f_t, _2N_mul_dot, light_direction);
return light_intensity *
powf(cos_angle_between_vectors(R, view_vector), specular_exponent);
}
f32 cos_angle_between_vectors(vec3f_t v1, vec3f_t v2) {
f32 dot_product = vec_dot(vec3f_t, v1, v2);
if (dot_product < 0.0f) { if (dot_product < 0.0f) {
return 0.0f; return 0.0f;
} }
f32 divisor = vec_magnitude(vec3f_t, light_direction) * f32 divisor = vec_magnitude(vec3f_t, v1) * vec_magnitude(vec3f_t, v2);
vec_magnitude(vec3f_t, surface_normal);
if (divisor == 0.0f) { if (divisor == 0.0f) {
return 0.0f; return 0.0f;
} }
return light_intensity * dot_product / divisor; return dot_product / divisor;
}
f32 clamp(f32 value, f32 min, f32 max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
} }