zigrtiow: use Sphere, Hittable, and HittableList abstractions.
This commit is contained in:
parent
5043a7e526
commit
84a0ba2ec6
36
zigrtiow/src/hittable.zig
Normal file
36
zigrtiow/src/hittable.zig
Normal file
@ -0,0 +1,36 @@
|
||||
const vec = @import("./vec.zig");
|
||||
const ray = @import("./ray.zig");
|
||||
|
||||
const Sphere = @import("./sphere.zig").Sphere;
|
||||
const HittableList = @import("./hittable_list.zig").HittableList;
|
||||
|
||||
const Vec3 = vec.Vec3;
|
||||
const Point3 = vec.Point3;
|
||||
const Ray = ray.Ray;
|
||||
|
||||
pub const Hittable = union(enum) {
|
||||
sphere: Sphere,
|
||||
hittable_list: HittableList,
|
||||
|
||||
pub fn hit(hittable: Hittable, r: Ray, t_min: f32, t_max: f32) ?HitRecord {
|
||||
return switch (hittable) {
|
||||
.sphere => |sphere| sphere.hit(r, t_min, t_max),
|
||||
.hittable_list => |hittable_list| hittable_list.hit(r, t_min, t_max),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const HitRecord = struct {
|
||||
p: Point3,
|
||||
normal: Vec3,
|
||||
t: f32,
|
||||
front_face: bool,
|
||||
|
||||
pub fn set_face_normal(hr: *HitRecord, r: Ray, outward_normal: Vec3) void {
|
||||
hr.front_face = r.direction().dot(outward_normal) < 0;
|
||||
hr.normal = if (hr.front_face)
|
||||
outward_normal
|
||||
else
|
||||
outward_normal.scale(-1);
|
||||
}
|
||||
};
|
||||
35
zigrtiow/src/hittable_list.zig
Normal file
35
zigrtiow/src/hittable_list.zig
Normal file
@ -0,0 +1,35 @@
|
||||
const std = @import("std");
|
||||
const ray = @import("./ray.zig");
|
||||
const hittable = @import("./hittable.zig");
|
||||
|
||||
const info = std.log.info;
|
||||
const ArrayList = std.ArrayList;
|
||||
const Ray = ray.Ray;
|
||||
const HitRecord = hittable.HitRecord;
|
||||
const Hittable = hittable.Hittable;
|
||||
|
||||
pub const HittableList = struct {
|
||||
objects: ArrayList(Hittable),
|
||||
|
||||
pub fn init() HittableList {
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
return HittableList{
|
||||
.objects = ArrayList(Hittable).init(allocator),
|
||||
};
|
||||
}
|
||||
pub fn hit(hittable_list: HittableList, r: Ray, t_min: f32, t_max: f32) ?HitRecord {
|
||||
var temp_rec: ?HitRecord = null;
|
||||
var closest_so_far = t_max;
|
||||
for (hittable_list.objects.items) |object| {
|
||||
if (object.hit(r, t_min, closest_so_far)) |rec| {
|
||||
temp_rec = rec;
|
||||
closest_so_far = rec.t;
|
||||
}
|
||||
}
|
||||
return temp_rec;
|
||||
}
|
||||
pub fn add(hittable_list: *HittableList, object: Hittable) anyerror!void {
|
||||
try hittable_list.objects.append(object);
|
||||
}
|
||||
};
|
||||
@ -2,27 +2,24 @@ const std = @import("std");
|
||||
const color = @import("./color.zig");
|
||||
const ray = @import("./ray.zig");
|
||||
const vec = @import("./vec.zig");
|
||||
const sphere = @import("./sphere.zig");
|
||||
const hittable = @import("./hittable.zig");
|
||||
const hittable_list = @import("./hittable_list.zig");
|
||||
|
||||
const Color = vec.Color;
|
||||
const Vec3 = vec.Vec3;
|
||||
const Hittable = hittable.Hittable;
|
||||
const HittableList = hittable_list.HittableList;
|
||||
const Point3 = vec.Point3;
|
||||
const Ray = ray.Ray;
|
||||
const Sphere = sphere.Sphere;
|
||||
const Vec3 = vec.Vec3;
|
||||
const info = std.log.info;
|
||||
const write_color = color.write_color;
|
||||
const Ray = ray.Ray;
|
||||
|
||||
fn hit_sphere(center: Point3, radius: f32, r: Ray) f32 {
|
||||
const oc = r.origin().sub(center);
|
||||
const a = r.direction().length_squared();
|
||||
const half_b = Vec3.dot(oc, r.direction());
|
||||
const c = oc.length_squared() - radius * radius;
|
||||
const discriminant = half_b * half_b - a * c;
|
||||
return if (discriminant < 0) -1 else (-half_b - @sqrt(discriminant)) / a;
|
||||
}
|
||||
|
||||
fn ray_color(r: Ray) Color {
|
||||
var t = hit_sphere(Point3.init(0, 0, -1), 0.5, r);
|
||||
if (t > 0) {
|
||||
const n = r.at(t).sub(Vec3.init(0, 0, -1)).unit();
|
||||
fn ray_color(r: Ray, world: Hittable) Color {
|
||||
var hit = world.hit(r, 0, std.math.inf(f32));
|
||||
if (hit) |rec| {
|
||||
const n = rec.normal;
|
||||
return Color.init(
|
||||
n.x() + 1,
|
||||
n.y() + 1,
|
||||
@ -30,7 +27,7 @@ fn ray_color(r: Ray) Color {
|
||||
).scale(0.5);
|
||||
}
|
||||
var unit_direction = r.direction().unit();
|
||||
t = 0.5 * (unit_direction.y() + 1);
|
||||
const t = 0.5 * (unit_direction.y() + 1);
|
||||
return Color.init(1, 1, 1).scale(1 - t).add(Color.init(0.5, 0.7, 1.0).scale(t));
|
||||
}
|
||||
|
||||
@ -40,6 +37,11 @@ pub fn main() anyerror!void {
|
||||
const image_width = 400;
|
||||
const image_height = @floatToInt(isize, @intToFloat(f32, image_width) / aspect_ratio);
|
||||
|
||||
// World
|
||||
var world = HittableList.init();
|
||||
try world.add(Hittable{ .sphere = Sphere.init(Point3.init(0, 0, -1), 0.5) });
|
||||
try world.add(Hittable{ .sphere = Sphere.init(Point3.init(0, -100.5, -1), 100) });
|
||||
|
||||
// Camera
|
||||
const viewport_height = 2;
|
||||
const viewport_width = aspect_ratio * viewport_height;
|
||||
@ -64,7 +66,7 @@ pub fn main() anyerror!void {
|
||||
const u = @intToFloat(f32, i) / @intToFloat(f32, image_width - 1);
|
||||
const v = @intToFloat(f32, j) / @intToFloat(f32, image_height - 1);
|
||||
const r = Ray.init(origin, lower_left_corner.add(horizontal.scale(u)).add(vertical.scale(v)).sub(origin));
|
||||
const pixel_color = ray_color(r);
|
||||
const pixel_color = ray_color(r, Hittable{ .hittable_list = world });
|
||||
try write_color(pixel_color);
|
||||
}
|
||||
}
|
||||
|
||||
51
zigrtiow/src/sphere.zig
Normal file
51
zigrtiow/src/sphere.zig
Normal file
@ -0,0 +1,51 @@
|
||||
const vec = @import("./vec.zig");
|
||||
const ray = @import("./ray.zig");
|
||||
const hittable = @import("./hittable.zig");
|
||||
|
||||
const Vec3 = vec.Vec3;
|
||||
const Point3 = vec.Point3;
|
||||
const Ray = ray.Ray;
|
||||
const HitRecord = hittable.HitRecord;
|
||||
|
||||
pub const Sphere = struct {
|
||||
center: Point3,
|
||||
radius: f32,
|
||||
|
||||
pub fn init(center: Point3, radius: f32) Sphere {
|
||||
return Sphere{
|
||||
.center = center,
|
||||
.radius = radius,
|
||||
};
|
||||
}
|
||||
pub fn hit(sphere: Sphere, r: Ray, t_min: f32, t_max: f32) ?HitRecord {
|
||||
const center = sphere.center;
|
||||
const radius = sphere.radius;
|
||||
const oc = r.origin().sub(center);
|
||||
const a = r.direction().length_squared();
|
||||
const half_b = Vec3.dot(oc, r.direction());
|
||||
const c = oc.length_squared() - radius * radius;
|
||||
|
||||
const discriminant = half_b * half_b - a * c;
|
||||
if (discriminant < 0) return null;
|
||||
|
||||
const sqrtd = @sqrt(discriminant);
|
||||
|
||||
// Find the nearest root that lies in the acceptable range.
|
||||
var root = (-half_b - sqrtd) / a;
|
||||
|
||||
if ((root < t_min) or (t_max < root)) {
|
||||
root = (-half_b + sqrtd) / a;
|
||||
if ((root < t_min) or (t_max < root)) return null;
|
||||
}
|
||||
const p = r.at(root);
|
||||
const outward_normal = p.sub(center).scale(1 / radius);
|
||||
var hr = HitRecord{
|
||||
.t = root,
|
||||
.p = p,
|
||||
.normal = Vec3.init(0, 0, 0),
|
||||
.front_face = false,
|
||||
};
|
||||
hr.set_face_normal(r, outward_normal);
|
||||
return hr;
|
||||
}
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user