diff --git a/.gitignore b/.gitignore index 2e774a5..9e5608d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ build/ -*.ppm +output.ppm .clangd/ .cache/ diff --git a/README.md b/README.md index 6c1673f..4156d8a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # Ray tracing in one week-end C implementation of the [*Ray tracing in one week-end*](https://raytracing.github.io/) series by Peter Shirley. + +## Examples + +![Ray tracing in one week-end book cover](examples/book-cover.png) diff --git a/color.c b/color.c index 78347b5..09e195d 100644 --- a/color.c +++ b/color.c @@ -12,6 +12,18 @@ Color color_mul(Color c1, Color c2) { return (Color){c1.r * c2.r, c1.g * c2.g, c1.b * c2.b}; } +Color color_random(void) { + return (Color){random_double_in_range(0.0, 1.0), + random_double_in_range(0.0, 1.0), + random_double_in_range(0.0, 1.0)}; +} + +Color color_random_in_range(double min, double max) { + return (Color){random_double_in_range(min, max), + random_double_in_range(min, max), + random_double_in_range(min, max)}; +} + Color color_lerp(Color c1, Color c2, double t) { return (Color){ (1.0 - t) * c1.r + t * c2.r, diff --git a/color.h b/color.h index 010c855..ad5ca59 100644 --- a/color.h +++ b/color.h @@ -10,6 +10,9 @@ typedef struct Color { Color color_add(Color c1, Color c2); Color color_mul(Color c1, Color c2); +Color color_random(void); +Color color_random_in_range(double min, double max); + Color color_lerp(Color c1, Color c2, double t); void color_write(FILE *out, Color c, int samples_per_pixel); diff --git a/examples/book-cover.png b/examples/book-cover.png new file mode 100644 index 0000000..361e375 Binary files /dev/null and b/examples/book-cover.png differ diff --git a/main.c b/main.c index 4abda6b..289f96e 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "camera.h" #include "color.h" @@ -12,7 +13,7 @@ #include "utils.h" #include "vec3.h" -Color ray_color(Ray r, const Hittable *world, int depth) { +static Color ray_color(Ray r, const Hittable *world, int depth) { if (depth <= 0) return (Color){0, 0, 0}; @@ -32,70 +33,112 @@ Color ray_color(Ray r, const Hittable *world, int depth) { return color_lerp(gradient1, gradient2, t); } +static const Hittable *generate_random_scene(void) { + static HittableList world = {.type = HITTABLE_LIST}; + + /* FIXME: Use arena allocators to be able to free memory */ + + static Lambertian ground_material = {.type = MATERIAL_LAMBERTIAN, + .albedo = (Color){0.5, 0.5, 0.5}}; + Sphere *ground_sphere = malloc(sizeof(Sphere)); + ground_sphere->type = HITTABLE_SPHERE; + ground_sphere->center = (Point3){0.0, -1000.0, 0.0}; + ground_sphere->radius = 1000.0; + ground_sphere->material = (const Material *)&ground_material; + hittable_list_add(&world, (const Hittable *)ground_sphere); + + static Lambertian lambertian = {.type = MATERIAL_LAMBERTIAN, + .albedo = {0.4, 0.2, 0.1}}; + static Metal metal = { + .type = MATERIAL_METAL, .albedo = {0.7, 0.6, 0.5}, .fuzziness = 0.0}; + static Dielectric glass = {.type = MATERIAL_DIELECTRIC, .eta = 1.5}; + + for (int a = -11; a < 11; ++a) { + for (int b = -11; b < 11; ++b) { + double choose_material = random_double(); + Point3 center = {a + 0.9 * random_double(), 0.2, + b + 0.9 * random_double()}; + + if (vec3_length(point3_sub(center, (Point3){4.0, 0.2, 0.0})) > 0.9) { + if (choose_material < 0.8) { + Color albedo = color_mul(color_random(), color_random()); + Lambertian *material = malloc(sizeof(Lambertian)); + material->type = MATERIAL_LAMBERTIAN; + material->albedo = albedo; + + Sphere *sphere = malloc(sizeof(Sphere)); + sphere->type = HITTABLE_SPHERE; + sphere->center = center; + sphere->radius = 0.2; + sphere->material = (const Material *)material; + hittable_list_add(&world, (const Hittable *)sphere); + } else if (choose_material < 0.95) { + Color albedo = color_random_in_range(0.5, 1); + double fuzziness = random_double_in_range(0.5, 1.0); + Metal *material = malloc(sizeof(Metal)); + material->type = MATERIAL_METAL; + material->albedo = albedo; + material->fuzziness = fuzziness; + + Sphere *sphere = malloc(sizeof(Sphere)); + sphere->type = HITTABLE_SPHERE; + sphere->center = center; + sphere->radius = 0.2; + sphere->material = (const Material *)material; + hittable_list_add(&world, (const Hittable *)sphere); + } else { + Sphere *sphere = malloc(sizeof(Sphere)); + sphere->type = HITTABLE_SPHERE; + sphere->center = center; + sphere->radius = 0.2; + sphere->material = (const Material *)&glass; + hittable_list_add(&world, (const Hittable *)sphere); + } + } + } + } + + Sphere *sphere1 = malloc(sizeof(Sphere)); + sphere1->type = HITTABLE_SPHERE; + sphere1->center = (Point3){0.0, 1.0, 0.0}; + sphere1->radius = 1.0; + sphere1->material = (const Material *)&glass; + hittable_list_add(&world, (const Hittable *)sphere1); + Sphere *sphere2 = malloc(sizeof(Sphere)); + sphere2->type = HITTABLE_SPHERE; + sphere2->center = (Point3){-4.0, 1.0, 0.0}; + sphere2->radius = 1.0; + sphere2->material = (const Material *)&lambertian; + hittable_list_add(&world, (const Hittable *)sphere2); + Sphere *sphere3 = malloc(sizeof(Sphere)); + sphere3->type = HITTABLE_SPHERE; + sphere3->center = (Point3){4.0, 1.0, 0.0}; + sphere3->radius = 1.0; + sphere3->material = (const Material *)&metal; + hittable_list_add(&world, (const Hittable *)sphere3); + + return (const Hittable *)&world; +} + int main(void) { /* Image parameters */ - const double aspect_ratio = 16.0 / 9.0; - const int image_width = 256; + const double aspect_ratio = 3.0 / 2.0; + const int image_width = 1200; const int image_height = (int)(image_width / aspect_ratio); - const int samples_per_pixel = 100; + const int samples_per_pixel = 500; const int max_depth = 50; /* World */ - HittableList world = {.type = HITTABLE_LIST}; - - Lambertian material_ground = {.type = MATERIAL_LAMBERTIAN, - .albedo = (Color){0.8, 0.8, 0.0}}; - Lambertian material_center = {.type = MATERIAL_LAMBERTIAN, - .albedo = (Color){0.1, 0.2, 0.5}}; - Dielectric material_left = {.type = MATERIAL_DIELECTRIC, .eta = 1.5}; - Metal material_right = {.type = MATERIAL_METAL, - .albedo = (Color){0.8, 0.6, 0.2}, - .fuzziness = 0.0}; - - Sphere sphere_ground = { - .type = HITTABLE_SPHERE, - .center = (Point3){0.0, -100.5, -1}, - .radius = 100.0, - .material = (const Material *)&material_ground, - }; - Sphere sphere_center = { - .type = HITTABLE_SPHERE, - .center = (Point3){0.0, 0.0, -1.0}, - .radius = 0.5, - .material = (const Material *)&material_center, - }; - Sphere sphere_left = { - .type = HITTABLE_SPHERE, - .center = (Point3){-1.0, 0.0, -1.0}, - .radius = 0.5, - .material = (const Material *)&material_left, - }; - Sphere sphere_inside_left = { - .type = HITTABLE_SPHERE, - .center = (Point3){-1.0, 0.0, -1.0}, - .radius = -0.45, - .material = (const Material *)&material_left, - }; - Sphere sphere_right = { - .type = HITTABLE_SPHERE, - .center = (Point3){1.0, 0.0, -1.0}, - .radius = 0.5, - .material = (const Material *)&material_right, - }; - hittable_list_add(&world, (const Hittable *)&sphere_ground); - hittable_list_add(&world, (const Hittable *)&sphere_center); - hittable_list_add(&world, (const Hittable *)&sphere_left); - hittable_list_add(&world, (const Hittable *)&sphere_inside_left); - hittable_list_add(&world, (const Hittable *)&sphere_right); + const Hittable *world = generate_random_scene(); /* Camera */ - Point3 look_from = {3.0, 3.0, 2.0}; - Point3 look_at = {0.0, 0.0, -1.0}; + Point3 look_from = {13.0, 2.0, 3.0}; + Point3 look_at = {0.0, 0.0, 0.0}; Vec3 up = {0.0, 1.0, 0.0}; - double dist_to_focus = vec3_length(point3_sub(look_from, look_at)); - double aperture = 2.0; + double dist_to_focus = 10.0; + double aperture = 0.1; Camera camera; camera_init(&camera, look_from, look_at, up, 20, aspect_ratio, aperture, @@ -111,8 +154,7 @@ int main(void) { double u = (i + random_double()) / (image_width - 1); double v = (j + random_double()) / (image_height - 1); Ray r = camera_get_ray(&camera, u, v); - pixel_color = color_add( - pixel_color, ray_color(r, (const Hittable *)&world, max_depth)); + pixel_color = color_add(pixel_color, ray_color(r, world, max_depth)); } color_write(stdout, pixel_color, samples_per_pixel); } @@ -120,8 +162,6 @@ int main(void) { fprintf(stderr, "\nDone.\n"); - hittable_list_free(&world); - return 0; }