Add basic transforms
This change allows us to render a complete Cornell box.
This commit is contained in:
parent
e78b539258
commit
990b36d9eb
@ -6,3 +6,4 @@ C implementation of the [*Ray tracing in one week-end*](https://raytracing.githu
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|
|||||||
BIN
examples/cornell.png
Normal file
BIN
examples/cornell.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 681 KiB |
131
hittable.c
131
hittable.c
@ -8,6 +8,7 @@
|
|||||||
#include "vec3.h"
|
#include "vec3.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <float.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -194,6 +195,60 @@ Hittable *hittable_create_box(Point3 p0, Point3 p1, const Material *material,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hittable *hittable_create_translation(Hittable *ptr, Vec3 offset,
|
||||||
|
Arena *arena) {
|
||||||
|
Hittable *result = arena_alloc(arena, sizeof(Hittable));
|
||||||
|
result->type = HITTABLE_TRANSLATION;
|
||||||
|
result->translation.ptr = ptr;
|
||||||
|
result->translation.offset = offset;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hittable *hittable_create_y_rotation(Hittable *ptr, double angle,
|
||||||
|
Arena *arena) {
|
||||||
|
Hittable *result = arena_alloc(arena, sizeof(Hittable));
|
||||||
|
result->type = HITTABLE_Y_ROTATION;
|
||||||
|
result->y_rotation.ptr = ptr;
|
||||||
|
|
||||||
|
double radians = degrees_to_radians(angle);
|
||||||
|
double sin_theta = sin(radians);
|
||||||
|
double cos_theta = cos(radians);
|
||||||
|
result->y_rotation.sin_theta = sin_theta;
|
||||||
|
result->y_rotation.cos_theta = cos_theta;
|
||||||
|
result->y_rotation.has_box =
|
||||||
|
hittable_bounding_box(ptr, 0.0, 1.0, &result->y_rotation.bounding_box);
|
||||||
|
|
||||||
|
Point3 min = {DBL_MAX, DBL_MAX, DBL_MAX};
|
||||||
|
Point3 max = {-DBL_MAX, -DBL_MAX, -DBL_MAX};
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
for (int j = 0; j < 2; ++j) {
|
||||||
|
for (int k = 0; k < 2; ++k) {
|
||||||
|
const AABB *bbox = &result->y_rotation.bounding_box;
|
||||||
|
double x = i * bbox->max.x + (1 - i) * bbox->min.x;
|
||||||
|
double y = j * bbox->max.y + (1 - j) * bbox->min.y;
|
||||||
|
double z = k * bbox->max.z + (1 - k) * bbox->min.z;
|
||||||
|
|
||||||
|
double new_x = cos_theta * x + sin_theta * z;
|
||||||
|
double new_z = -sin_theta * x + cos_theta * z;
|
||||||
|
|
||||||
|
min.x = fmin(min.x, new_x);
|
||||||
|
max.x = fmax(max.x, new_x);
|
||||||
|
min.y = fmin(min.y, y);
|
||||||
|
max.y = fmax(max.y, y);
|
||||||
|
min.z = fmin(min.z, new_z);
|
||||||
|
max.z = fmax(max.z, new_z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result->y_rotation.bounding_box = (AABB){min, max};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===----------------------------------------------------------------------===*/
|
||||||
|
|
||||||
static bool hittable_list_hit(const HittableList *list, Ray r, double t_min,
|
static bool hittable_list_hit(const HittableList *list, Ray r, double t_min,
|
||||||
double t_max, HitRecord *record) {
|
double t_max, HitRecord *record) {
|
||||||
bool hit_anything = false;
|
bool hit_anything = false;
|
||||||
@ -367,6 +422,53 @@ static bool box_hit(const Box *box, Ray r, double t_min, double t_max,
|
|||||||
return hittable_list_hit(&box->sides, r, t_min, t_max, record);
|
return hittable_list_hit(&box->sides, r, t_min, t_max, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool translation_hit(const Translation *translation, Ray r, double t_min,
|
||||||
|
double t_max, HitRecord *record) {
|
||||||
|
Ray moved_r = {point3_add(r.origin, vec3_neg(translation->offset)),
|
||||||
|
r.direction, r.time};
|
||||||
|
if (!hittable_hit(translation->ptr, moved_r, t_min, t_max, record))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
record->p = point3_add(record->p, translation->offset);
|
||||||
|
hit_record_set_face_normal(record, moved_r, record->normal);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool y_rotation_hit(const YRotation *rotation, Ray r, double t_min,
|
||||||
|
double t_max, HitRecord *record) {
|
||||||
|
Point3 origin = {
|
||||||
|
rotation->cos_theta * r.origin.x - rotation->sin_theta * r.origin.z,
|
||||||
|
r.origin.y,
|
||||||
|
rotation->sin_theta * r.origin.x + rotation->cos_theta * r.origin.z,
|
||||||
|
};
|
||||||
|
Vec3 direction = {
|
||||||
|
rotation->cos_theta * r.direction.x - rotation->sin_theta * r.direction.z,
|
||||||
|
r.direction.y,
|
||||||
|
rotation->sin_theta * r.direction.x + rotation->cos_theta * r.direction.z,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ray rotated_r = {origin, direction};
|
||||||
|
if (!hittable_hit(rotation->ptr, rotated_r, t_min, t_max, record))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
record->p = (Point3){
|
||||||
|
rotation->cos_theta * record->p.x + rotation->sin_theta * record->p.z,
|
||||||
|
record->p.y,
|
||||||
|
-rotation->sin_theta * record->p.x + rotation->cos_theta * record->p.z,
|
||||||
|
};
|
||||||
|
|
||||||
|
Vec3 normal = {
|
||||||
|
rotation->cos_theta * record->normal.x +
|
||||||
|
rotation->sin_theta * record->normal.z,
|
||||||
|
record->normal.y,
|
||||||
|
-rotation->sin_theta * record->normal.x +
|
||||||
|
rotation->cos_theta * record->normal.z,
|
||||||
|
};
|
||||||
|
hit_record_set_face_normal(record, rotated_r, normal);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
||||||
HitRecord *record) {
|
HitRecord *record) {
|
||||||
switch (hittable->type) {
|
switch (hittable->type) {
|
||||||
@ -386,10 +488,16 @@ bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
|||||||
return yz_rectangle_hit(&hittable->yz_rectangle, r, t_min, t_max, record);
|
return yz_rectangle_hit(&hittable->yz_rectangle, r, t_min, t_max, record);
|
||||||
case HITTABLE_BOX:
|
case HITTABLE_BOX:
|
||||||
return box_hit(&hittable->box, r, t_min, t_max, record);
|
return box_hit(&hittable->box, r, t_min, t_max, record);
|
||||||
|
case HITTABLE_TRANSLATION:
|
||||||
|
return translation_hit(&hittable->translation, r, t_min, t_max, record);
|
||||||
|
case HITTABLE_Y_ROTATION:
|
||||||
|
return y_rotation_hit(&hittable->y_rotation, r, t_min, t_max, record);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===----------------------------------------------------------------------===*/
|
||||||
|
|
||||||
static bool hittable_list_bounding_box(const HittableList *list,
|
static bool hittable_list_bounding_box(const HittableList *list,
|
||||||
double time_start, double time_end,
|
double time_start, double time_end,
|
||||||
AABB *bounding_box) {
|
AABB *bounding_box) {
|
||||||
@ -482,6 +590,24 @@ static bool box_bounding_box(const Box *box, AABB *bounding_box) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool translation_bounding_box(const Translation *translation,
|
||||||
|
double time_start, double time_end,
|
||||||
|
AABB *bounding_box) {
|
||||||
|
if (!hittable_bounding_box(translation->ptr, time_start, time_end,
|
||||||
|
bounding_box))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*bounding_box = (AABB){point3_add(bounding_box->min, translation->offset),
|
||||||
|
point3_add(bounding_box->max, translation->offset)};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool y_rotation_bounding_box(const YRotation *rotation,
|
||||||
|
AABB *bounding_box) {
|
||||||
|
*bounding_box = rotation->bounding_box;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool hittable_bounding_box(const Hittable *hittable, double time_start,
|
bool hittable_bounding_box(const Hittable *hittable, double time_start,
|
||||||
double time_end, AABB *bounding_box) {
|
double time_end, AABB *bounding_box) {
|
||||||
switch (hittable->type) {
|
switch (hittable->type) {
|
||||||
@ -503,6 +629,11 @@ bool hittable_bounding_box(const Hittable *hittable, double time_start,
|
|||||||
return yz_rectangle_bounding_box(&hittable->yz_rectangle, bounding_box);
|
return yz_rectangle_bounding_box(&hittable->yz_rectangle, bounding_box);
|
||||||
case HITTABLE_BOX:
|
case HITTABLE_BOX:
|
||||||
return box_bounding_box(&hittable->box, bounding_box);
|
return box_bounding_box(&hittable->box, bounding_box);
|
||||||
|
case HITTABLE_TRANSLATION:
|
||||||
|
return translation_bounding_box(&hittable->translation, time_start,
|
||||||
|
time_end, bounding_box);
|
||||||
|
case HITTABLE_Y_ROTATION:
|
||||||
|
return y_rotation_bounding_box(&hittable->y_rotation, bounding_box);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
19
hittable.h
19
hittable.h
@ -31,6 +31,8 @@ typedef enum HittableType {
|
|||||||
HITTABLE_XZ_RECTANGLE,
|
HITTABLE_XZ_RECTANGLE,
|
||||||
HITTABLE_YZ_RECTANGLE,
|
HITTABLE_YZ_RECTANGLE,
|
||||||
HITTABLE_BOX,
|
HITTABLE_BOX,
|
||||||
|
HITTABLE_TRANSLATION,
|
||||||
|
HITTABLE_Y_ROTATION,
|
||||||
} HittableType;
|
} HittableType;
|
||||||
|
|
||||||
typedef struct Hittable Hittable;
|
typedef struct Hittable Hittable;
|
||||||
@ -81,6 +83,19 @@ typedef struct Box {
|
|||||||
Point3 max;
|
Point3 max;
|
||||||
} Box;
|
} Box;
|
||||||
|
|
||||||
|
typedef struct Translation {
|
||||||
|
const Hittable *ptr;
|
||||||
|
Vec3 offset;
|
||||||
|
} Translation;
|
||||||
|
|
||||||
|
typedef struct YRotation {
|
||||||
|
const Hittable *ptr;
|
||||||
|
double sin_theta;
|
||||||
|
double cos_theta;
|
||||||
|
bool has_box;
|
||||||
|
AABB bounding_box;
|
||||||
|
} YRotation;
|
||||||
|
|
||||||
struct Hittable {
|
struct Hittable {
|
||||||
HittableType type;
|
HittableType type;
|
||||||
union {
|
union {
|
||||||
@ -92,6 +107,8 @@ struct Hittable {
|
|||||||
XZRectangle xz_rectangle;
|
XZRectangle xz_rectangle;
|
||||||
YZRectangle yz_rectangle;
|
YZRectangle yz_rectangle;
|
||||||
Box box;
|
Box box;
|
||||||
|
Translation translation;
|
||||||
|
YRotation y_rotation;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,6 +132,8 @@ Hittable *hittable_create_yz_rectangle(double y0, double y1, double z0,
|
|||||||
const Material *material, Arena *arena);
|
const Material *material, Arena *arena);
|
||||||
Hittable *hittable_create_box(Point3 p0, Point3 p1, const Material *material,
|
Hittable *hittable_create_box(Point3 p0, Point3 p1, const Material *material,
|
||||||
Arena *arena);
|
Arena *arena);
|
||||||
|
Hittable *hittable_create_translation(Hittable *ptr, Vec3 offset, Arena *arena);
|
||||||
|
Hittable *hittable_create_y_rotation(Hittable *ptr, double angle, Arena *arena);
|
||||||
|
|
||||||
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
||||||
HitRecord *record);
|
HitRecord *record);
|
||||||
|
|||||||
21
main.c
21
main.c
@ -219,14 +219,17 @@ static Hittable *cornell_box(Arena *arena) {
|
|||||||
&world->list,
|
&world->list,
|
||||||
hittable_create_xy_rectangle(0, 555, 0, 555, 555, white, arena), arena);
|
hittable_create_xy_rectangle(0, 555, 0, 555, 555, white, arena), arena);
|
||||||
|
|
||||||
hittable_list_add(&world->list,
|
Hittable *box1 = hittable_create_box((Point3){0, 0, 0},
|
||||||
hittable_create_box((Point3){130, 0, 65},
|
(Point3){165, 330, 165}, white, arena);
|
||||||
(Point3){295, 165, 230}, white, arena),
|
box1 = hittable_create_y_rotation(box1, 15, arena);
|
||||||
arena);
|
box1 = hittable_create_translation(box1, (Vec3){265, 0, 295}, arena);
|
||||||
hittable_list_add(&world->list,
|
hittable_list_add(&world->list, box1, arena);
|
||||||
hittable_create_box((Point3){265, 0, 295},
|
|
||||||
(Point3){430, 330, 460}, white, arena),
|
Hittable *box2 = hittable_create_box((Point3){0, 0, 0},
|
||||||
arena);
|
(Point3){165, 165, 165}, white, arena);
|
||||||
|
box2 = hittable_create_y_rotation(box2, -18, arena);
|
||||||
|
box2 = hittable_create_translation(box2, (Vec3){130, 0, 65}, arena);
|
||||||
|
hittable_list_add(&world->list, box2, arena);
|
||||||
|
|
||||||
Hittable *bvh_root = hittable_create_bvh_node(
|
Hittable *bvh_root = hittable_create_bvh_node(
|
||||||
world->list.objects, 0, world->list.size, 0.0, 1.0, arena);
|
world->list.objects, 0, world->list.size, 0.0, 1.0, arena);
|
||||||
@ -310,7 +313,7 @@ int main(int argc, char *argv[]) {
|
|||||||
world = cornell_box(&arena);
|
world = cornell_box(&arena);
|
||||||
aspect_ratio = 1.0;
|
aspect_ratio = 1.0;
|
||||||
image_width = 600;
|
image_width = 600;
|
||||||
samples_per_pixel = 200;
|
samples_per_pixel = 1000;
|
||||||
background_color = (Color){0.0, 0.0, 0.0};
|
background_color = (Color){0.0, 0.0, 0.0};
|
||||||
look_from = (Point3){278.0, 278.0, -800.0};
|
look_from = (Point3){278.0, 278.0, -800.0};
|
||||||
look_at = (Point3){278.0, 278.0, 0.0};
|
look_at = (Point3){278.0, 278.0, 0.0};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user