132 lines
3.1 KiB
Zig
132 lines
3.1 KiB
Zig
const std = @import("std");
|
|
const print = std.debug.print;
|
|
const math = std.math;
|
|
const Random = std.rand.Random;
|
|
|
|
pub const Vec3 = packed struct {
|
|
x: f32 = 0.0,
|
|
y: f32 = 0.0,
|
|
z: f32 = 0.0,
|
|
|
|
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(self: Vec3, v: Vec3) Vec3 {
|
|
return Vec3{
|
|
.x = self.x * v.x,
|
|
.y = self.y * v.y,
|
|
.z = self.z * v.z,
|
|
};
|
|
}
|
|
|
|
pub fn mul_s(self: Vec3, scalar: f32) Vec3 {
|
|
return Vec3{
|
|
.x = self.x * scalar,
|
|
.y = self.y * scalar,
|
|
.z = self.z * scalar,
|
|
};
|
|
}
|
|
|
|
pub fn div(self: Vec3, scalar: f32) Vec3 {
|
|
return Vec3{
|
|
.x = self.x / scalar,
|
|
.y = self.y / scalar,
|
|
.z = self.z / scalar,
|
|
};
|
|
}
|
|
|
|
pub fn length(self: Vec3) f32 {
|
|
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
|
|
}
|
|
|
|
pub fn length_squared(self: Vec3) f32 {
|
|
return self.x * self.x + self.y * self.y + self.z * self.z;
|
|
}
|
|
|
|
pub fn dot(u: Vec3, v: Vec3) f32 {
|
|
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 unit(self: Vec3) Vec3 {
|
|
return self.div(self.length());
|
|
}
|
|
|
|
pub fn nearZero(self: Vec3) bool {
|
|
const t = 1e-8;
|
|
return math.absFloat(self.x) < t
|
|
and math.absFloat(self.y) < t
|
|
and math.absFloat(self.z) < t;
|
|
}
|
|
|
|
pub fn reflect(self: Vec3, n: Vec3) Vec3 {
|
|
return self.sub(n.mul_s(self.dot(n) * 2));
|
|
}
|
|
};
|
|
|
|
pub fn random(rng: *Random, min: f32, max: f32) Vec3 {
|
|
const range = max - min;
|
|
return Vec3{
|
|
.x = rng.*.float(f32) * range + min,
|
|
.y = rng.*.float(f32) * range + min,
|
|
.z = rng.*.float(f32) * range + min,
|
|
};
|
|
}
|
|
|
|
pub fn random_in_unit_sphere(rng: *Random) Vec3 {
|
|
while (true) {
|
|
const v = random(rng, -1, 1);
|
|
if (v.length_squared() < 1) {
|
|
return v;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn random_unit_vector(rng: *Random) Vec3 {
|
|
return random_in_unit_sphere(rng).unit();
|
|
}
|
|
|
|
pub fn random_in_hemisphere(rng: *Random, normal: Vec3) Vec3 {
|
|
const in_unit_sphere = random_in_unit_sphere(rng);
|
|
if (in_unit_sphere.dot(normal) > 0) {
|
|
// In the same hemisphere as the normal
|
|
return in_unit_sphere;
|
|
} else {
|
|
return in_unit_sphere.mul_s(-1);
|
|
}
|
|
}
|
|
|
|
pub const Point3 = Vec3;
|
|
|
|
const assert = @import("std").debug.assert;
|
|
|
|
fn assert_cmp(actual: f32, expected: f32) void {
|
|
const epsilon: f32 = 1e-5;
|
|
assert(math.fabs(actual - expected) < epsilon);
|
|
}
|
|
|
|
test "Vec3.length" {
|
|
const v = Vec3{ .x = 1.0, .y = 1.0, .z = 1.0 };
|
|
assert_cmp(v.length(), 1.7320508);
|
|
}
|