this repo has no description

moveable camera

+52 -13
+42 -10
src/camera.zig
··· 6 6 const zm = @import("zmath"); 7 7 8 8 pub const Ray = @import("ray.zig"); 9 + const util = @import("util.zig"); 9 10 10 11 const log = std.log.scoped(.camera); 11 12 ··· 16 17 aspect_ratio: f32, 17 18 samples_per_pixel: usize, 18 19 max_depth: usize, 20 + vfov: f32 = 90, 21 + look_from: zm.Vec = zm.f32x4s(0), 22 + look_at: zm.Vec = zm.f32x4(0, 0, -1, 0), 23 + vup: zm.Vec = zm.f32x4(0, 1, 0, 0), 19 24 }; 20 25 21 26 image_height: usize, ··· 25 30 samples_per_pixel: usize, 26 31 max_depth: usize, 27 32 33 + vfov: f32, 34 + look_from: zm.Vec, 35 + look_at: zm.Vec, 36 + vup: zm.Vec, 37 + 28 38 focal_lenght: f32, 29 39 viewport_height: f32, 30 40 viewport_width: f32, 31 - camera_center: zm.Vec, 41 + center: zm.Vec, 32 42 33 43 viewport_u: zm.Vec, 34 44 viewport_v: zm.Vec, 35 45 pixel_delta_u: zm.Vec, 36 46 pixel_delta_v: zm.Vec, 47 + u: zm.Vec, 48 + v: zm.Vec, 49 + w: zm.Vec, 37 50 38 51 viewport_upper_left: zm.Vec, 39 52 pixel00_loc: zm.Vec, ··· 46 59 const image_height = @as(usize, @intFromFloat(@as(f32, @floatFromInt(image_width)) / aspect_ratio)); 47 60 if (image_height < 1) return error.ImageWidthLessThanOne; 48 61 49 - const focal_lenght: f32 = 1.0; 50 - const viewport_height: f32 = 2.0; 62 + const vfov = opts.vfov; 63 + const look_from = opts.look_from; 64 + const look_at = opts.look_at; 65 + const vup = opts.vup; 66 + const center = look_from; 67 + 68 + const focal_lenght: f32 = zm.length3(look_from - look_at)[0]; 69 + const theta = util.degreesToRadians(opts.vfov); 70 + const h = @tan(theta / 2); 71 + const viewport_height: f32 = 2 * h * focal_lenght; 51 72 const viewport_width = viewport_height * (@as(f32, @floatFromInt(image_width)) / @as(f32, @floatFromInt(image_height))); 52 - const camera_center = zm.f32x4s(0.0); 73 + 74 + const w = zm.normalize3(look_from - look_at); 75 + const u = zm.normalize3(zm.cross3(vup, w)); 76 + const v = zm.cross3(w, u); 53 77 54 78 // Calculate the vectors across the horizontal and down the vertical viewport edges. 55 - const viewport_u = zm.f32x4(viewport_width, 0, 0, 0); 56 - const viewport_v = zm.f32x4(0, -viewport_height, 0, 0); 79 + const viewport_u = zm.f32x4s(viewport_width) * u; 80 + const viewport_v = zm.f32x4s(viewport_height) * -v; 57 81 58 82 // Calculate the horizontal and vertical delta vectors from pixel to pixel. 59 83 const pixel_delta_u = viewport_u / zm.f32x4s(@as(f32, @floatFromInt(image_width))); 60 84 const pixel_delta_v = viewport_v / zm.f32x4s(@as(f32, @floatFromInt(image_height))); 61 85 62 86 // Calculate the location of the upper left pixel. 63 - const viewport_upper_left = camera_center - zm.f32x4(0, 0, focal_lenght, 0) - viewport_u / zm.f32x4s(2.0) - viewport_v / zm.f32x4s(2.0); 87 + const viewport_upper_left = center - zm.f32x4s(focal_lenght) * w - viewport_u / zm.f32x4s(2.0) - viewport_v / zm.f32x4s(2.0); 64 88 const pixel00_loc = viewport_upper_left + zm.f32x4s(0.5) * (pixel_delta_u + pixel_delta_v); 65 89 66 90 log.debug("image_width: {}, image_height: {}, aspect_ratio: {d:.2}, focal_lenght: {d:.1}", .{ image_width, image_height, aspect_ratio, focal_lenght }); ··· 73 97 .samples_per_pixel = opts.samples_per_pixel, 74 98 .max_depth = opts.max_depth, 75 99 100 + .vfov = vfov, 101 + .look_from = look_from, 102 + .look_at = look_at, 103 + .vup = vup, 104 + 76 105 .focal_lenght = focal_lenght, 77 106 .viewport_height = viewport_height, 78 107 .viewport_width = viewport_width, 79 - .camera_center = camera_center, 108 + .center = center, 80 109 81 110 .viewport_u = viewport_u, 82 111 .viewport_v = viewport_v, 83 112 .pixel_delta_u = pixel_delta_u, 84 113 .pixel_delta_v = pixel_delta_v, 114 + .u = u, 115 + .v = v, 116 + .w = w, 85 117 86 118 .viewport_upper_left = viewport_upper_left, 87 119 .pixel00_loc = pixel00_loc, ··· 98 130 const pixel_center = self.pixel00_loc + (zm.f32x4s(@as(f32, @floatFromInt(i))) * self.pixel_delta_u) + (zm.f32x4s(@as(f32, @floatFromInt(j))) * self.pixel_delta_v); 99 131 const pixel_sample = pixel_center + self.pixelSamplesSq(); 100 132 101 - const ray_direction = pixel_sample - self.camera_center; 102 - return Ray.init(self.camera_center, ray_direction); 133 + const ray_direction = pixel_sample - self.center; 134 + return Ray.init(self.center, ray_direction); 103 135 } 104 136 105 137 pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void {
+4 -1
src/main.zig
··· 35 35 36 36 var world = HittableList.init(allocator); 37 37 try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, -100.5, -1, 0), .radius = 100, .mat = &material_ground })); 38 - try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, 0, -1, 0), .radius = 0.5, .mat = &material_center })); 38 + try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(0, 0, -1.2, 0), .radius = 0.5, .mat = &material_center })); 39 39 try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(-1, 0, -1, 0), .radius = 0.5, .mat = &material_left })); 40 40 try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(-1, 0, -1, 0), .radius = 0.4, .mat = &material_bubble })); 41 41 try world.add(Hittable.sphere(Sphere{ .center = zm.f32x4(1, 0, -1, 0), .radius = 0.5, .mat = &material_right })); ··· 48 48 .image_width = 400, 49 49 .samples_per_pixel = 100, 50 50 .max_depth = 50, 51 + .vfov = 20, 52 + .look_from = zm.f32x4(-2, 2, 1, 0), 53 + .look_at = zm.f32x4(0, 0, -1, 0), 51 54 }); 52 55 defer raytracer.deinit(); 53 56
+6 -2
src/util.zig
··· 1 - const std = @import("std"); 2 - const random = std.crypto.random; 1 + const random = @import("std").crypto.random; 2 + const math = @import("std").math; 3 3 4 4 const zm = @import("zmath"); 5 + 6 + pub inline fn degreesToRadians(degrees: f32) f32 { 7 + return degrees * math.pi / 180.0; 8 + } 5 9 6 10 /// Returns a random real in [0,1). 7 11 pub inline fn randomF32() f32 {