this repo has no description
at 232ee55093cceaa6d53d8fd08f9ee489f6bcec79 115 lines 3.9 kB view raw
1const std = @import("std"); 2const random = std.crypto.random; 3 4const zigimg = @import("zigimg"); 5const color = zigimg.color; 6const zm = @import("zmath"); 7 8pub const Ray = @import("ray.zig"); 9 10const log = std.log.scoped(.camera); 11 12const Camera = @This(); 13 14pub const Options = struct { 15 image_width: usize, 16 aspect_ratio: f32, 17 samples_per_pixel: usize, 18 max_depth: usize, 19}; 20 21image_height: usize, 22image_width: usize, 23aspect_ratio: f32, 24 25samples_per_pixel: usize, 26max_depth: usize, 27 28focal_lenght: f32, 29viewport_height: f32, 30viewport_width: f32, 31camera_center: zm.Vec, 32 33viewport_u: zm.Vec, 34viewport_v: zm.Vec, 35pixel_delta_u: zm.Vec, 36pixel_delta_v: zm.Vec, 37 38viewport_upper_left: zm.Vec, 39pixel00_loc: zm.Vec, 40 41image: zigimg.Image, 42 43pub fn init(allocator: std.mem.Allocator, opts: Options) !Camera { 44 const image_width = opts.image_width; 45 const aspect_ratio = opts.aspect_ratio; 46 const image_height = @as(usize, @intFromFloat(@as(f32, @floatFromInt(image_width)) / aspect_ratio)); 47 if (image_height < 1) return error.ImageWidthLessThanOne; 48 49 const focal_lenght: f32 = 1.0; 50 const viewport_height: f32 = 2.0; 51 const viewport_width = viewport_height * (@as(f32, @floatFromInt(image_width)) / @as(f32, @floatFromInt(image_height))); 52 const camera_center = zm.f32x4s(0.0); 53 54 // 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); 57 58 // Calculate the horizontal and vertical delta vectors from pixel to pixel. 59 const pixel_delta_u = viewport_u / zm.f32x4s(@as(f32, @floatFromInt(image_width))); 60 const pixel_delta_v = viewport_v / zm.f32x4s(@as(f32, @floatFromInt(image_height))); 61 62 // 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); 64 const pixel00_loc = viewport_upper_left + zm.f32x4s(0.5) * (pixel_delta_u + pixel_delta_v); 65 66 log.debug("image_width: {}, image_height: {}, aspect_ratio: {d:.2}, focal_lenght: {d:.1}", .{ image_width, image_height, aspect_ratio, focal_lenght }); 67 68 return Camera{ 69 .image_width = image_width, 70 .image_height = image_height, 71 .aspect_ratio = aspect_ratio, 72 73 .samples_per_pixel = opts.samples_per_pixel, 74 .max_depth = opts.max_depth, 75 76 .focal_lenght = focal_lenght, 77 .viewport_height = viewport_height, 78 .viewport_width = viewport_width, 79 .camera_center = camera_center, 80 81 .viewport_u = viewport_u, 82 .viewport_v = viewport_v, 83 .pixel_delta_u = pixel_delta_u, 84 .pixel_delta_v = pixel_delta_v, 85 86 .viewport_upper_left = viewport_upper_left, 87 .pixel00_loc = pixel00_loc, 88 89 .image = try zigimg.Image.create(allocator, image_width, image_height, zigimg.PixelFormat.rgba32), 90 }; 91} 92 93pub fn deinit(self: *Camera) void { 94 self.image.deinit(); 95} 96 97pub fn getRay(self: *Camera, i: usize, j: usize) Ray { 98 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 const pixel_sample = pixel_center + self.pixelSamplesSq(); 100 101 const ray_direction = pixel_sample - self.camera_center; 102 return Ray.init(self.camera_center, ray_direction); 103} 104 105pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void { 106 if (x >= self.image_width or y >= self.image_height) return error.OutOfBounds; 107 const i = x + self.image_width * y; 108 self.image.pixels.rgba32[i] = c; 109} 110 111fn pixelSamplesSq(self: *Camera) zm.Vec { 112 const px = zm.f32x4s(-0.5 + random.float(f32)); 113 const py = zm.f32x4s(-0.5 + random.float(f32)); 114 return (px * self.pixel_delta_u) + (py * self.pixel_delta_v); 115}