tangled
alpha
login
or
join now
altagos.dev
/
rayray
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
pulls
pipelines
added camera and rays
altagos.dev
2 years ago
63a4befc
d3334d20
+125
-44
4 changed files
expand all
collapse all
unified
split
.gitignore
src
camera.zig
ray.zig
rayray.zig
+2
-2
.gitignore
···
1
1
-
/zig-cache
2
2
-
/zig-out
1
1
+
**/zig-cache
2
2
+
**/zig-out
3
3
/out
+79
src/camera.zig
···
1
1
+
const std = @import("std");
2
2
+
3
3
+
const zigimg = @import("zigimg");
4
4
+
const color = zigimg.color;
5
5
+
const zm = @import("zmath");
6
6
+
7
7
+
const log = std.log.scoped(.camera);
8
8
+
9
9
+
const Camera = @This();
10
10
+
11
11
+
image_height: usize,
12
12
+
image_width: usize,
13
13
+
aspect_ratio: f32,
14
14
+
15
15
+
focal_lenght: f32,
16
16
+
viewport_height: f32,
17
17
+
viewport_width: f32,
18
18
+
camera_center: zm.Vec,
19
19
+
20
20
+
viewport_u: zm.Vec,
21
21
+
viewport_v: zm.Vec,
22
22
+
pixel_delta_u: zm.Vec,
23
23
+
pixel_delta_v: zm.Vec,
24
24
+
25
25
+
viewport_upper_left: zm.Vec,
26
26
+
pixel00_loc: zm.Vec,
27
27
+
28
28
+
image: zigimg.Image,
29
29
+
30
30
+
pub fn init(allocator: std.mem.Allocator, image_width: usize, aspect_ratio: f32) !Camera {
31
31
+
const image_height = @as(usize, @intFromFloat(@as(f32, @floatFromInt(image_width)) / aspect_ratio));
32
32
+
if (image_height < 1) return error.ImageWidthLessThanOne;
33
33
+
34
34
+
const focal_lenght: f32 = 1.0;
35
35
+
const viewport_height: f32 = 2.0;
36
36
+
const viewport_width = viewport_height * (@as(f32, @floatFromInt(image_width)) / @as(f32, @floatFromInt(image_height)));
37
37
+
const camera_center = zm.f32x4s(0.0);
38
38
+
39
39
+
// Calculate the vectors across the horizontal and down the vertical viewport edges.
40
40
+
const viewport_u = zm.f32x4(viewport_width, 0, 0, 0);
41
41
+
const viewport_v = zm.f32x4(0, -viewport_height, 0, 0);
42
42
+
43
43
+
// Calculate the horizontal and vertical delta vectors from pixel to pixel.
44
44
+
const pixel_delta_u = viewport_u / zm.f32x4s(@as(f32, @floatFromInt(image_width)));
45
45
+
const pixel_delta_v = viewport_v / zm.f32x4s(@as(f32, @floatFromInt(image_height)));
46
46
+
47
47
+
// Calculate the location of the upper left pixel.
48
48
+
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);
49
49
+
const pixel00_loc = viewport_upper_left + zm.f32x4s(0.5) * (pixel_delta_u + pixel_delta_v);
50
50
+
51
51
+
log.debug("image_width: {}, image_height: {}, aspect_ratio: {d:.2}, focal_lenght: {d:.1}", .{ image_width, image_height, aspect_ratio, focal_lenght });
52
52
+
53
53
+
return Camera{
54
54
+
.image_width = image_width,
55
55
+
.image_height = image_height,
56
56
+
.aspect_ratio = aspect_ratio,
57
57
+
58
58
+
.focal_lenght = focal_lenght,
59
59
+
.viewport_height = viewport_height,
60
60
+
.viewport_width = viewport_width,
61
61
+
.camera_center = camera_center,
62
62
+
63
63
+
.viewport_u = viewport_u,
64
64
+
.viewport_v = viewport_v,
65
65
+
.pixel_delta_u = pixel_delta_u,
66
66
+
.pixel_delta_v = pixel_delta_v,
67
67
+
68
68
+
.viewport_upper_left = viewport_upper_left,
69
69
+
.pixel00_loc = pixel00_loc,
70
70
+
71
71
+
.image = try zigimg.Image.create(allocator, image_width, image_height, zigimg.PixelFormat.rgba32),
72
72
+
};
73
73
+
}
74
74
+
75
75
+
pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void {
76
76
+
if (x >= self.image_width or y >= self.image_height) return error.OutOfBounds;
77
77
+
const i = x + self.image_width * y;
78
78
+
self.image.pixels.rgba32[i] = c;
79
79
+
}
+19
src/ray.zig
···
1
1
+
const zm = @import("zmath");
2
2
+
3
3
+
const Ray = @This();
4
4
+
5
5
+
orig: zm.Vec,
6
6
+
dir: zm.Vec,
7
7
+
8
8
+
pub fn init(origin: zm.Vec, direction: zm.Vec) Ray {
9
9
+
return Ray{
10
10
+
.orig = origin,
11
11
+
.dir = direction,
12
12
+
};
13
13
+
}
14
14
+
15
15
+
pub fn color(self: *Ray) zm.Vec {
16
16
+
const unit_direction = zm.normalize3(self.dir);
17
17
+
const a = 0.5 * (unit_direction[1] + 1.0);
18
18
+
return zm.f32x4s(1.0 - a) * zm.f32x4s(1.0) + zm.f32x4s(a) * zm.f32x4(0.5, 0.7, 1.0, 1.0);
19
19
+
}
+25
-42
src/rayray.zig
···
3
3
const spall = @import("spall");
4
4
const zigimg = @import("zigimg");
5
5
const color = zigimg.color;
6
6
+
const zm = @import("zmath");
7
7
+
8
8
+
const Camera = @import("camera.zig");
9
9
+
const Ray = @import("ray.zig");
6
10
7
11
const log = std.log.scoped(.rayray);
8
12
···
16
20
pub fn init(allocator: std.mem.Allocator) !Self {
17
21
return .{
18
22
.allocator = allocator,
19
19
-
.camera = try Camera.init(allocator, 256 * 10, 256 * 10),
23
23
+
.camera = try Camera.init(allocator, 400, 16.0 / 9.0),
20
24
};
21
25
}
22
26
···
30
34
defer s.end();
31
35
32
36
const rows: usize = try std.Thread.getCpuCount();
33
33
-
const row_height = @divTrunc(self.camera.height, rows);
37
37
+
const row_height = @divTrunc(self.camera.image_height, rows);
34
38
const num_threads = blk: {
35
35
-
if (self.camera.height % rows == 0) {
39
39
+
if (self.camera.image_height % rows == 0) {
36
40
break :blk rows;
37
41
}
38
42
break :blk rows + 1;
···
44
48
defer self.allocator.free(threads);
45
49
46
50
for (0..num_threads) |row| {
47
47
-
const t = try std.Thread.spawn(.{}, r, .{ &self.camera, row, row_height });
51
51
+
const t = try std.Thread.spawn(.{}, render_thread, .{ &self.camera, row, row_height });
48
52
threads[row] = t;
49
53
}
50
54
···
55
59
return self.camera.image;
56
60
}
57
61
58
58
-
fn r(cam: *Camera, row: usize, height: usize) void {
62
62
+
fn render_thread(cam: *Camera, row: usize, height: usize) void {
59
63
spall.init_thread();
60
64
defer spall.deinit_thread();
61
65
62
66
const s = spall.trace(@src(), "Render Thread {}", .{row});
63
67
defer s.end();
64
68
65
65
-
for (0..height) |iy| {
66
66
-
const y = iy + height * row;
67
67
-
if (y >= cam.height) break;
69
69
+
for (0..height) |ij| {
70
70
+
const j = ij + height * row;
71
71
+
if (j >= cam.image_height) break;
68
72
69
69
-
for (0..cam.width) |x| {
70
70
-
const col = blk: {
71
71
-
if (iy <= height - 5) {
72
72
-
@setRuntimeSafety(false);
73
73
-
break :blk color.Rgba32.initRgba(
74
74
-
@intCast(x),
75
75
-
@intCast(y),
76
76
-
0,
77
77
-
255,
78
78
-
);
79
79
-
}
80
80
-
break :blk color.Rgba32.initRgba(0, 0, 255, 255);
81
81
-
};
73
73
+
for (0..cam.image_width) |i| {
74
74
+
const pixel_center = cam.pixel00_loc + (zm.f32x4s(@as(f32, @floatFromInt(i))) * cam.pixel_delta_u) + (zm.f32x4s(@as(f32, @floatFromInt(j))) * cam.pixel_delta_v);
75
75
+
const ray_direction = pixel_center - cam.camera_center;
76
76
+
var ray = Ray.init(cam.camera_center, ray_direction);
77
77
+
const col = vecToRgba(ray.color());
82
78
83
83
-
cam.setPixel(x, y, col) catch break;
79
79
+
cam.setPixel(i, j, col) catch break;
84
80
}
85
81
}
86
82
}
87
83
};
88
84
89
89
-
pub const Camera = struct {
90
90
-
width: usize,
91
91
-
height: usize,
92
92
-
image: zigimg.Image,
85
85
+
fn vecToRgba(v: zm.Vec) color.Rgba32 {
86
86
+
const r: u8 = @intFromFloat(255.999 * v[0]);
87
87
+
const g: u8 = @intFromFloat(255.999 * v[1]);
88
88
+
const b: u8 = @intFromFloat(255.999 * v[2]);
89
89
+
const a: u8 = @intFromFloat(255.999 * v[3]);
93
90
94
94
-
pub fn init(allocator: std.mem.Allocator, width: usize, height: usize) !Camera {
95
95
-
const img = try zigimg.Image.create(allocator, width, height, zigimg.PixelFormat.rgba32);
96
96
-
97
97
-
return Camera{
98
98
-
.width = width,
99
99
-
.height = height,
100
100
-
.image = img,
101
101
-
};
102
102
-
}
103
103
-
104
104
-
pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void {
105
105
-
if (x >= self.width or y >= self.height) return error.OutOfBounds;
106
106
-
const i = x + self.width * y;
107
107
-
self.image.pixels.rgba32[i] = c;
108
108
-
}
109
109
-
};
91
91
+
return color.Rgba32.initRgba(r, g, b, a);
92
92
+
}