From f89a779b8fa822607feada2418d903e72db43a3c Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Tue, 23 Sep 2025 15:35:26 +0100 Subject: [PATCH] Add camera aperture / depth-of-field --- demo.c | 5 ++++- include/camera.h | 4 +++- src/camera.c | 12 +++++++----- src/render.c | 14 ++++++++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/demo.c b/demo.c index 922b36a..ca5a918 100644 --- a/demo.c +++ b/demo.c @@ -13,6 +13,8 @@ #define MIN_RAD 1.0 #define FOV 90 +#define APERTURE 0.5 +#define FOCAL_LEN 100.0 #define SAMPLES_PER_PIXEL 100 static const vec3_t camera_pos = { -100.0, 25.0, -100.0 }; @@ -62,7 +64,8 @@ int main() rand_obj(objs + i, &rng); img_t img = { .pix = pixbuf }; - camera_t camera = camera_init(camera_pos, target, FOV, W, H, APERTURE); + camera_t camera + = camera_init(camera_pos, target, FOV, W, H, APERTURE, FOCAL_LEN); const scene_t scene = { .sky_colour = sky, diff --git a/include/camera.h b/include/camera.h index 6c282b7..53863a8 100644 --- a/include/camera.h +++ b/include/camera.h @@ -8,11 +8,13 @@ typedef struct { vec3_t pos; vec3_t pix_origin, x_step, y_step; + vec3_t u_hat, v_hat; uint32_t img_width, img_height; + double aperture; } camera_t; camera_t camera_init( vec3_t pos, vec3_t target, double fov, uint32_t img_width, - uint32_t img_height); + uint32_t img_height, double aperture, double focal_len); #endif diff --git a/src/camera.c b/src/camera.c index 3d618dd..a09e199 100644 --- a/src/camera.c +++ b/src/camera.c @@ -10,11 +10,8 @@ static const vec3_t up = { 0.0, 1.0, 0.0 }; camera_t camera_init( vec3_t pos, vec3_t target, double fov, uint32_t img_width, - uint32_t img_height) + uint32_t img_height, double aperture, double focal_len) { - const vec3_t target_disp = vec3_sub(target, pos); - const double focal_len = vec3_len(target_disp); - const double fov_rad = M_PI * fov / 180.0; const double aspect = (double)img_width / (double)img_height; const double viewport_height = focal_len * tan(fov_rad / 2); @@ -27,7 +24,9 @@ camera_t camera_init( const vec3_t u = vec3_scale(u_hat, viewport_width); const vec3_t v = vec3_scale(v_hat, -viewport_height); - const vec3_t topleft = vec3_sub(target, vec3_scale(vec3_add(u, v), 0.5)); + const vec3_t topleft = vec3_sub( + vec3_add(pos, vec3_scale(w_hat, focal_len)), + vec3_scale(vec3_add(u, v), 0.5)); const vec3_t x_step = vec3_scale(u, 1.0 / (double)img_width); const vec3_t y_step = vec3_scale(v, 1.0 / (double)img_height); @@ -39,7 +38,10 @@ camera_t camera_init( .pix_origin = pix_origin, .x_step = x_step, .y_step = y_step, + .u_hat = u_hat, + .v_hat = v_hat, .img_width = img_width, .img_height = img_height, + .aperture = aperture, }; } diff --git a/src/render.c b/src/render.c index c48db95..3e104d2 100644 --- a/src/render.c +++ b/src/render.c @@ -94,9 +94,19 @@ static int render_thread(void *arg) vec3_scale(camera->y_step, jitter.y)); const vec3_t jittered_pix = vec3_add(pix, offset); + vec3_t source = camera->pos; + if (camera->aperture != 0.0) { + const vec3_t pos + = vec3_scale(rng_xy(&slice->rng), camera->aperture); + const vec3_t offset = vec3_add( + vec3_scale(camera->u_hat, pos.x), + vec3_scale(camera->v_hat, pos.y)); + source = vec3_add(source, offset); + } + const ray_t ray = { - .orig = camera->pos, - .dir = vec3_unit(vec3_sub(jittered_pix, camera->pos)), + .orig = source, + .dir = vec3_unit(vec3_sub(jittered_pix, source)), }; const vec3_t sample = trace(ray, slice->scene, &slice->rng);