diff options
| author | nsfisis <nsfisis@gmail.com> | 2023-03-05 17:55:51 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2023-05-07 10:09:08 +0900 |
| commit | ca914b32fabdc5bb3e2782d91cc323205d0714fd (patch) | |
| tree | 6862d744e41286d5e371c5a19946e7fa400285db | |
| parent | 9ab677e15853814079583257d11256bdcdc88cbe (diff) | |
| download | RayTracingInOneWeekend.zig-ca914b32fabdc5bb3e2782d91cc323205d0714fd.tar.gz RayTracingInOneWeekend.zig-ca914b32fabdc5bb3e2782d91cc323205d0714fd.tar.zst RayTracingInOneWeekend.zig-ca914b32fabdc5bb3e2782d91cc323205d0714fd.zip | |
6.2
| -rw-r--r-- | src/main.zig | 20 | ||||
| -rw-r--r-- | src/rtw/texture.zig | 48 |
2 files changed, 67 insertions, 1 deletions
diff --git a/src/main.zig b/src/main.zig index 00bc7e6..4a667f9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -244,6 +244,19 @@ fn generateRandomScene(rng: Random, allocator: anytype) !Hittable { return .{ .list = .{ .objects = hittable_objects } }; } +fn generateEarthScene(allocator: anytype) !Hittable { + var hittable_objects = ArrayList(Hittable).init(allocator); + + const earth_texture = try Texture.makeImage(allocator, "assets/sekaichizu.png"); + var earth_surface = try allocator.create(Material); + + earth_surface.* = .{ .diffuse = .{ .albedo = earth_texture } }; + + try hittable_objects.append(makeSphere(.{ .x = 0, .y = 0, .z = 0 }, 2, earth_surface)); + + return .{ .list = .{ .objects = hittable_objects } }; +} + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); @@ -259,7 +272,7 @@ pub fn main() !void { const samples_per_pixel = 50; const max_depth = 50; - const scene = 3; + const scene = 4; // World var world: Hittable = undefined; @@ -284,6 +297,11 @@ pub fn main() !void { lookFrom = .{ .x = 13, .y = 2, .z = 3 }; lookAt = .{ .x = 0, .y = 0, .z = 0 }; vFov = 20.0; + } else if (scene == 4) { + world = try generateEarthScene(allocator); + lookFrom = .{ .x = 13, .y = 2, .z = 3 }; + lookAt = .{ .x = 0, .y = 0, .z = 0 }; + vFov = 20.0; } defer world.deinit(allocator); diff --git a/src/rtw/texture.zig b/src/rtw/texture.zig index ae24265..95cbef4 100644 --- a/src/rtw/texture.zig +++ b/src/rtw/texture.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Image = @import("zigimg").Image; const Color = @import("vec.zig").Color; const Vec3 = @import("vec.zig").Vec3; @@ -10,12 +11,14 @@ const TextureTag = enum { solid, checker, noise, + image, }; pub const Texture = union(TextureTag) { solid: SolidTexture, checker: CheckerTexture, noise: NoiseTexture, + image: ImageTexture, pub fn makeSolid(color: Color) Texture { return .{ .solid = .{ .color = color } }; @@ -33,11 +36,16 @@ pub const Texture = union(TextureTag) { return .{ .noise = try NoiseTexture.init(allocator, rng, scale) }; } + pub fn makeImage(allocator: std.mem.Allocator, file_path: []const u8) !Texture { + return .{ .image = try ImageTexture.init(allocator, file_path) }; + } + pub fn value(tx: Texture, u: f64, v: f64, p: Vec3) Color { return switch (tx) { TextureTag.solid => |solidTx| solidTx.value(u, v, p), TextureTag.checker => |checkerTx| checkerTx.value(u, v, p), TextureTag.noise => |noiseTx| noiseTx.value(u, v, p), + TextureTag.image => |imageTx| imageTx.value(u, v, p), }; } }; @@ -102,3 +110,43 @@ pub const NoiseTexture = struct { return rgb(1, 1, 1).mul(0.5 * (1.0 + @sin(tx.scale * p.z + 10.0 * tx.perlin.turb(p, 7)))); } }; + +pub const ImageTexture = struct { + image: Image, + + fn init(allocator: std.mem.Allocator, file_path: []const u8) !ImageTexture { + const image = try Image.fromFilePath(allocator, file_path); + return .{ + .image = image, + }; + } + + fn deinit(tx: ImageTexture) void { + tx.image.deinit(); + } + + fn value(tx: ImageTexture, u: f64, v: f64, p: Vec3) Color { + _ = p; + // Clamp input texture coordinates to [0, 1] x [1, 0] + const u_ = std.math.clamp(u, 0.0, 1.0); + const v_ = 1.0 - std.math.clamp(v, 0.0, 1.0); // Flip v to image coordinates + const i = @floatToInt(usize, u_ * @intToFloat(f64, tx.image.width)); + const j = @floatToInt(usize, v_ * @intToFloat(f64, tx.image.height)); + // Clamp integer mapping, since actual coordinates should be less than 1.0 + const i_ = @min(i, tx.image.width - 1); + const j_ = @min(j, tx.image.width - 1); + const color_scale = 1.0 / 255.0; + const pixels = tx.image.pixels.asBytes(); + const offset = j_ * tx.image.width * 4 + i_ * 4; + const r = @intToFloat(f64, pixels[offset + 0]); + const g = @intToFloat(f64, pixels[offset + 1]); + const b = @intToFloat(f64, pixels[offset + 2]); + const a = @intToFloat(f64, pixels[offset + 3]); + if (a == 0) { + // Ocean + return rgb(0, 0, 1.0); + } else { + return rgb(color_scale * r, color_scale * g, color_scale * b); + } + } +}; |
