-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1f5ca8c
commit c21982d
Showing
12 changed files
with
806 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const std = @import("std"); | ||
const sycl_badge = @import("sycl_badge"); | ||
|
||
pub const author_name = "Nathan Bourgeois"; | ||
pub const author_handle = "iridescentrose"; | ||
pub const cart_title = "Raytracer"; | ||
pub const description = "Raytracing in One Weekend raytracer on badge!"; | ||
|
||
pub fn build(b: *std.Build) void { | ||
const optimize = b.standardOptimizeOption(.{}); | ||
const sycl_badge_dep = b.dependency("sycl_badge", .{}); | ||
|
||
const cart = sycl_badge.add_cart(sycl_badge_dep, b, .{ | ||
.name = "raytracer", | ||
.optimize = optimize, | ||
.root_source_file = b.path("src/main.zig"), | ||
}); | ||
cart.install(b); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
.{ | ||
.name = "raytracer", | ||
.version = "0.0.0", | ||
.dependencies = .{ | ||
.sycl_badge = .{ .path = "../../.." }, | ||
}, | ||
.paths = .{ | ||
"build.zig", | ||
"build.zig.zon", | ||
"src", | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
const Camera = @This(); | ||
const vec = @import("vec.zig"); | ||
const Point3 = vec.Point3; | ||
const Vec3 = vec.Vec3; | ||
const Color3 = vec.Color3; | ||
const std = @import("std"); | ||
const Ray = @import("ray.zig"); | ||
const hit = @import("hit.zig"); | ||
const HittableList = hit.HittableList; | ||
const HitRecord = hit.HitRecord; | ||
const Interval = @import("interval.zig"); | ||
const cart = @import("cart-api"); | ||
|
||
const aspect_ratio = 5.0 / 4.0; | ||
const image_width: usize = 160; | ||
const image_height: usize = @intFromFloat(@as(f32, @floatFromInt(image_width)) / aspect_ratio); | ||
|
||
const theta: f32 = vfov / 180.0 * std.math.pi; | ||
const h: f32 = std.math.tan(theta / 2.0); | ||
const viewport_height: f32 = 2 * h * focus_distance; | ||
const viewport_width: f32 = viewport_height * @as(f32, @floatFromInt(image_width)) / @as(f32, @floatFromInt(image_height)); | ||
const vfov: f32 = 20; | ||
const lookat = Point3.init(0, 0, 0); | ||
const vup = Vec3.init(0, 1, 0); | ||
const defocus_angle: f32 = 0.6; | ||
const focus_distance: f32 = 10.0; | ||
|
||
lookfrom: Vec3, | ||
pixel00_location: Vec3, | ||
pixel_delta_u: Vec3, | ||
pixel_delta_v: Vec3, | ||
camera_center: Vec3, | ||
samples: usize, | ||
max_children: usize, | ||
rand_engine: std.rand.DefaultPrng, | ||
random: std.rand.Random, | ||
u: Vec3, | ||
v: Vec3, | ||
w: Vec3, | ||
defocus_disk_u: Vec3, | ||
defocus_disk_v: Vec3, | ||
|
||
pub fn init(position: Vec3) Camera { | ||
var self: Camera = undefined; | ||
self.lookfrom = position; | ||
self.camera_center = self.lookfrom; | ||
|
||
self.w = self.lookfrom.sub(lookat).unit_vector(); | ||
self.u = vup.cross(self.w).unit_vector(); | ||
self.v = self.w.cross(self.u); | ||
|
||
var viewport_u = self.u.mul_scalar(viewport_width); | ||
var viewport_v = self.v.mul_scalar(-viewport_height); | ||
|
||
self.pixel_delta_u = viewport_u.div_scalar(@floatFromInt(image_width)); | ||
self.pixel_delta_v = viewport_v.div_scalar(@floatFromInt(image_height)); | ||
|
||
self.rand_engine = std.rand.DefaultPrng.init(0); | ||
self.random = self.rand_engine.random(); | ||
self.samples = 25; | ||
self.max_children = 7; | ||
|
||
var viewport_upper_left = self.camera_center.sub(self.w.mul_scalar(focus_distance)).sub(viewport_u.div_scalar(2.0)).sub(viewport_v.div_scalar(2.0)); | ||
self.pixel00_location = viewport_upper_left.add(self.pixel_delta_u.add(self.pixel_delta_v).mul_scalar(0.5)); | ||
|
||
const defocus_radians = (defocus_angle / 2.0) / 180.0 * std.math.pi; | ||
const defocus_radius = focus_distance * @tan(defocus_radians); | ||
|
||
self.defocus_disk_u = self.u.mul_scalar(defocus_radius); | ||
self.defocus_disk_v = self.v.mul_scalar(defocus_radius); | ||
|
||
return self; | ||
} | ||
|
||
fn pixel_sample_square(self: *Camera) Vec3 { | ||
const x = -0.5 + self.random.float(f32); | ||
const y = -0.5 + self.random.float(f32); | ||
|
||
return self.pixel_delta_u.mul_scalar(x).add(self.pixel_delta_v.mul_scalar(y)); | ||
} | ||
|
||
fn defocus_disk_sample(self: *Camera) Vec3 { | ||
const p = Vec3.random_in_unit_disk(self.random); | ||
return self.camera_center.add(self.defocus_disk_u.mul_scalar(p.data[0])).add(self.defocus_disk_v.mul_scalar(p.data[1])); | ||
} | ||
|
||
pub fn get_ray(self: *Camera, i: u32, j: u32) Ray { | ||
var pixel_center = self.pixel00_location.add(self.pixel_delta_u.mul_scalar(@floatFromInt(i))).add(self.pixel_delta_v.mul_scalar(@floatFromInt(j))); | ||
var pixel_sample = pixel_center.add(self.pixel_sample_square()); | ||
|
||
const ray_origin = if (defocus_angle <= 0) self.camera_center else self.defocus_disk_sample(); | ||
const ray_direction = pixel_sample.sub(ray_origin); | ||
|
||
return Ray.init(ray_origin, ray_direction); | ||
} | ||
|
||
pub fn render(self: *Camera, world: *HittableList) !void { | ||
var j: u32 = 0; | ||
while (j < image_height) : (j += 1) { | ||
//std.debug.print("Scanlines Remaining: {}\n", .{image_height - j}); | ||
|
||
var i: u32 = 0; | ||
while (i < image_width) : (i += 1) { | ||
var col = Color3.zero(); | ||
|
||
for (0..self.samples) |_| { | ||
const ray = self.get_ray(i, j); | ||
_ = col.addEq(self.ray_color(ray, self.max_children, world)); | ||
} | ||
|
||
const samples: f32 = @floatFromInt(self.samples); | ||
col = col.div_scalar(samples); | ||
|
||
const index: usize = i + j * image_width; | ||
const color = vec.color3_to_color(col); | ||
cart.framebuffer[index] = .{ | ||
.r = @truncate(color.rgb.r >> 3), | ||
.g = @truncate(color.rgb.g >> 2), | ||
.b = @truncate(color.rgb.b >> 3), | ||
}; | ||
} | ||
} | ||
//std.debug.print("Done!\n", .{}); | ||
} | ||
|
||
fn ray_color(self: *Camera, ray: Ray, depth: usize, world: *HittableList) Color3 { | ||
var hit_record: HitRecord = undefined; | ||
|
||
if (depth == 0) { | ||
return Color3.zero(); | ||
} | ||
|
||
if (world.hit(ray, Interval{ .min = 0.001, .max = std.math.inf(f32) }, &hit_record)) { | ||
var scattered: Ray = undefined; | ||
var attenuation: Color3 = undefined; | ||
|
||
const mat = hit_record.mat; | ||
if (mat.vtable.scatter(mat.ptr, self.random, ray, hit_record, &attenuation, &scattered)) { | ||
var col = self.ray_color(scattered, depth - 1, world); | ||
return col.mul(attenuation); | ||
} | ||
|
||
return Color3.zero(); | ||
} | ||
|
||
var dir = ray.direction.unit_vector(); | ||
const a = 0.5 * (dir.y() + 1.0); | ||
|
||
const white = Color3.init(1.0, 1.0, 1.0); | ||
const blue = Color3.init(0.5, 0.7, 1.0); | ||
|
||
return white.mul_scalar(1.0 - a).add(blue.mul_scalar(a)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
const vec = @import("vec.zig"); | ||
const Vec3 = vec.Vec3; | ||
const Point3 = vec.Point3; | ||
const Interval = @import("interval.zig"); | ||
const Ray = @import("ray.zig"); | ||
const std = @import("std"); | ||
const material = @import("material.zig"); | ||
const Material = material.Material; | ||
|
||
pub const HitRecord = struct { | ||
point: Point3, | ||
normal: Vec3, | ||
t: f32, | ||
front_face: bool, | ||
mat: Material, | ||
|
||
pub fn set_face_normal(self: *HitRecord, ray: Ray, outward_normal: Vec3) void { | ||
self.front_face = ray.direction.dot(outward_normal) < 0; | ||
self.normal = if (self.front_face) outward_normal else outward_normal.negate(); | ||
} | ||
}; | ||
|
||
pub const Hittable = struct { | ||
ptr: *anyopaque, | ||
vtable: *const VTable, | ||
|
||
pub const VTable = struct { | ||
hit: *const fn (ctx: *anyopaque, ray: Ray, ray_t: Interval, hit_record: *HitRecord, ret_addr: usize) bool, | ||
}; | ||
|
||
pub fn rawHit(self: Hittable, ray: Ray, ray_t: Interval, hit_record: *HitRecord, ret_addr: usize) bool { | ||
return self.vtable.hit(self.ptr, ray, ray_t, hit_record, ret_addr); | ||
} | ||
}; | ||
|
||
pub const Sphere = struct { | ||
center: Point3, | ||
radius: f32, | ||
mat: Material, | ||
|
||
pub fn init(center: Point3, radius: f32, mat: Material) Sphere { | ||
return Sphere{ .center = center, .radius = radius, .mat = mat }; | ||
} | ||
|
||
pub fn hit(ctx: *anyopaque, ray: Ray, ray_t: Interval, hit_record: *HitRecord, ret_addr: usize) bool { | ||
_ = ret_addr; | ||
const self: *Sphere = @ptrCast(@alignCast(ctx)); | ||
|
||
const oc = ray.origin.sub(self.center); | ||
const a = ray.direction.length_squared(); | ||
const half_b = oc.dot(ray.direction); | ||
const c = oc.length_squared() - self.radius * self.radius; | ||
|
||
const discriminant = half_b * half_b - a * c; | ||
if (discriminant < 0) | ||
return false; | ||
|
||
const sqrtd = std.math.sqrt(discriminant); | ||
|
||
var root = (-half_b - sqrtd) / a; | ||
|
||
if (!ray_t.surrounds(root)) { | ||
root = (-half_b + sqrtd) / a; | ||
if (!ray_t.surrounds(root)) | ||
return false; | ||
} | ||
|
||
hit_record.t = root; | ||
hit_record.point = ray.at(root); | ||
const outward_normal = hit_record.point.sub(self.center).div_scalar(self.radius); | ||
hit_record.set_face_normal(ray, outward_normal); | ||
hit_record.mat = self.mat; | ||
|
||
return true; | ||
} | ||
|
||
pub fn hittable(self: *Sphere) Hittable { | ||
return .{ | ||
.ptr = self, | ||
.vtable = &.{ | ||
.hit = hit, | ||
}, | ||
}; | ||
} | ||
}; | ||
|
||
pub const HittableList = struct { | ||
objects: std.ArrayList(Hittable), | ||
|
||
pub fn init(allocator: std.mem.Allocator) !HittableList { | ||
var self: HittableList = undefined; | ||
self.objects = std.ArrayList(Hittable).init(allocator); | ||
return self; | ||
} | ||
|
||
pub fn hit(self: *HittableList, ray: Ray, ray_t: Interval, hit_record: *HitRecord) bool { | ||
var record: HitRecord = undefined; | ||
var hit_anything: bool = false; | ||
var closest_so_far = ray_t.max; | ||
|
||
for (self.objects.items) |item| { | ||
const is_hit = item.vtable.hit(item.ptr, ray, ray_t, &record, @returnAddress()); | ||
|
||
if (is_hit) { | ||
// Make sure record is only set if it's closer | ||
if (record.t < closest_so_far) { | ||
hit_anything = true; | ||
closest_so_far = record.t; | ||
hit_record.* = record; | ||
} | ||
} | ||
} | ||
|
||
return hit_anything; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
const std = @import("std"); | ||
|
||
const Interval = @This(); | ||
|
||
max: f32, | ||
min: f32, | ||
|
||
pub fn empty() Interval { | ||
return .{ .min = std.math.inf(f32), .max = -std.math.inf(f32) }; | ||
} | ||
|
||
pub fn universe() Interval { | ||
return .{ .min = -std.math.inf(f32), .max = std.math.inf(f32) }; | ||
} | ||
|
||
pub fn contains(self: *const Interval, x: f32) bool { | ||
return self.min <= x and x <= self.max; | ||
} | ||
|
||
pub fn surrounds(self: *const Interval, x: f32) bool { | ||
return self.min < x and x < self.max; | ||
} | ||
|
||
pub fn clamp(self: *const Interval, x: f32) f32 { | ||
if (x < self.min) { | ||
return self.min; | ||
} else if (x > self.max) { | ||
return self.max; | ||
} | ||
|
||
return x; | ||
} |
Oops, something went wrong.