Add moving spheres
This commit is contained in:
parent
2abc2ba697
commit
1034668c66
2
build.sh
2
build.sh
@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
CC=${CC:-"gcc"}
|
CC=${CC:-"gcc"}
|
||||||
CFLAGS=${CFLAGS:-"-Wall -Wextra -std=gnu18 -fno-strict-aliasing -g"}
|
CFLAGS=${CFLAGS:-"-Wall -Wextra -std=gnu18 -fno-strict-aliasing -O3"}
|
||||||
LDFLAGS=${LDFLAGS:-"-lm"}
|
LDFLAGS=${LDFLAGS:-"-lm"}
|
||||||
MAIN_FILE=${MAIN_FILE:-"main.c"}
|
MAIN_FILE=${MAIN_FILE:-"main.c"}
|
||||||
|
|
||||||
|
|||||||
11
camera.c
11
camera.c
@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
void camera_init(Camera *camera, Point3 look_from, Point3 look_at, Vec3 up,
|
void camera_init(Camera *camera, Point3 look_from, Point3 look_at, Vec3 up,
|
||||||
double vertical_fov, double aspect_ratio, double aperture,
|
double vertical_fov, double aspect_ratio, double aperture,
|
||||||
double focus_distance) {
|
double focus_distance, double shutter_open,
|
||||||
|
double shutter_close) {
|
||||||
double theta = degrees_to_radians(vertical_fov);
|
double theta = degrees_to_radians(vertical_fov);
|
||||||
double h = tan(theta / 2.0);
|
double h = tan(theta / 2.0);
|
||||||
double viewport_height = 2.0 * h;
|
double viewport_height = 2.0 * h;
|
||||||
@ -26,6 +27,8 @@ void camera_init(Camera *camera, Point3 look_from, Point3 look_at, Vec3 up,
|
|||||||
camera->lower_left_corner = point3_add(camera->origin, vec3_neg(offset));
|
camera->lower_left_corner = point3_add(camera->origin, vec3_neg(offset));
|
||||||
|
|
||||||
camera->lens_radius = aperture / 2.0;
|
camera->lens_radius = aperture / 2.0;
|
||||||
|
camera->shutter_open = shutter_open;
|
||||||
|
camera->shutter_close = shutter_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ray camera_get_ray(const Camera *camera, double s, double t) {
|
Ray camera_get_ray(const Camera *camera, double s, double t) {
|
||||||
@ -37,7 +40,9 @@ Ray camera_get_ray(const Camera *camera, double s, double t) {
|
|||||||
vec3_add(vec3_mul(s, camera->horizontal), vec3_mul(t, camera->vertical)));
|
vec3_add(vec3_mul(s, camera->horizontal), vec3_mul(t, camera->vertical)));
|
||||||
Vec3 direction = point3_sub(screen_point, camera->origin);
|
Vec3 direction = point3_sub(screen_point, camera->origin);
|
||||||
return (Ray){
|
return (Ray){
|
||||||
point3_add(camera->origin, offset),
|
.origin = point3_add(camera->origin, offset),
|
||||||
vec3_sub(direction, offset),
|
.direction = vec3_sub(direction, offset),
|
||||||
|
.time =
|
||||||
|
random_double_in_range(camera->shutter_open, camera->shutter_close),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
7
camera.h
7
camera.h
@ -8,15 +8,16 @@
|
|||||||
typedef struct Camera {
|
typedef struct Camera {
|
||||||
Point3 origin;
|
Point3 origin;
|
||||||
Point3 lower_left_corner;
|
Point3 lower_left_corner;
|
||||||
Vec3 horizontal;
|
Vec3 horizontal, vertical;
|
||||||
Vec3 vertical;
|
|
||||||
Vec3 u, v, w;
|
Vec3 u, v, w;
|
||||||
double lens_radius;
|
double lens_radius;
|
||||||
|
double shutter_open, shutter_close;
|
||||||
} Camera;
|
} Camera;
|
||||||
|
|
||||||
void camera_init(Camera *camera, Point3 look_from, Point3 look_at, Vec3 up,
|
void camera_init(Camera *camera, Point3 look_from, Point3 look_at, Vec3 up,
|
||||||
double vertical_fov, double aspect_ratio, double aperture,
|
double vertical_fov, double aspect_ratio, double aperture,
|
||||||
double focus_distance);
|
double focus_distance, double shutter_open,
|
||||||
|
double shutter_close);
|
||||||
|
|
||||||
Ray camera_get_ray(const Camera *camera, double s, double t);
|
Ray camera_get_ray(const Camera *camera, double s, double t);
|
||||||
|
|
||||||
|
|||||||
53
hittable.c
53
hittable.c
@ -3,6 +3,7 @@
|
|||||||
#include "point3.h"
|
#include "point3.h"
|
||||||
#include "vec3.h"
|
#include "vec3.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -21,6 +22,9 @@ bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
|||||||
record);
|
record);
|
||||||
case HITTABLE_SPHERE:
|
case HITTABLE_SPHERE:
|
||||||
return sphere_hit((const Sphere *)hittable, r, t_min, t_max, record);
|
return sphere_hit((const Sphere *)hittable, r, t_min, t_max, record);
|
||||||
|
case HITTABLE_MOVING_SPHERE:
|
||||||
|
return moving_sphere_hit((const MovingSphere *)hittable, r, t_min, t_max,
|
||||||
|
record);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -97,3 +101,52 @@ bool sphere_hit(const Sphere *sphere, Ray r, double t_min, double t_max,
|
|||||||
record->material = sphere->material;
|
record->material = sphere->material;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MovingSphere *moving_sphere_create(Point3 center_start, Point3 center_end,
|
||||||
|
double start, double end, double radius,
|
||||||
|
const Material *material, Arena *arena) {
|
||||||
|
assert(start <= end);
|
||||||
|
MovingSphere *sphere = arena_alloc(arena, sizeof(MovingSphere));
|
||||||
|
sphere->type = HITTABLE_MOVING_SPHERE;
|
||||||
|
sphere->center_start = center_start;
|
||||||
|
sphere->center_end = center_end;
|
||||||
|
sphere->start = start;
|
||||||
|
sphere->end = end;
|
||||||
|
sphere->radius = radius;
|
||||||
|
sphere->material = material;
|
||||||
|
return sphere;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3 moving_sphere_center(const MovingSphere *sphere, double t) {
|
||||||
|
Vec3 dir = point3_sub(sphere->center_end, sphere->center_start);
|
||||||
|
double c = (t - sphere->start) / (sphere->end - sphere->start);
|
||||||
|
return point3_add(sphere->center_start, vec3_mul(c, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool moving_sphere_hit(const MovingSphere *sphere, Ray r, double t_min,
|
||||||
|
double t_max, HitRecord *record) {
|
||||||
|
Vec3 oc = point3_sub(r.origin, moving_sphere_center(sphere, r.time));
|
||||||
|
double a = vec3_length2(r.direction);
|
||||||
|
double half_b = vec3_dot(oc, r.direction);
|
||||||
|
double c = vec3_length2(oc) - sphere->radius * sphere->radius;
|
||||||
|
double discriminant = half_b * half_b - a * c;
|
||||||
|
if (discriminant < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double square_root = sqrt(discriminant);
|
||||||
|
double root = (-half_b - square_root) / a;
|
||||||
|
if (root < t_min || t_max < root) {
|
||||||
|
root = (-half_b + square_root) / a;
|
||||||
|
if (root < t_min || t_max < root)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
record->t = root;
|
||||||
|
record->p = ray_at(r, root);
|
||||||
|
Vec3 outward_normal =
|
||||||
|
vec3_div(point3_sub(record->p, moving_sphere_center(sphere, r.time)),
|
||||||
|
sphere->radius);
|
||||||
|
hit_record_set_face_normal(record, r, outward_normal);
|
||||||
|
record->material = sphere->material;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
16
hittable.h
16
hittable.h
@ -23,6 +23,7 @@ void hit_record_set_face_normal(HitRecord *record, Ray r, Vec3 outward_normal);
|
|||||||
typedef enum HittableType {
|
typedef enum HittableType {
|
||||||
HITTABLE_LIST,
|
HITTABLE_LIST,
|
||||||
HITTABLE_SPHERE,
|
HITTABLE_SPHERE,
|
||||||
|
HITTABLE_MOVING_SPHERE,
|
||||||
} HittableType;
|
} HittableType;
|
||||||
|
|
||||||
typedef struct Hittable {
|
typedef struct Hittable {
|
||||||
@ -56,4 +57,19 @@ Sphere *sphere_create(Point3 center, double radius, const Material *material,
|
|||||||
bool sphere_hit(const Sphere *sphere, Ray r, double t_min, double t_max,
|
bool sphere_hit(const Sphere *sphere, Ray r, double t_min, double t_max,
|
||||||
HitRecord *record);
|
HitRecord *record);
|
||||||
|
|
||||||
|
typedef struct MovingSphere {
|
||||||
|
HittableType type;
|
||||||
|
const Material *material;
|
||||||
|
Point3 center_start, center_end;
|
||||||
|
double start, end;
|
||||||
|
double radius;
|
||||||
|
} MovingSphere;
|
||||||
|
|
||||||
|
MovingSphere *moving_sphere_create(Point3 center_start, Point3 center_end,
|
||||||
|
double start, double end, double radius,
|
||||||
|
const Material *material, Arena *arena);
|
||||||
|
Point3 moving_sphere_center(const MovingSphere *sphere, double t);
|
||||||
|
bool moving_sphere_hit(const MovingSphere *sphere, Ray r, double t_min,
|
||||||
|
double t_max, HitRecord *record);
|
||||||
|
|
||||||
#endif /* INCLUDED_HITTABLE_H */
|
#endif /* INCLUDED_HITTABLE_H */
|
||||||
|
|||||||
15
main.c
15
main.c
@ -56,8 +56,11 @@ static const Hittable *generate_random_scene(Arena *arena) {
|
|||||||
if (choose_material < 0.8) {
|
if (choose_material < 0.8) {
|
||||||
const Lambertian *material = lambertian_create(
|
const Lambertian *material = lambertian_create(
|
||||||
color_mul(color_random(), color_random()), arena);
|
color_mul(color_random(), color_random()), arena);
|
||||||
const Sphere *sphere =
|
Point3 center2 = point3_add(
|
||||||
sphere_create(center, 0.2, (const Material *)material, arena);
|
center, (Vec3){0, random_double_in_range(0.0, 0.5), 0});
|
||||||
|
const MovingSphere *sphere =
|
||||||
|
moving_sphere_create(center, center2, 0.0, 1.0, 0.2,
|
||||||
|
(const Material *)material, arena);
|
||||||
hittable_list_add(&world, (const Hittable *)sphere, arena);
|
hittable_list_add(&world, (const Hittable *)sphere, arena);
|
||||||
} else if (choose_material < 0.95) {
|
} else if (choose_material < 0.95) {
|
||||||
const Metal *material =
|
const Metal *material =
|
||||||
@ -104,10 +107,10 @@ int main(void) {
|
|||||||
|
|
||||||
/* Image parameters */
|
/* Image parameters */
|
||||||
|
|
||||||
const double aspect_ratio = 3.0 / 2.0;
|
const double aspect_ratio = 16.0 / 9.0;
|
||||||
const int image_width = 1200;
|
const int image_width = 400;
|
||||||
const int image_height = (int)(image_width / aspect_ratio);
|
const int image_height = (int)(image_width / aspect_ratio);
|
||||||
const int samples_per_pixel = 2;
|
const int samples_per_pixel = 100;
|
||||||
const int max_depth = 50;
|
const int max_depth = 50;
|
||||||
|
|
||||||
/* World */
|
/* World */
|
||||||
@ -124,7 +127,7 @@ int main(void) {
|
|||||||
|
|
||||||
Camera camera;
|
Camera camera;
|
||||||
camera_init(&camera, look_from, look_at, up, 20, aspect_ratio, aperture,
|
camera_init(&camera, look_from, look_at, up, 20, aspect_ratio, aperture,
|
||||||
dist_to_focus);
|
dist_to_focus, 0.0, 1.0);
|
||||||
|
|
||||||
printf("P3\n%u %u\n255\n", image_width, image_height);
|
printf("P3\n%u %u\n255\n", image_width, image_height);
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ bool lambertian_scatter(const Lambertian *lambertian, Ray r,
|
|||||||
if (vec3_is_near_zero(scatter_direction))
|
if (vec3_is_near_zero(scatter_direction))
|
||||||
scatter_direction = record->normal;
|
scatter_direction = record->normal;
|
||||||
|
|
||||||
*scattered = (Ray){record->p, scatter_direction};
|
*scattered = (Ray){record->p, scatter_direction, r.time};
|
||||||
*attenuation = lambertian->albedo;
|
*attenuation = lambertian->albedo;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -62,6 +62,7 @@ bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record,
|
|||||||
record->p,
|
record->p,
|
||||||
vec3_add(reflected,
|
vec3_add(reflected,
|
||||||
vec3_mul(metal->fuzziness, vec3_random_in_unit_sphere())),
|
vec3_mul(metal->fuzziness, vec3_random_in_unit_sphere())),
|
||||||
|
r.time,
|
||||||
};
|
};
|
||||||
*attenuation = metal->albedo;
|
*attenuation = metal->albedo;
|
||||||
return vec3_dot(scattered->direction, record->normal) > 0;
|
return vec3_dot(scattered->direction, record->normal) > 0;
|
||||||
@ -101,6 +102,6 @@ bool dielectric_scatter(const Dielectric *dielectric, Ray r,
|
|||||||
else
|
else
|
||||||
direction = vec3_refract(unit_direction, record->normal, refraction_ratio);
|
direction = vec3_refract(unit_direction, record->normal, refraction_ratio);
|
||||||
|
|
||||||
*scattered = (Ray){record->p, direction};
|
*scattered = (Ray){record->p, direction, r.time};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user