Create initial raytraced scene

This commit is contained in:
Abdelrahman Said 2023-12-20 00:05:49 +00:00
parent 36913bf365
commit 6b0732980a

View File

@ -1,22 +1,77 @@
#include "SDL_events.h" #include "SDL_events.h"
#include "c_cpp_aliases/aliases.h" #include "c_cpp_aliases/aliases.h"
#include "vector/vec.h"
#include "window/window.h" #include "window/window.h"
#include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#define ARR_LEN(ARR) sizeof(ARR) / sizeof(ARR[0])
typedef struct {
f32 radius;
vec3f_t centre;
colour_t colour;
} sphere_t;
typedef struct {
sphere_t *spheres;
u32 count;
} scene_t;
typedef struct {
f32 t1;
f32 t2;
} solutions_t;
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);
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
colour_t bg = (colour_t){.r = 128, .g = 128, .b = 128, .a = 255}; colour_t bg = (colour_t){.r = 128, .g = 128, .b = 128, .a = 255};
vec3f_t camera = {.x = 0.0f, .y = 0.0f, .z = 0.0f};
vec3f_t viewport = {.x = 1.0f, .y = 1.0f, .z = 1.0f};
window_t window = {0}; window_t window = {0};
if (!init_window(&window, 1000, 800, "CG From Scratch")) { if (!init_window(&window, 800, 800, "CG From Scratch")) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
bool running = true; bool running = true;
SDL_Event event = {0}; SDL_Event event = {0};
sphere_t spheres[] = {
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 0.0f, .y = -1.0f, .z = 3.0f},
.colour = (colour_t){.r = 255, .g = 0, .b = 0, .a = 255},
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = -2.0f, .y = 0.0f, .z = 4.0f},
.colour = (colour_t){.r = 0, .g = 255, .b = 0, .a = 255},
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 2.0f, .y = 0.0f, .z = 4.0f},
.colour = (colour_t){.r = 0, .g = 0, .b = 255, .a = 255},
},
};
scene_t scene = {
.spheres = spheres,
.count = ARR_LEN(spheres),
};
i32 w_min = ((i32)window.half_width) * -1;
i32 w_max = (i32)window.half_width;
i32 h_min = ((i32)window.half_height) * -1;
i32 h_max = (i32)window.half_height;
while (running) { while (running) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
@ -28,6 +83,14 @@ int main(int argc, char *argv[]) {
clear_window(&window, bg); clear_window(&window, bg);
for (i32 y = h_min; y < h_max; ++y) {
for (i32 x = w_min; x < w_max; ++x) {
vec3f_t direction = window_to_viewport(&window, x, y, viewport);
colour_t colour = trace_ray(camera, direction, 1, INFINITY, &scene, bg);
set_pixel(&window, x, y, colour);
}
}
swap_buffers(&window); swap_buffers(&window);
} }
@ -35,3 +98,52 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
sphere_t sphere) {
f32 r = sphere.radius;
vec3f_t CO = vec_sub(vec3f_t, origin, sphere.centre);
f32 a = vec_dot(vec3f_t, direction, direction);
f32 b = 2.0f * vec_dot(vec3f_t, CO, direction);
f32 c = vec_dot(vec3f_t, CO, CO) - r * r;
f32 discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return (solutions_t){INFINITY, INFINITY};
}
f32 t1 = (-b + sqrtf(discriminant)) / (2 * a);
f32 t2 = (-b - sqrtf(discriminant)) / (2 * a);
return (solutions_t){t1, t2};
}
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 closest_t = INFINITY;
sphere_t *closest_sphere = NULL;
for (u32 i = 0; i < scene->count; ++i) {
solutions_t solutions =
ray_intersects_sphere(origin, direction, scene->spheres[i]);
if (solutions.t1 >= t_min && solutions.t1 <= t_max &&
solutions.t1 < closest_t) {
closest_t = solutions.t1;
closest_sphere = &(scene->spheres[i]);
}
if (solutions.t2 >= t_min && solutions.t2 <= t_max &&
solutions.t2 < closest_t) {
closest_t = solutions.t2;
closest_sphere = &(scene->spheres[i]);
}
}
if (!closest_sphere) {
return default_colour;
}
return closest_sphere->colour;
}