Add camera aperture / depth-of-field

This commit is contained in:
Camden Dixie O'Brien
2025-09-23 15:35:26 +01:00
parent f32ec378a3
commit f89a779b8f
4 changed files with 26 additions and 9 deletions

5
demo.c
View File

@@ -13,6 +13,8 @@
#define MIN_RAD 1.0 #define MIN_RAD 1.0
#define FOV 90 #define FOV 90
#define APERTURE 0.5
#define FOCAL_LEN 100.0
#define SAMPLES_PER_PIXEL 100 #define SAMPLES_PER_PIXEL 100
static const vec3_t camera_pos = { -100.0, 25.0, -100.0 }; static const vec3_t camera_pos = { -100.0, 25.0, -100.0 };
@@ -62,7 +64,8 @@ int main()
rand_obj(objs + i, &rng); rand_obj(objs + i, &rng);
img_t img = { .pix = pixbuf }; 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 = { const scene_t scene = {
.sky_colour = sky, .sky_colour = sky,

View File

@@ -8,11 +8,13 @@
typedef struct { typedef struct {
vec3_t pos; vec3_t pos;
vec3_t pix_origin, x_step, y_step; vec3_t pix_origin, x_step, y_step;
vec3_t u_hat, v_hat;
uint32_t img_width, img_height; uint32_t img_width, img_height;
double aperture;
} camera_t; } camera_t;
camera_t camera_init( camera_t camera_init(
vec3_t pos, vec3_t target, double fov, uint32_t img_width, 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 #endif

View File

@@ -10,11 +10,8 @@ static const vec3_t up = { 0.0, 1.0, 0.0 };
camera_t camera_init( camera_t camera_init(
vec3_t pos, vec3_t target, double fov, uint32_t img_width, 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 fov_rad = M_PI * fov / 180.0;
const double aspect = (double)img_width / (double)img_height; const double aspect = (double)img_width / (double)img_height;
const double viewport_height = focal_len * tan(fov_rad / 2); 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 u = vec3_scale(u_hat, viewport_width);
const vec3_t v = vec3_scale(v_hat, -viewport_height); 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 x_step = vec3_scale(u, 1.0 / (double)img_width);
const vec3_t y_step = vec3_scale(v, 1.0 / (double)img_height); 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, .pix_origin = pix_origin,
.x_step = x_step, .x_step = x_step,
.y_step = y_step, .y_step = y_step,
.u_hat = u_hat,
.v_hat = v_hat,
.img_width = img_width, .img_width = img_width,
.img_height = img_height, .img_height = img_height,
.aperture = aperture,
}; };
} }

View File

@@ -94,9 +94,19 @@ static int render_thread(void *arg)
vec3_scale(camera->y_step, jitter.y)); vec3_scale(camera->y_step, jitter.y));
const vec3_t jittered_pix = vec3_add(pix, offset); 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 = { const ray_t ray = {
.orig = camera->pos, .orig = source,
.dir = vec3_unit(vec3_sub(jittered_pix, camera->pos)), .dir = vec3_unit(vec3_sub(jittered_pix, source)),
}; };
const vec3_t sample = trace(ray, slice->scene, &slice->rng); const vec3_t sample = trace(ray, slice->scene, &slice->rng);