aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main.zig
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2022-12-07 22:37:14 +0900
committernsfisis <nsfisis@gmail.com>2022-12-07 22:54:47 +0900
commit86914985b77ddf5d6d3a3dd6c13deed9d906a471 (patch)
treea523883d6524d55aee713bfd6400f044f8715d52 /src/main.zig
parente264078ed9d94b5091a6d78f8128496ac49fbde4 (diff)
downloadRayTracingInOneWeekend.zig-86914985b77ddf5d6d3a3dd6c13deed9d906a471.tar.gz
RayTracingInOneWeekend.zig-86914985b77ddf5d6d3a3dd6c13deed9d906a471.tar.zst
RayTracingInOneWeekend.zig-86914985b77ddf5d6d3a3dd6c13deed9d906a471.zip
refactor: separate single main.zig
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig765
1 files changed, 56 insertions, 709 deletions
diff --git a/src/main.zig b/src/main.zig
index eb537a8..e0e5702 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -3,422 +3,38 @@ const debug = std.debug;
const math = std.math;
const ArrayList = std.ArrayList;
-const Vec3 = struct {
- x: f64,
- y: f64,
- z: f64,
-
- pub fn norm(v: Vec3) f64 {
- return @sqrt(v.normSquared());
- }
-
- pub fn normSquared(v: Vec3) f64 {
- return v.x * v.x + v.y * v.y + v.z * v.z;
- }
-
- pub fn dot(u: Vec3, v: Vec3) f64 {
- return u.x * v.x + u.y * v.y + u.z * v.z;
- }
-
- pub fn cross(u: Vec3, v: Vec3) Vec3 {
- return Vec3{
- .x = u.y * v.z - u.z * v.y,
- .y = u.z * v.x - u.x * v.z,
- .z = u.x * v.y - u.y * v.x,
- };
- }
-
- pub fn normalized(v: Vec3) Vec3 {
- const n = v.norm();
- if (n == 0.0) {
- return v;
- } else {
- return v.div(n);
- }
- }
-
- pub fn add(u: Vec3, v: Vec3) Vec3 {
- return Vec3{
- .x = u.x + v.x,
- .y = u.y + v.y,
- .z = u.z + v.z,
- };
- }
-
- pub fn sub(u: Vec3, v: Vec3) Vec3 {
- return Vec3{
- .x = u.x - v.x,
- .y = u.y - v.y,
- .z = u.z - v.z,
- };
- }
-
- pub fn mul(v: Vec3, t: f64) Vec3 {
- return Vec3{
- .x = v.x * t,
- .y = v.y * t,
- .z = v.z * t,
- };
- }
-
- pub fn mulV(u: Vec3, v: Vec3) Vec3 {
- return Vec3{
- .x = u.x * v.x,
- .y = u.y * v.y,
- .z = u.z * v.z,
- };
- }
-
- pub fn div(v: Vec3, t: f64) Vec3 {
- return Vec3{
- .x = v.x / t,
- .y = v.y / t,
- .z = v.z / t,
- };
- }
-
- pub fn random01(rand: std.rand.Random) Vec3 {
- return Vec3{
- .x = randomReal01(rand),
- .y = randomReal01(rand),
- .z = randomReal01(rand),
- };
- }
-
- pub fn random(rand: std.rand.Random, min: f64, max: f64) Vec3 {
- return Vec3{
- .x = randomReal(rand, min, max),
- .y = randomReal(rand, min, max),
- .z = randomReal(rand, min, max),
- };
- }
-
- // for debugging
- pub fn pp(v: Vec3) void {
- debug.print("{} {} {}\n", .{ v.x, v.y, v.z });
- }
-
- fn near_zero(v: Vec3) bool {
- const epsilon = 1e-8;
- return @fabs(v.x) < epsilon and @fabs(v.y) < epsilon and @fabs(v.z) < epsilon;
- }
-};
-
-fn randomPointInUnitSphere(rand: std.rand.Random) Vec3 {
- while (true) {
- const p = Vec3.random(rand, -1.0, 1.0);
- if (p.norm() >= 1) continue;
- return p;
- }
-}
-
-fn randomPointInUnitDisk(rand: std.rand.Random) Vec3 {
- while (true) {
- const p = Vec3{ .x = randomReal(rand, -1.0, 1.0), .y = randomReal(rand, -1.0, 1.0), .z = 0.0 };
- if (p.norm() >= 1) continue;
- return p;
- }
-}
-
-fn randomUnitVector(rand: std.rand.Random) Vec3 {
- return randomPointInUnitSphere(rand).normalized();
-}
-
-fn reflect(v: Vec3, n: Vec3) Vec3 {
- return v.sub(n.mul(2 * v.dot(n)));
-}
-
-fn refract(uv: Vec3, n: Vec3, etai_over_etat: f64) Vec3 {
- const cos_theta = @min(uv.mul(-1.0).dot(n), 1.0);
- const r_out_perpendicular = uv.add(n.mul(cos_theta)).mul(etai_over_etat);
- const r_out_parallel = n.mul(-@sqrt(@fabs(1.0 - r_out_perpendicular.normSquared())));
- return r_out_perpendicular.add(r_out_parallel);
-}
-
-const Point3 = Vec3;
-const Color = Vec3;
-
-fn rgb(r: f64, g: f64, b: f64) Color {
- return .{ .x = r, .y = g, .z = b };
-}
-
-const Ray = struct {
- origin: Vec3,
- dir: Vec3,
- time: f64,
-
- pub fn at(r: Ray, t: f64) Point3 {
- return r.origin.add(r.dir.mul(t));
- }
-};
-
-const MaterialTag = enum {
- diffuse,
- metal,
- dielectric,
-};
-
-const Material = union(MaterialTag) {
- diffuse: DiffuseMaterial,
- metal: MetalMaterial,
- dielectric: DielectricMaterial,
-
- fn scatter(mat: Material, r_in: Ray, record: HitRecord, attenuation: *Color, scattered: *Ray, rand: std.rand.Random) bool {
- return switch (mat) {
- MaterialTag.diffuse => |diffuse_mat| diffuse_mat.scatter(r_in, record, attenuation, scattered, rand),
- MaterialTag.metal => |metal_mat| metal_mat.scatter(r_in, record, attenuation, scattered, rand),
- MaterialTag.dielectric => |dielectric_mat| dielectric_mat.scatter(r_in, record, attenuation, scattered, rand),
- };
- }
-};
-
-const DiffuseMaterial = struct {
- albedo: Texture,
-
- fn scatter(mat: DiffuseMaterial, r_in: Ray, record: HitRecord, attenuation: *Color, scattered: *Ray, rand: std.rand.Random) bool {
- var scatter_direction = record.normal.add(randomUnitVector(rand));
- if (scatter_direction.near_zero()) {
- scatter_direction = record.normal;
- }
- scattered.* = .{ .origin = record.p, .dir = scatter_direction, .time = r_in.time };
- attenuation.* = mat.albedo.value(record.u, record.v, record.p);
- return true;
- }
-};
-
-const MetalMaterial = struct {
- albedo: Color,
- fuzz: f64,
-
- fn scatter(mat: MetalMaterial, r_in: Ray, record: HitRecord, attenuation: *Color, scattered: *Ray, rand: std.rand.Random) bool {
- debug.assert(mat.fuzz <= 1.0);
- const reflected = reflect(r_in.dir.normalized(), record.normal);
- scattered.* = .{ .origin = record.p, .dir = reflected.add(randomPointInUnitSphere(rand).mul(mat.fuzz)), .time = r_in.time };
- attenuation.* = mat.albedo;
- return reflected.dot(record.normal) > 0.0;
- }
-};
-
-const DielectricMaterial = struct {
- // index of refraction.
- ir: f64,
-
- fn scatter(mat: DielectricMaterial, r_in: Ray, record: HitRecord, attenuation: *Color, scattered: *Ray, rand: std.rand.Random) bool {
- const refraction_ratio = if (record.front_face) 1.0 / mat.ir else mat.ir;
- const unit_dir = r_in.dir.normalized();
-
- const cos_theta = @min(unit_dir.mul(-1.0).dot(record.normal), 1.0);
- const sin_theta = @sqrt(1.0 - cos_theta * cos_theta);
- // sin(theta') = refraction_ratio * sin(theta) <= 1
- const can_refract = refraction_ratio * sin_theta <= 1.0;
-
- const dir = if (can_refract and reflectance(cos_theta, refraction_ratio) < randomReal01(rand)) refract(unit_dir, record.normal, refraction_ratio) else reflect(unit_dir, record.normal);
- scattered.* = .{ .origin = record.p, .dir = dir, .time = r_in.time };
- attenuation.* = rgb(1.0, 1.0, 1.0);
- return true;
- }
-
- fn reflectance(cos: f64, refraction_idx: f64) f64 {
- const r0 = (1.0 - refraction_idx) / (1.0 + refraction_idx);
- const r1 = r0 * r0;
- return r1 + (1.0 - r1) * math.pow(f64, 1.0 - cos, 5.0);
- }
-};
-
-const HitRecord = struct {
- // The point where the ray and the hittable hits.
- p: Point3,
- // The normal of the hittable at p.
- normal: Vec3,
- // The material at p.
- material: *const Material,
- // p = ray.at(t)
- t: f64,
- // The coordinate of the surface where the ray intersects.
- u: f64,
- v: f64,
- // True if the ray hits the hittable from the front face, i.e., outside of it.
- front_face: bool,
-};
-
-const HittableTag = enum {
- sphere,
- movingSphere,
- list,
- bvhNode,
-};
-
-const Hittable = union(HittableTag) {
- sphere: Sphere,
- movingSphere: MovingSphere,
- list: HittableList,
- bvhNode: BvhNode,
-
- fn hit(h: Hittable, r: Ray, tMin: f64, tMax: f64, record: *HitRecord) bool {
- return switch (h) {
- HittableTag.sphere => |sphere| sphere.hit(r, tMin, tMax, record),
- HittableTag.movingSphere => |movingSphere| movingSphere.hit(r, tMin, tMax, record),
- HittableTag.list => |list| list.hit(r, tMin, tMax, record),
- HittableTag.bvhNode => |node| node.hit(r, tMin, tMax, record),
- };
- }
-
- fn boudingBox(h: Hittable, time0: f64, time1: f64, outputBox: *Aabb) bool {
- return switch (h.*) {
- HittableTag.sphere => |sphere| sphere.boudingBox(time0, time1, outputBox),
- HittableTag.movingSphere => |movingSphere| movingSphere.boudingBox(time0, time1, outputBox),
- HittableTag.list => |list| list.boudingBox(time0, time1, outputBox),
- HittableTag.bvhNode => |node| node.boudingBox(time0, time1, outputBox),
- };
- }
-
- fn deinit(h: *const Hittable, allocator: anytype) void {
- return switch (h.*) {
- HittableTag.sphere => |sphere| sphere.deinit(allocator),
- HittableTag.movingSphere => |movingSphere| movingSphere.deinit(allocator),
- HittableTag.list => |list| list.deinit(allocator),
- HittableTag.bvhNode => |node| node.deinit(allocator),
- };
- }
-};
-
-const Sphere = struct {
- center: Point3,
- radius: f64,
- material: *const Material,
-
- fn hit(sphere: Sphere, r: Ray, tMin: f64, tMax: f64, record: *HitRecord) bool {
- const oc = r.origin.sub(sphere.center);
- const a = r.dir.normSquared();
- const half_b = Vec3.dot(oc, r.dir);
- const c = oc.normSquared() - sphere.radius * sphere.radius;
-
- const discriminant = half_b * half_b - a * c;
- if (discriminant < 0.0) {
- // r does not intersect the sphere.
- return false;
- }
- const sqrtd = @sqrt(discriminant);
-
- // Find the nearest root that lies in the acceptable range.
- var root = (-half_b - sqrtd) / a;
- if (root < tMin or tMax < root) {
- root = (-half_b + sqrtd) / a;
- if (root < tMin or tMax < root) {
- // out of range
- return false;
- }
- }
-
- record.t = root;
- record.p = r.at(root);
- const outward_normal = (record.p.sub(sphere.center)).div(sphere.radius);
- record.front_face = Vec3.dot(outward_normal, r.dir) < 0.0;
- if (record.front_face) {
- record.normal = outward_normal;
- } else {
- record.normal = outward_normal.mul(-1.0);
- }
- Sphere.getSphereUv(outward_normal, &record.u, &record.v);
- record.material = sphere.material;
-
- return true;
- }
-
- fn boudingBox(sphere: Sphere, time0: f64, time1: f64, outputBox: *Aabb) bool {
- _ = time0;
- _ = time1;
- const o = sphere.center;
- const r = sphere.radius;
- outputBox.* = .{
- .min = o.sub(.{ .x = r, .y = r, .z = r }),
- .max = o.add(.{ .x = r, .y = r, .z = r }),
- };
- return true;
- }
-
- fn getSphereUv(p: Point3, u: *f64, v: *f64) void {
- const phi = math.atan2(f64, -p.z, p.x) + pi;
- const theta = math.acos(-p.y);
- u.* = phi / (2.0 * pi);
- v.* = theta / pi;
- }
-
- fn deinit(sphere: *const Sphere, allocator: anytype) void {
- allocator.destroy(sphere.material);
- }
-};
-
-const MovingSphere = struct {
- center0: Point3,
- center1: Point3,
- time0: f64,
- time1: f64,
- radius: f64,
- material: *const Material,
-
- fn hit(sphere: MovingSphere, r: Ray, tMin: f64, tMax: f64, record: *HitRecord) bool {
- const center_ = sphere.center(r.time);
- const oc = r.origin.sub(center_);
- const a = r.dir.normSquared();
- const half_b = Vec3.dot(oc, r.dir);
- const c = oc.normSquared() - sphere.radius * sphere.radius;
-
- const discriminant = half_b * half_b - a * c;
- if (discriminant < 0.0) {
- // r does not intersect the sphere.
- return false;
- }
- const sqrtd = @sqrt(discriminant);
-
- // Find the nearest root that lies in the acceptable range.
- var root = (-half_b - sqrtd) / a;
- if (root < tMin or tMax < root) {
- root = (-half_b + sqrtd) / a;
- if (root < tMin or tMax < root) {
- // out of range
- return false;
- }
- }
-
- record.t = root;
- record.p = r.at(root);
- const outward_normal = (record.p.sub(center_)).div(sphere.radius);
- record.front_face = Vec3.dot(outward_normal, r.dir) < 0.0;
- if (record.front_face) {
- record.normal = outward_normal;
- } else {
- record.normal = outward_normal.mul(-1.0);
- }
- record.material = sphere.material;
-
- return true;
- }
-
- fn boudingBox(sphere: MovingSphere, time0: f64, time1: f64, outputBox: *Aabb) bool {
- const o0 = sphere.center(time0);
- const o1 = sphere.center(time1);
- const r = sphere.radius;
- const box0 = .{
- .min = o0.sub(.{ .x = r, .y = r, .z = r }),
- .max = o0.add(.{ .x = r, .y = r, .z = r }),
- };
- const box1 = .{
- .min = o1.sub(.{ .x = r, .y = r, .z = r }),
- .max = o1.add(.{ .x = r, .y = r, .z = r }),
- };
- outputBox.* = surroundingBox(box0, box1);
- return true;
- }
-
- fn center(sphere: MovingSphere, t: f64) Point3 {
- return sphere.center0.add(sphere.center1.sub(sphere.center0).mul((t - sphere.time0) / (sphere.time1 - sphere.time0)));
- }
-
- fn deinit(sphere: *const MovingSphere, allocator: anytype) void {
- allocator.destroy(sphere.material);
- }
-};
+const rtw = @import("rtw.zig");
+
+const Ray = rtw.ray.Ray;
+const Vec3 = rtw.vec.Vec3;
+const Point3 = rtw.vec.Point3;
+const Color = rtw.vec.Color;
+const rgb = rtw.vec.rgb;
+const Random = rtw.rand.Random;
+const randomPointInUnitSphere = rtw.rand.randomPointInUnitSphere;
+const randomPointInUnitDisk = rtw.rand.randomPointInUnitDisk;
+const randomUnitVector = rtw.rand.randomUnitVector;
+const randomInt = rtw.rand.randomInt;
+const randomReal01 = rtw.rand.randomReal01;
+const randomReal = rtw.rand.randomReal;
+
+const Material = rtw.material.Material;
+const DiffuseMaterial = rtw.material.DiffuseMaterial;
+const MetalMaterial = rtw.material.MetalMaterial;
+const DielectricMaterial = rtw.material.DielectricMaterial;
+
+const Texture = rtw.texture.Texture;
+const SolidTexture = rtw.texture.SolidTexture;
+const CheckerTexture = rtw.texture.CheckerTexture;
+
+const Hittable = rtw.hittable.Hittable;
+const Sphere = rtw.hittable.Sphere;
+const MovingSphere = rtw.hittable.MovingSphere;
+const HittableList = rtw.hittable.HittableList;
+const BvhNode = rtw.hittable.BvhNode;
+
+const Aabb = rtw.aabb.Aabb;
+const HitRecord = rtw.hit_record.HitRecord;
fn makeSphere(center: Point3, radius: f64, material: *const Material) Hittable {
return .{
@@ -430,48 +46,6 @@ fn makeSphere(center: Point3, radius: f64, material: *const Material) Hittable {
};
}
-const HittableList = struct {
- objects: ArrayList(Hittable),
-
- fn hit(list: HittableList, r: Ray, tMin: f64, tMax: f64, record: *HitRecord) bool {
- var hit_anything = false;
- var closest_so_far = tMax;
-
- for (list.objects.items) |object| {
- var rec: HitRecord = undefined;
- if (object.hit(r, tMin, closest_so_far, &rec)) {
- hit_anything = true;
- closest_so_far = rec.t;
- record.* = rec;
- }
- }
- return hit_anything;
- }
-
- fn boudingBox(list: HittableList, time0: f64, time1: f64, outputBox: *Aabb) bool {
- if (list.objects.items.len == 0) {
- return false;
- }
- var firstBox = true;
- var tmpBox: Aabb = undefined;
- for (list.objects.items) |object| {
- if (!object.boudingBox(time0, time1, tmpBox)) {
- return false;
- }
- outputBox = if (firstBox) tmpBox else surroundingBox(outputBox, tmpBox);
- firstBox = false;
- }
- return true;
- }
-
- fn deinit(list: *const HittableList, allocator: anytype) void {
- for (list.objects.items) |object| {
- object.deinit(allocator);
- }
- list.objects.deinit();
- }
-};
-
const inf = math.inf(f64);
const pi = math.pi;
@@ -479,233 +53,6 @@ fn deg2rad(degree: f64) f64 {
return degree * pi / 180.0;
}
-// [min, max)
-fn randomInt(comptime T: type, rand: std.rand.Random, min: T, max: T) T {
- return rand.intRangeLessThan(T, min, max);
-}
-
-// [0, 1)
-fn randomReal01(rand: std.rand.Random) f64 {
- return rand.float(f64);
-}
-
-// [min, max)
-fn randomReal(rand: std.rand.Random, min: f64, max: f64) f64 {
- return min + randomReal01(rand) * (max - min);
-}
-
-const Aabb = struct {
- min: Point3,
- max: Point3,
-
- fn hit(aabb: Aabb, r: Ray, tMin: f64, tMax: f64) bool {
- var tMin_ = tMin;
- var tMax_ = tMax;
- {
- const s0 = (aabb.min.x - r.origin.x) / r.dir.x;
- const s1 = (aabb.max.x - r.origin.x) / r.dir.x;
- const t0 = @min(s0, s1);
- const t1 = @max(s0, s1);
- tMin_ = @max(t0, tMin_);
- tMax_ = @min(t1, tMax_);
- if (tMax_ <= tMin_) {
- return false;
- }
- }
- {
- const s0 = (aabb.min.y - r.origin.y) / r.dir.y;
- const s1 = (aabb.max.y - r.origin.y) / r.dir.y;
- const t0 = @min(s0, s1);
- const t1 = @max(s0, s1);
- tMin_ = @max(t0, tMin_);
- tMax_ = @min(t1, tMax_);
- if (tMax_ <= tMin_) {
- return false;
- }
- }
- {
- const s0 = (aabb.min.z - r.origin.z) / r.dir.z;
- const s1 = (aabb.max.z - r.origin.z) / r.dir.z;
- const t0 = @min(s0, s1);
- const t1 = @max(s0, s1);
- tMin_ = @max(t0, tMin_);
- tMax_ = @min(t1, tMax_);
- if (tMax_ <= tMin_) {
- return false;
- }
- }
- return true;
- }
-};
-
-fn surroundingBox(box0: Aabb, box1: Aabb) Aabb {
- return .{
- .min = .{
- .x = @min(box0.min.x, box1.min.x),
- .y = @min(box0.min.y, box1.min.y),
- .z = @min(box0.min.z, box1.min.z),
- },
- .max = .{
- .x = @max(box0.max.x, box1.max.x),
- .y = @max(box0.max.y, box1.max.y),
- .z = @max(box0.max.z, box1.max.z),
- },
- };
-}
-
-const BvhNode = struct {
- left: *Hittable, // TODO
- right: *Hittable, // TODO
- box: Aabb,
-
- fn init(
- objects: ArrayList(*Hittable),
- start: usize,
- end: usize,
- time0: f64,
- time1: f64,
- ) BvhNode {
- var left: *Hittable = undefined;
- var right: *Hittable = undefined;
-
- var objects_ = objects;
- const axis = randomInt(u8, 0, 3);
-
- const objectSpan = end - start;
- if (objectSpan == 1) {
- left = objects.items[start];
- right = objects.items[start];
- } else if (objectSpan == 2) {
- if (BvhNode.boxCompare(axis, objects[start], objects[start + 1])) {
- left = objects[start];
- right = objects[start + 1];
- } else {
- left = objects[start + 1];
- right = objects[start];
- }
- } else {
- std.sort.sort(*Hittable, objects_, axis, BvhNode.boxCompare);
- const mid = start + objectSpan / 2;
- left.* = .{ .bvhNode = BvhNode.init(objects, start, mid, time0, time1) };
- right.* = .{ .bvhNode = BvhNode.init(objects, mid, end, time0, time1) };
- }
-
- var boxLeft: Aabb = undefined;
- var boxRight: Aabb = undefined;
-
- if (!left.boudingBox(time0, time1, boxLeft) || !right.boudingBox(time0, time1, boxRight)) {
- // ERROR
- }
-
- return .{
- .left = left,
- .right = right,
- .box = surroundingBox(boxLeft, boxRight),
- };
- }
-
- fn boxCompare(axis: u8, a: *const Hittable, b: *const Hittable) bool {
- if (axis == 0) {
- return a.x < b.x;
- } else if (axis == 1) {
- return a.y < b.y;
- } else {
- return a.z < b.z;
- }
- }
-
- fn hit(node: BvhNode, r: Ray, tMin: f64, tMax: f64, record: *HitRecord) bool {
- if (!node.box.hit(r, tMin, tMax)) {
- return false;
- }
-
- const hitLeft = node.left.hit(r, tMin, tMax, record);
- const hitRight = node.right.hit(r, tMin, if (hitLeft) record.t else tMax, record);
-
- return hitLeft or hitRight;
- }
-
- fn boudingBox(node: BvhNode, time0: f64, time1: f64, outputBox: *Aabb) bool {
- _ = time0;
- _ = time1;
- outputBox.* = node.box;
- return true;
- }
-
- fn deinit(node: *const BvhNode, allocator: anytype) void {
- _ = node;
- _ = allocator;
- }
-};
-
-const TextureTag = enum {
- solid,
- checker,
-};
-
-const Texture = union(TextureTag) {
- solid: SolidTexture,
- checker: CheckerTexture,
-
- fn makeSolid(color: Color) Texture {
- return .{ .solid = .{ .color = color } };
- }
-
- fn makeChecker(allocator: std.mem.Allocator, odd: Color, even: Color) !Texture {
- return .{ .checker = try CheckerTexture.init(
- allocator,
- Texture.makeSolid(odd),
- Texture.makeSolid(even),
- ) };
- }
-
- 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),
- };
- }
-};
-
-const SolidTexture = struct {
- color: Color,
-
- fn value(tx: SolidTexture, u: f64, v: f64, p: Vec3) Color {
- _ = u;
- _ = v;
- _ = p;
- return tx.color;
- }
-};
-
-const CheckerTexture = struct {
- allocator: std.mem.Allocator,
- odd: *const Texture,
- even: *const Texture,
-
- fn init(allocator: std.mem.Allocator, odd: Texture, even: Texture) !CheckerTexture {
- var odd_ = try allocator.create(Texture);
- var even_ = try allocator.create(Texture);
- odd_.* = odd;
- even_.* = even;
- return .{
- .allocator = allocator,
- .odd = odd_,
- .even = even_,
- };
- }
-
- fn deinit(tx: CheckerTexture) void {
- tx.allocator.destroy(tx.even);
- tx.allocator.destroy(tx.odd);
- }
-
- fn value(tx: CheckerTexture, u: f64, v: f64, p: Vec3) Color {
- const sines = @sin(10 * p.x) * @sin(10 * p.y) * @sin(10 * p.z);
- return if (sines < 0) tx.odd.value(u, v, p) else tx.even.value(u, v, p);
- }
-};
-
const Camera = struct {
origin: Point3,
horizontal: Vec3,
@@ -757,19 +104,19 @@ const Camera = struct {
};
}
- fn getRay(camera: Camera, rand: std.rand.Random, s: f64, t: f64) Ray {
- const rd = randomPointInUnitDisk(rand).mul(camera.lens_radius);
+ fn getRay(camera: Camera, rng: Random, s: f64, t: f64) Ray {
+ const rd = randomPointInUnitDisk(rng).mul(camera.lens_radius);
const offset = camera.u.mul(rd.x).add(camera.v.mul(rd.y));
const dir = camera.lower_left_corner.add(camera.horizontal.mul(s)).add(camera.vertical.mul(t)).sub(camera.origin).sub(offset);
return .{
.origin = camera.origin.add(offset),
.dir = dir,
- .time = randomReal(rand, camera.time0, camera.time1),
+ .time = randomReal(rng, camera.time0, camera.time1),
};
}
};
-fn rayColor(r: Ray, world: Hittable, rand: std.rand.Random, depth: u32) Color {
+fn rayColor(r: Ray, world: Hittable, rng: Random, depth: u32) Color {
var rec: HitRecord = undefined;
if (depth == 0) {
// If we've exceeded the ray bounce limit, no more ligth is gathered.
@@ -778,8 +125,8 @@ fn rayColor(r: Ray, world: Hittable, rand: std.rand.Random, depth: u32) Color {
if (world.hit(r, 0.001, inf, &rec)) {
var scattered: Ray = undefined;
var attenuation: Color = undefined;
- if (rec.material.scatter(r, rec, &attenuation, &scattered, rand)) {
- return attenuation.mulV(rayColor(scattered, world, rand, depth - 1));
+ if (rec.material.scatter(r, rec, &attenuation, &scattered, rng)) {
+ return attenuation.mulV(rayColor(scattered, world, rng, depth - 1));
} else {
return rgb(0.0, 0.0, 0.0);
}
@@ -798,8 +145,8 @@ fn writeColor(out: anytype, c: Color, samples_per_pixel: u32) !void {
});
}
-fn generateTwoSpheres(rand: std.rand.Random, allocator: anytype) !Hittable {
- _ = rand;
+fn generateTwoSpheres(rng: Random, allocator: anytype) !Hittable {
+ _ = rng;
var hittable_objects = ArrayList(Hittable).init(allocator);
const checker = try Texture.makeChecker(allocator, rgb(0.2, 0.3, 0.1), rgb(0.9, 0.9, 0.9));
@@ -815,7 +162,7 @@ fn generateTwoSpheres(rand: std.rand.Random, allocator: anytype) !Hittable {
return .{ .list = .{ .objects = hittable_objects } };
}
-fn generateRandomScene(rand: std.rand.Random, allocator: anytype) !Hittable {
+fn generateRandomScene(rng: Random, allocator: anytype) !Hittable {
var hittable_objects = ArrayList(Hittable).init(allocator);
var mat_ground = try allocator.create(Material);
@@ -839,11 +186,11 @@ fn generateRandomScene(rand: std.rand.Random, allocator: anytype) !Hittable {
while (a < 3) : (a += 1) {
var b: i32 = -3;
while (b < 3) : (b += 1) {
- const choose_mat = randomReal01(rand);
+ const choose_mat = randomReal01(rng);
const center = Point3{
- .x = @intToFloat(f64, a) + 0.9 * randomReal01(rand),
+ .x = @intToFloat(f64, a) + 0.9 * randomReal01(rng),
.y = 0.2,
- .z = @intToFloat(f64, b) + 0.9 * randomReal01(rand),
+ .z = @intToFloat(f64, b) + 0.9 * randomReal01(rng),
};
if (center.sub(.{ .x = 4, .y = 0.2, .z = 0 }).norm() <= 0.9) {
@@ -853,9 +200,9 @@ fn generateRandomScene(rand: std.rand.Random, allocator: anytype) !Hittable {
var mat_sphere = try allocator.create(Material);
if (choose_mat < 0.8) {
// diffuse
- const albedo = Color.random01(rand).mulV(Color.random01(rand));
+ const albedo = Color.random01(rng).mulV(Color.random01(rng));
mat_sphere.* = .{ .diffuse = .{ .albedo = .{ .solid = .{ .color = albedo } } } };
- const center1 = center.add(.{ .x = 0, .y = randomReal(rand, 0, 0.5), .z = 0 });
+ const center1 = center.add(.{ .x = 0, .y = randomReal(rng, 0, 0.5), .z = 0 });
try hittable_objects.append(.{ .movingSphere = .{
.center0 = center,
.center1 = center1,
@@ -866,8 +213,8 @@ fn generateRandomScene(rand: std.rand.Random, allocator: anytype) !Hittable {
} });
} else if (choose_mat < 0.95) {
// metal
- const albedo = Color.random(rand, 0.5, 1);
- const fuzz = randomReal(rand, 0, 0.5);
+ const albedo = Color.random(rng, 0.5, 1);
+ const fuzz = randomReal(rng, 0, 0.5);
mat_sphere.* = .{ .metal = .{ .albedo = albedo, .fuzz = fuzz } };
try hittable_objects.append(makeSphere(center, 0.2, mat_sphere));
} else {
@@ -886,8 +233,8 @@ pub fn main() !void {
const allocator = gpa.allocator();
defer debug.assert(!gpa.deinit());
- var rng = std.rand.DefaultPrng.init(42);
- var rand = rng.random();
+ var rng_ = std.rand.DefaultPrng.init(42);
+ var rng = rng_.random();
// Image
const aspect_ratio = 3.0 / 2.0;
@@ -906,13 +253,13 @@ pub fn main() !void {
var aperture: f64 = 0;
if (scene == 1) {
- world = try generateRandomScene(rand, allocator);
+ world = try generateRandomScene(rng, allocator);
lookFrom = .{ .x = 13, .y = 2, .z = 3 };
lookAt = .{ .x = 0, .y = 0, .z = 0 };
vFov = 20.0;
aperture = 0.1;
} else if (scene == 2) {
- world = try generateTwoSpheres(rand, allocator);
+ world = try generateTwoSpheres(rng, allocator);
lookFrom = .{ .x = 13, .y = 2, .z = 3 };
lookAt = .{ .x = 0, .y = 0, .z = 0 };
vFov = 20.0;
@@ -947,10 +294,10 @@ pub fn main() !void {
var s: u32 = 0;
var pixelColor = rgb(0.0, 0.0, 0.0);
while (s < samples_per_pixel) : (s += 1) {
- const u = (@intToFloat(f64, i) + randomReal01(rand)) / (image_width - 1);
- const v = (@intToFloat(f64, j) + randomReal01(rand)) / (image_height - 1);
- const r = camera.getRay(rand, u, v);
- pixelColor = pixelColor.add(rayColor(r, world, rand, max_depth));
+ const u = (@intToFloat(f64, i) + randomReal01(rng)) / (image_width - 1);
+ const v = (@intToFloat(f64, j) + randomReal01(rng)) / (image_height - 1);
+ const r = camera.getRay(rng, u, v);
+ pixelColor = pixelColor.add(rayColor(r, world, rng, max_depth));
}
try writeColor(stdout, pixelColor, samples_per_pixel);
}