@@ 5,6 5,10 @@ export type camera = struct {
plane_origin: vector,
horizontal: vector,
vertical: vector,
+ u: vector,
+ v: vector,
+ w: vector,
+ lens_r: f64,
};
export fn make_camera(
@@ 12,7 16,9 @@ export fn make_camera(
to: vector,
vup: vector,
vfov: f64,
- ar: f64
+ ar: f64,
+ ap: f64,
+ fdist: f64,
) camera = {
let height = 2.0 * math::tanf64(vfov * math::PI / 360.0);
let width = ar * height;
@@ 20,19 26,43 @@ export fn make_camera(
let w = unit(diff(from, to)), u = unit(cross(vup, w)), v = cross(w, u);
let c = camera {
+ w = w,
+ u = u,
+ v = v,
origin = from,
- horizontal = scale(u, width),
- vertical = scale(v, height),
+ lens_r = ap / 2.0,
...
};
- c.plane_origin = neg(sum(scale(sum(c.horizontal, c.vertical), 0.5), w));
+ c.horizontal = scale(c.u, width * fdist);
+ c.vertical = scale(c.v, height * fdist);
+ c.plane_origin = neg(sum(scale(sum(c.horizontal, c.vertical), 0.5), scale(w, fdist)));
return c;
};
-export fn get_ray_for(c: *const camera, u: f64, v: f64) ray = ray {
- origin = c.origin,
- direction = sum(
- sum(scale(c.horizontal, u), scale(c.vertical, v)),
- c.plane_origin
- ),
+export fn random_in_circle() (f64, f64) = {
+ for (true) {
+ let x = random(-1.0, 1.0);
+ let y = random(-1.0, 1.0);
+ let l = x * x + y * y;
+ if (l < 1.0) {
+ let l = math::sqrtf64(l);
+ return (x / l, y / l);
+ };
+ };
+ abort();
+};
+
+export fn get_ray_for(c: *const camera, u: f64, v: f64) ray = {
+ let r = random_in_circle();
+ let offs = sum(scale(c.u, r.0 * c.lens_r), scale(c.v, r.1 * c.lens_r));
+ return ray {
+ origin = sum(c.origin, offs),
+ direction = diff(
+ sum(
+ sum(scale(c.horizontal, u), scale(c.vertical, v)),
+ c.plane_origin
+ ),
+ offs
+ ),
+ };
};
@@ 49,8 49,10 @@ export fn main() void = {
let samples = 50u32;
let max_bounce = 50u;
- let c = make_camera(V(-2.0, -2.0, 1.0), V(0.0, 0.0, -1.0), V(0.0, 1.0, 0.0),
- 20.0, 4.0/3.0);
+ let from = V(3.0, -3.0, 2.0);
+ let at = V(0.0, 0.0, -1.0);
+ let c = make_camera(from, at, V(0.0, 1.0, 0.0),
+ 20.0, 4.0/3.0, 2.0, length(diff(from, at)));
let scene = init_scene();