diff --git a/hittable.c b/hittable.c index ff6d65a..1cf6b9d 100644 --- a/hittable.c +++ b/hittable.c @@ -133,6 +133,34 @@ Hittable *hittable_create_xy_rectangle(double x0, double x1, double y0, return result; } +Hittable *hittable_create_xz_rectangle(double x0, double x1, double z0, + double z1, double k, + const Material *material, Arena *arena) { + Hittable *result = arena_alloc(arena, sizeof(Hittable)); + result->type = HITTABLE_XZ_RECTANGLE; + result->xz_rectangle.x0 = x0; + result->xz_rectangle.x1 = x1; + result->xz_rectangle.z0 = z0; + result->xz_rectangle.z1 = z1; + result->xz_rectangle.k = k; + result->xz_rectangle.material = material; + return result; +} + +Hittable *hittable_create_yz_rectangle(double y0, double y1, double z0, + double z1, double k, + const Material *material, Arena *arena) { + Hittable *result = arena_alloc(arena, sizeof(Hittable)); + result->type = HITTABLE_YZ_RECTANGLE; + result->yz_rectangle.y0 = y0; + result->yz_rectangle.y1 = y1; + result->yz_rectangle.z0 = z0; + result->yz_rectangle.z1 = z1; + result->yz_rectangle.k = k; + result->yz_rectangle.material = material; + return result; +} + static bool hittable_list_hit(const HittableList *list, Ray r, double t_min, double t_max, HitRecord *record) { bool hit_anything = false; @@ -251,6 +279,56 @@ static bool xy_rectangle_hit(const XYRectangle *rectangle, Ray r, double t_min, return true; } +static bool xz_rectangle_hit(const XZRectangle *rectangle, Ray r, double t_min, + double t_max, HitRecord *record) { + double t = (rectangle->k - r.origin.y) / r.direction.y; + if (t < t_min || t > t_max) + return false; + + double x = r.origin.x + t * r.direction.x; + double z = r.origin.z + t * r.direction.z; + + if (x < rectangle->x0 || x > rectangle->x1 || z < rectangle->z0 || + z > rectangle->z1) + return false; + + record->u = (x - rectangle->x0) / (rectangle->x1 - rectangle->x0); + record->v = (z - rectangle->z0) / (rectangle->z1 - rectangle->z0); + record->t = t; + + Vec3 outward_normal = {0.0, 1.0, 0.0}; + hit_record_set_face_normal(record, r, outward_normal); + record->material = rectangle->material; + record->p = ray_at(r, t); + + return true; +} + +static bool yz_rectangle_hit(const YZRectangle *rectangle, Ray r, double t_min, + double t_max, HitRecord *record) { + double t = (rectangle->k - r.origin.x) / r.direction.x; + if (t < t_min || t > t_max) + return false; + + double y = r.origin.y + t * r.direction.y; + double z = r.origin.z + t * r.direction.z; + + if (y < rectangle->y0 || y > rectangle->y1 || z < rectangle->z0 || + z > rectangle->z1) + return false; + + record->u = (y - rectangle->y0) / (rectangle->y1 - rectangle->y0); + record->v = (z - rectangle->z0) / (rectangle->z1 - rectangle->z0); + record->t = t; + + Vec3 outward_normal = {1.0, 0.0, 0.0}; + hit_record_set_face_normal(record, r, outward_normal); + record->material = rectangle->material; + record->p = ray_at(r, t); + + return true; +} + bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max, HitRecord *record) { switch (hittable->type) { @@ -264,6 +342,10 @@ bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max, return bvh_node_hit(&hittable->bvh_node, r, t_min, t_max, record); case HITTABLE_XY_RECTANGLE: return xy_rectangle_hit(&hittable->xy_rectangle, r, t_min, t_max, record); + case HITTABLE_XZ_RECTANGLE: + return xz_rectangle_hit(&hittable->xz_rectangle, r, t_min, t_max, record); + case HITTABLE_YZ_RECTANGLE: + return yz_rectangle_hit(&hittable->yz_rectangle, r, t_min, t_max, record); } return false; } @@ -325,8 +407,8 @@ static bool bvh_node_bounding_box(const BVHNode *node, AABB *bounding_box) { return true; } -static bool xy_rectangle_bouding_box(const XYRectangle *rectangle, - AABB *bounding_box) { +static bool xy_rectangle_bounding_box(const XYRectangle *rectangle, + AABB *bounding_box) { /* Pad the bounding box to make sure it is not zero-width */ *bounding_box = (AABB){ .min = {rectangle->x0, rectangle->y0, rectangle->k - 0.0001}, @@ -335,6 +417,26 @@ static bool xy_rectangle_bouding_box(const XYRectangle *rectangle, return true; } +static bool xz_rectangle_bounding_box(const XZRectangle *rectangle, + AABB *bounding_box) { + /* Pad the bounding box to make sure it is not zero-width */ + *bounding_box = (AABB){ + .min = {rectangle->x0, rectangle->k - 0.0001, rectangle->z0}, + .max = {rectangle->x1, rectangle->k + 0.0001, rectangle->z1}, + }; + return true; +} + +static bool yz_rectangle_bounding_box(const YZRectangle *rectangle, + AABB *bounding_box) { + /* Pad the bounding box to make sure it is not zero-width */ + *bounding_box = (AABB){ + .min = {rectangle->k - 0.0001, rectangle->y0, rectangle->z0}, + .max = {rectangle->k + 0.0001, rectangle->y1, rectangle->z1}, + }; + return true; +} + bool hittable_bounding_box(const Hittable *hittable, double time_start, double time_end, AABB *bounding_box) { switch (hittable->type) { @@ -349,7 +451,11 @@ bool hittable_bounding_box(const Hittable *hittable, double time_start, case HITTABLE_BVH_NODE: return bvh_node_bounding_box(&hittable->bvh_node, bounding_box); case HITTABLE_XY_RECTANGLE: - return xy_rectangle_bouding_box(&hittable->xy_rectangle, bounding_box); + return xy_rectangle_bounding_box(&hittable->xy_rectangle, bounding_box); + case HITTABLE_XZ_RECTANGLE: + return xz_rectangle_bounding_box(&hittable->xz_rectangle, bounding_box); + case HITTABLE_YZ_RECTANGLE: + return yz_rectangle_bounding_box(&hittable->yz_rectangle, bounding_box); } return false; } diff --git a/hittable.h b/hittable.h index 0481815..644f9dd 100644 --- a/hittable.h +++ b/hittable.h @@ -28,6 +28,8 @@ typedef enum HittableType { HITTABLE_MOVING_SPHERE, HITTABLE_BVH_NODE, HITTABLE_XY_RECTANGLE, + HITTABLE_XZ_RECTANGLE, + HITTABLE_YZ_RECTANGLE, } HittableType; typedef struct Hittable Hittable; @@ -62,6 +64,16 @@ typedef struct XYRectangle { double x0, x1, y0, y1, k; } XYRectangle; +typedef struct XZRectangle { + const Material *material; + double x0, x1, z0, z1, k; +} XZRectangle; + +typedef struct YZRectangle { + const Material *material; + double y0, y1, z0, z1, k; +} YZRectangle; + struct Hittable { HittableType type; union { @@ -70,6 +82,8 @@ struct Hittable { MovingSphere moving_sphere; BVHNode bvh_node; XYRectangle xy_rectangle; + XZRectangle xz_rectangle; + YZRectangle yz_rectangle; }; }; @@ -85,6 +99,12 @@ Hittable *hittable_create_bvh_node(const Hittable **objects, size_t start, Hittable *hittable_create_xy_rectangle(double x0, double x1, double y0, double y1, double k, const Material *material, Arena *arena); +Hittable *hittable_create_xz_rectangle(double x0, double x1, double z0, + double z1, double k, + const Material *material, Arena *arena); +Hittable *hittable_create_yz_rectangle(double y0, double y1, double z0, + double z1, double k, + const Material *material, Arena *arena); bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max, HitRecord *record); diff --git a/main.c b/main.c index 882e7a8..647b3a3 100644 --- a/main.c +++ b/main.c @@ -22,9 +22,10 @@ #define SCENE_TWO_PERLIN_SPHERES 2 #define SCENE_EARTH 3 #define SCENE_SIMPLE_LIGHT 4 +#define SCENE_CORNELL_BOX 5 #ifndef SCENE_SELECT -#define SCENE_SELECT SCENE_SIMPLE_LIGHT +#define SCENE_SELECT SCENE_CORNELL_BOX #endif static Color ray_color(Ray r, Color background_color, const Hittable *world, @@ -186,6 +187,41 @@ static Hittable *simple_light(Arena *arena) { return world; } +static Hittable *cornell_box(Arena *arena) { + Hittable *world = hittable_create_hittable_list(arena); + + Material *red = + material_create_lambertian_color((Color){0.65, 0.05, 0.05}, arena); + Material *white = + material_create_lambertian_color((Color){0.73, 0.73, 0.73}, arena); + Material *green = + material_create_lambertian_color((Color){0.12, 0.45, 0.15}, arena); + Material *light = + material_create_diffuse_light_color((Color){15.0, 15.0, 15.0}, arena); + + hittable_list_add( + &world->list, + hittable_create_yz_rectangle(0, 555, 0, 555, 555, green, arena), arena); + hittable_list_add(&world->list, + hittable_create_yz_rectangle(0, 555, 0, 555, 0, red, arena), + arena); + hittable_list_add( + &world->list, + hittable_create_xz_rectangle(213, 343, 227, 332, 554, light, arena), + arena); + hittable_list_add( + &world->list, + hittable_create_xz_rectangle(0, 555, 0, 555, 0, white, arena), arena); + hittable_list_add( + &world->list, + hittable_create_xz_rectangle(0, 555, 0, 555, 555, white, arena), arena); + hittable_list_add( + &world->list, + hittable_create_xy_rectangle(0, 555, 0, 555, 555, white, arena), arena); + + return world; +} + int main(int argc, char *argv[]) { srand(time(0)); @@ -212,10 +248,9 @@ int main(int argc, char *argv[]) { /* Image parameters */ - const double aspect_ratio = 16.0 / 9.0; - const int image_width = 400; - const int image_height = (int)(image_width / aspect_ratio); - const int samples_per_pixel = 400; + double aspect_ratio = 16.0 / 9.0; + int image_width = 400; + int samples_per_pixel = 400; const int max_depth = 50; Point3 look_from = {0.0, 0.0, 1.0}; @@ -260,8 +295,20 @@ int main(int argc, char *argv[]) { look_from = (Point3){26.0, 3.0, 6.0}; look_at = (Point3){0.0, 2.0, 0.0}; vfov = 20.0; +#elif SCENE_SELECT == SCENE_CORNELL_BOX + world = cornell_box(&arena); + aspect_ratio = 1.0; + image_width = 600; + samples_per_pixel = 200; + background_color = (Color){0.0, 0.0, 0.0}; + look_from = (Point3){278.0, 278.0, -800.0}; + look_at = (Point3){278.0, 278.0, 0.0}; + vfov = 40.0; +#else +#error Unknown scene selected #endif + int image_height = (int)(image_width / aspect_ratio); Vec3 up = {0.0, 1.0, 0.0}; Camera camera;