Refactor to hardcode f32 and use @Vector
This commit is contained in:
parent
d53cf2063b
commit
8b8eeb25c9
5 changed files with 566 additions and 288 deletions
|
|
@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
const unit_tests = b.addTest(.{
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("./main.zig"),
|
||||
.root_source_file = b.path("./src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
|
|
|
|||
7
main.zig
7
main.zig
|
|
@ -1,7 +0,0 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {}
|
||||
|
||||
test "main" {
|
||||
_ = @import("./vec3/src/vec3.zig");
|
||||
}
|
||||
270
src/main.zig
Normal file
270
src/main.zig
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
const std = @import("std");
|
||||
|
||||
const Vec3F32Simd = @Vector(3, f32);
|
||||
const Vec4F32Simd = @Vector(4, f32);
|
||||
|
||||
const Vec3F32Struct = struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
};
|
||||
|
||||
pub fn vec3_struct_add(a: Vec3F32Struct, b: Vec3F32Struct) Vec3F32Struct {
|
||||
return .{
|
||||
.x = a.x + b.x,
|
||||
.y = a.y + b.y,
|
||||
.z = a.z + b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn vec3_struct_mul(a: Vec3F32Struct, b: Vec3F32Struct) Vec3F32Struct {
|
||||
return .{
|
||||
.x = a.x * b.x,
|
||||
.y = a.y * b.y,
|
||||
.z = a.z * b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn vec3_struct_sub(a: Vec3F32Struct, b: Vec3F32Struct) Vec3F32Struct {
|
||||
return .{
|
||||
.x = a.x - b.x,
|
||||
.y = a.y - b.y,
|
||||
.z = a.z - b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn vec3_struct_kernel(a: Vec3F32Struct, x: Vec3F32Struct, c: Vec3F32Struct) Vec3F32Struct {
|
||||
const mixed = vec3_struct_add(vec3_struct_sub(vec3_struct_add(a, x), c), vec3_struct_mul(vec3_struct_sub(a, c), c));
|
||||
return .{
|
||||
.x = @sqrt(@abs(mixed.x) + 1.0),
|
||||
.y = @sqrt(@abs(mixed.y) + 1.0),
|
||||
.z = @sqrt(@abs(mixed.z) + 1.0),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn vec3_simd_add(a: Vec3F32Simd, b: Vec3F32Simd) Vec3F32Simd {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
pub fn vec3_simd_mul(a: Vec3F32Simd, b: Vec3F32Simd) Vec3F32Simd {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
pub fn vec3_simd_sub(a: Vec3F32Simd, b: Vec3F32Simd) Vec3F32Simd {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
pub fn vec3_simd_kernel(a: Vec3F32Simd, x: Vec3F32Simd, c: Vec3F32Simd) Vec3F32Simd {
|
||||
const mixed = vec3_simd_add(vec3_simd_sub(vec3_simd_add(a, x), c), vec3_simd_mul(vec3_simd_sub(a, c), c));
|
||||
return @sqrt(@abs(mixed) + @as(Vec3F32Simd, @splat(1.0)));
|
||||
}
|
||||
|
||||
pub fn vec4_simd_add(a: Vec4F32Simd, b: Vec4F32Simd) Vec4F32Simd {
|
||||
return a + b;
|
||||
}
|
||||
pub fn vec4_simd_mul(a: Vec4F32Simd, b: Vec4F32Simd) Vec4F32Simd {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
pub fn vec4_simd_sub(a: Vec4F32Simd, b: Vec4F32Simd) Vec4F32Simd {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
pub fn vec4_simd_kernel(a: Vec4F32Simd, x: Vec4F32Simd, c: Vec4F32Simd) Vec4F32Simd {
|
||||
const mixed = vec4_simd_add(vec4_simd_sub(vec4_simd_add(a, x), c), vec4_simd_mul(vec4_simd_sub(a, c), c));
|
||||
return @sqrt(@abs(mixed) + @as(Vec4F32Simd, @splat(1.0)));
|
||||
}
|
||||
|
||||
pub fn bench_vec3F32Simd(io: std.Io) void {
|
||||
var rng: std.Random.DefaultPrng = .init(42);
|
||||
var prng = rng.random();
|
||||
|
||||
var a: Vec3F32Simd = .{ 0, 0, 0 };
|
||||
const x: Vec3F32Simd = .{ prng.float(f32), prng.float(f32), prng.float(f32) };
|
||||
const c: Vec3F32Simd = .{ prng.float(f32), prng.float(f32), prng.float(f32) };
|
||||
|
||||
var i: usize = 0;
|
||||
const start = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
while (i < 100_000_000) : (i += 1) {
|
||||
a = vec3_simd_kernel(a, x, c);
|
||||
}
|
||||
const end = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
|
||||
std.debug.print("Vec3F32Simd took {} with final answer {}\n", .{ end - start, a });
|
||||
}
|
||||
|
||||
pub fn bench_vec4F32Simd(io: std.Io) void {
|
||||
var rng: std.Random.DefaultPrng = .init(42);
|
||||
var prng = rng.random();
|
||||
var a: Vec4F32Simd = .{ 0, 0, 0, 0 };
|
||||
const x: Vec4F32Simd = .{ prng.float(f32), prng.float(f32), prng.float(f32), prng.float(f32) };
|
||||
const c: Vec4F32Simd = .{ prng.float(f32), prng.float(f32), prng.float(f32), prng.float(f32) };
|
||||
|
||||
var i: usize = 0;
|
||||
const start = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
while (i < 100_000_000) : (i += 1) {
|
||||
a = vec4_simd_kernel(a, x, c);
|
||||
}
|
||||
const end = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
|
||||
std.debug.print("Vec4F32Simd took {} with final answer {}\n", .{ end - start, a });
|
||||
}
|
||||
|
||||
pub fn bench_vec3F32Struct(io: std.Io) void {
|
||||
var rng: std.Random.DefaultPrng = .init(42);
|
||||
var prng = rng.random();
|
||||
var a: Vec3F32Struct = .{ .x = 0, .y = 0, .z = 0 };
|
||||
const x: Vec3F32Struct = .{ .x = prng.float(f32), .y = prng.float(f32), .z = prng.float(f32) };
|
||||
const c: Vec3F32Struct = .{ .x = prng.float(f32), .y = prng.float(f32), .z = prng.float(f32) };
|
||||
|
||||
var i: usize = 0;
|
||||
const start = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
while (i < 100_000_000) : (i += 1) {
|
||||
a = vec3_struct_kernel(a, x, c);
|
||||
}
|
||||
const end = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
|
||||
std.debug.print("Vec3F32Struct took {} with final answer {}\n", .{ end - start, a });
|
||||
}
|
||||
|
||||
const Vec3F64Struct = struct {
|
||||
x: f64,
|
||||
y: f64,
|
||||
z: f64,
|
||||
};
|
||||
|
||||
const Vec3F64Simd = @Vector(3, f64);
|
||||
const Vec4F64Simd = @Vector(4, f64);
|
||||
|
||||
pub fn f64vec3_struct_add(a: Vec3F64Struct, b: Vec3F64Struct) Vec3F64Struct {
|
||||
return .{
|
||||
.x = a.x + b.x,
|
||||
.y = a.y + b.y,
|
||||
.z = a.z + b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn f64vec3_struct_mul(a: Vec3F64Struct, b: Vec3F64Struct) Vec3F64Struct {
|
||||
return .{
|
||||
.x = a.x * b.x,
|
||||
.y = a.y * b.y,
|
||||
.z = a.z * b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn f64vec3_struct_sub(a: Vec3F64Struct, b: Vec3F64Struct) Vec3F64Struct {
|
||||
return .{
|
||||
.x = a.x - b.x,
|
||||
.y = a.y - b.y,
|
||||
.z = a.z - b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn f64vec3_struct_kernel(a: Vec3F64Struct, x: Vec3F64Struct, c: Vec3F64Struct) Vec3F64Struct {
|
||||
const mixed = f64vec3_struct_add(f64vec3_struct_sub(f64vec3_struct_add(a, x), c), f64vec3_struct_mul(f64vec3_struct_sub(a, c), c));
|
||||
return .{
|
||||
.x = @sqrt(@abs(mixed.x) + 1.0),
|
||||
.y = @sqrt(@abs(mixed.y) + 1.0),
|
||||
.z = @sqrt(@abs(mixed.z) + 1.0),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn f64vec3_simd_add(a: Vec3F64Simd, b: Vec3F64Simd) Vec3F64Simd {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
pub fn f64vec3_simd_mul(a: Vec3F64Simd, b: Vec3F64Simd) Vec3F64Simd {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
pub fn f64vec3_simd_sub(a: Vec3F64Simd, b: Vec3F64Simd) Vec3F64Simd {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
pub fn f64vec3_simd_kernel(a: Vec3F64Simd, x: Vec3F64Simd, c: Vec3F64Simd) Vec3F64Simd {
|
||||
const mixed = f64vec3_simd_add(f64vec3_simd_sub(f64vec3_simd_add(a, x), c), f64vec3_simd_mul(f64vec3_simd_sub(a, c), c));
|
||||
return @sqrt(@abs(mixed) + @as(Vec3F64Simd, @splat(1.0)));
|
||||
}
|
||||
|
||||
pub fn f64vec4_simd_add(a: Vec4F64Simd, b: Vec4F64Simd) Vec4F64Simd {
|
||||
return a + b;
|
||||
}
|
||||
pub fn f64vec4_simd_mul(a: Vec4F64Simd, b: Vec4F64Simd) Vec4F64Simd {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
pub fn f64vec4_simd_sub(a: Vec4F64Simd, b: Vec4F64Simd) Vec4F64Simd {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
pub fn f64vec4_simd_kernel(a: Vec4F64Simd, x: Vec4F64Simd, c: Vec4F64Simd) Vec4F64Simd {
|
||||
const mixed = f64vec4_simd_add(f64vec4_simd_sub(f64vec4_simd_add(a, x), c), f64vec4_simd_mul(f64vec4_simd_sub(a, c), c));
|
||||
return @sqrt(@abs(mixed) + @as(Vec4F64Simd, @splat(1.0)));
|
||||
}
|
||||
|
||||
pub fn bench_f64vec3F64Simd(io: std.Io) void {
|
||||
var rng: std.Random.DefaultPrng = .init(42);
|
||||
var prng = rng.random();
|
||||
|
||||
var a: Vec3F64Simd = .{ 0, 0, 0 };
|
||||
const x: Vec3F64Simd = .{ prng.float(f64), prng.float(f64), prng.float(f64) };
|
||||
const c: Vec3F64Simd = .{ prng.float(f64), prng.float(f64), prng.float(f64) };
|
||||
|
||||
var i: usize = 0;
|
||||
const start = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
while (i < 100_000_000) : (i += 1) {
|
||||
a = f64vec3_simd_kernel(a, x, c);
|
||||
}
|
||||
const end = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
|
||||
std.debug.print("Vec3F64Simd took {} with final answer {}\n", .{ end - start, a });
|
||||
}
|
||||
|
||||
pub fn bench_f64vec4F64Simd(io: std.Io) void {
|
||||
var rng: std.Random.DefaultPrng = .init(42);
|
||||
var prng = rng.random();
|
||||
var a: Vec4F64Simd = .{ 0, 0, 0, 0 };
|
||||
const x: Vec4F64Simd = .{ prng.float(f64), prng.float(f64), prng.float(f64), prng.float(f64) };
|
||||
const c: Vec4F64Simd = .{ prng.float(f64), prng.float(f64), prng.float(f64), prng.float(f64) };
|
||||
|
||||
var i: usize = 0;
|
||||
const start = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
while (i < 100_000_000) : (i += 1) {
|
||||
a = f64vec4_simd_kernel(a, x, c);
|
||||
}
|
||||
const end = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
|
||||
std.debug.print("Vec4F64Simd took {} with final answer {}\n", .{ end - start, a });
|
||||
}
|
||||
|
||||
pub fn bench_f64vec3F64Struct(io: std.Io) void {
|
||||
var rng: std.Random.DefaultPrng = .init(42);
|
||||
var prng = rng.random();
|
||||
var a: Vec3F64Struct = .{ .x = 0, .y = 0, .z = 0 };
|
||||
const x: Vec3F64Struct = .{ .x = prng.float(f64), .y = prng.float(f64), .z = prng.float(f64) };
|
||||
const c: Vec3F64Struct = .{ .x = prng.float(f64), .y = prng.float(f64), .z = prng.float(f64) };
|
||||
|
||||
var i: usize = 0;
|
||||
const start = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
while (i < 100_000_000) : (i += 1) {
|
||||
a = f64vec3_struct_kernel(a, x, c);
|
||||
}
|
||||
const end = std.Io.Clock.real.now(io).toMicroseconds();
|
||||
|
||||
std.debug.print("Vec3F64Struct took {} with final answer {}\n", .{ end - start, a });
|
||||
}
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
std.debug.print("Suggested lanes for f32: {}\n", .{std.simd.suggestVectorLength(f32).?});
|
||||
std.debug.print("Suggested lanes for f64: {}\n\n", .{std.simd.suggestVectorLength(f64).?});
|
||||
|
||||
bench_vec3F32Simd(init.io);
|
||||
bench_vec4F32Simd(init.io);
|
||||
bench_vec3F32Struct(init.io);
|
||||
bench_f64vec3F64Simd(init.io);
|
||||
bench_f64vec4F64Simd(init.io);
|
||||
bench_f64vec3F64Struct(init.io);
|
||||
}
|
||||
|
||||
test "main" {
|
||||
//_ = @import("./f64vec3/src/vec3.zig");
|
||||
}
|
||||
295
src/types/vec3.zig
Normal file
295
src/types/vec3.zig
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
const std = @import("std");
|
||||
|
||||
const Vec3F32 = struct {
|
||||
data: @Vector(4, f32),
|
||||
|
||||
pub fn init(_x: f32, _y: f32, _z: f32) Vec3F32 {
|
||||
return .{ .data = .{ _x, _y, _z, 0 } };
|
||||
}
|
||||
|
||||
pub fn x(self: Vec3F32) f32 {
|
||||
return self.data[0];
|
||||
}
|
||||
|
||||
pub fn y(self: Vec3F32) f32 {
|
||||
return self.data[1];
|
||||
}
|
||||
|
||||
pub fn z(self: Vec3F32) f32 {
|
||||
return self.data[2];
|
||||
}
|
||||
};
|
||||
|
||||
pub fn vec3Add(a: Vec3F32, b: Vec3F32) Vec3F32 {
|
||||
return .{ .data = a.data + b.data };
|
||||
}
|
||||
|
||||
pub fn vec3Sub(a: Vec3F32, b: Vec3F32) Vec3F32 {
|
||||
return .{ .data = a.data - b.data };
|
||||
}
|
||||
|
||||
pub fn vec3Dot(a: Vec3F32, b: Vec3F32) f32 {
|
||||
return @reduce(.Add, a.data * b.data);
|
||||
}
|
||||
|
||||
pub fn vec3Cross(a: Vec3F32, b: Vec3F32) Vec3F32 {
|
||||
const x = a.y() * b.z() - a.z() * b.y();
|
||||
const y = a.z() * b.x() - a.x() * b.z();
|
||||
const z = a.x() * b.y() - a.y() * b.x();
|
||||
return .init(x, y, z);
|
||||
}
|
||||
|
||||
const Mat3F32 = struct {
|
||||
row1: Vec3F32,
|
||||
row2: Vec3F32,
|
||||
row3: Vec3F32,
|
||||
};
|
||||
|
||||
pub fn mat3Add(a: Mat3F32, b: Mat3F32) Mat3F32 {
|
||||
return .{
|
||||
.row1 = vec3Add(a.row1, b.row1),
|
||||
.row2 = vec3Add(a.row2, b.row2),
|
||||
.row3 = vec3Add(a.row3, b.row3),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mat3Sub(a: Mat3F32, b: Mat3F32) Mat3F32 {
|
||||
return .{
|
||||
.row1 = vec3Sub(a.row1, b.row1),
|
||||
.row2 = vec3Sub(a.row2, b.row2),
|
||||
.row3 = vec3Sub(a.row3, b.row3),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mat3Mul(a: Mat3F32, b: Mat3F32) Mat3F32 {
|
||||
const c_row1: Vec3F32 = .init(
|
||||
a.row1.x() * b.row1.x() + a.row1.y() * b.row2.x() + a.row1.z() * b.row3.x(),
|
||||
a.row1.x() * b.row1.y() + a.row1.y() * b.row2.y() + a.row1.z() * b.row3.y(),
|
||||
a.row1.x() * b.row1.z() + a.row1.y() * b.row2.z() + a.row1.z() * b.row3.z(),
|
||||
);
|
||||
|
||||
const c_row2: Vec3F32 = .init(
|
||||
a.row2.x() * b.row1.x() + a.row2.y() * b.row2.x() + a.row2.z() * b.row3.x(),
|
||||
a.row2.x() * b.row1.y() + a.row2.y() * b.row2.y() + a.row2.z() * b.row3.y(),
|
||||
a.row2.x() * b.row1.z() + a.row2.y() * b.row2.z() + a.row2.z() * b.row3.z(),
|
||||
);
|
||||
|
||||
const c_row3: Vec3F32 = .init(
|
||||
a.row3.x() * b.row1.x() + a.row3.y() * b.row2.x() + a.row3.z() * b.row3.x(),
|
||||
a.row3.x() * b.row1.y() + a.row3.y() * b.row2.y() + a.row3.z() * b.row3.y(),
|
||||
a.row3.x() * b.row1.z() + a.row3.y() * b.row2.z() + a.row3.z() * b.row3.z(),
|
||||
);
|
||||
|
||||
return .{ .row1 = c_row1, .row2 = c_row2, .row3 = c_row3 };
|
||||
}
|
||||
|
||||
pub fn vec3MulMat3(a: Mat3F32, b: Vec3F32) Vec3F32 {
|
||||
return .init(
|
||||
b.x() * a.row1.x() + b.y() * a.row1.y() + b.z() * a.row1.z(),
|
||||
b.x() * a.row2.x() + b.y() * a.row2.y() + b.z() * a.row2.z(),
|
||||
b.x() * a.row3.x() + b.y() * a.row3.y() + b.z() * a.row3.z(),
|
||||
);
|
||||
}
|
||||
|
||||
// Uses the Quaternion definition of q = w + xi + yj + zk
|
||||
// and with i^2 = j^2 = k^2 = ijk = -1
|
||||
// I grabbed a lot of this math from https://imadrahmoune.com/rotations-with-quaternions/
|
||||
const QuatF32 = struct {
|
||||
data: @Vector(4, f32),
|
||||
pub fn init(_x: f32, _y: f32, _z: f32, _w: f32) QuatF32 {
|
||||
return .{ .data = .{ _x, _y, _z, _w } };
|
||||
}
|
||||
pub fn x(self: QuatF32) f32 {
|
||||
return self.data[0];
|
||||
}
|
||||
|
||||
pub fn y(self: QuatF32) f32 {
|
||||
return self.data[1];
|
||||
}
|
||||
|
||||
pub fn z(self: QuatF32) f32 {
|
||||
return self.data[2];
|
||||
}
|
||||
pub fn w(self: QuatF32) f32 {
|
||||
return self.data[3];
|
||||
}
|
||||
pub fn mag(q: QuatF32) f32 {
|
||||
return std.math.sqrt(@reduce(.Add, q.data * q.data));
|
||||
}
|
||||
|
||||
pub fn normalized(q: QuatF32) QuatF32 {
|
||||
const magnitude = q.mag();
|
||||
return .{ .data = q.data / @as(@Vector(4, f32), @splat(magnitude)) };
|
||||
}
|
||||
};
|
||||
|
||||
//pub fn yawPitchRollToQuat(comptime T: comptime_float, yaw: T, pitch: T, roll: T) Quat(T) {
|
||||
// const cx = @cos(roll);
|
||||
//}
|
||||
|
||||
pub fn quatMul(a: QuatF32, b: QuatF32) QuatF32 {
|
||||
return .init(
|
||||
a.w() * b.x() + a.x() * b.w() + a.y() * b.z() - a.z() * b.y(),
|
||||
a.w() * b.y() - a.x() * b.z() + a.y() * b.w() + a.z() * b.x(),
|
||||
a.w() * b.z() + a.x() * b.y() - a.y() * b.x() + a.z() * b.w(),
|
||||
a.w() * b.w() - a.x() * b.x() - a.y() * b.y() - a.z() * b.z(),
|
||||
);
|
||||
}
|
||||
|
||||
test "vec3Add adds properly" {
|
||||
const a = Vec3F32.init(1, 2, 3);
|
||||
const b = Vec3F32.init(3, 1, 0);
|
||||
const c = vec3Add(a, b);
|
||||
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, c.x(), 4, 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, c.y(), 3, 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, c.z(), 3, 1e-7));
|
||||
}
|
||||
test "vec3Sub subs properly" {
|
||||
const a = Vec3F32.init(1, 2, 3);
|
||||
const b = Vec3F32.init(3, 1, 0);
|
||||
const c = vec3Sub(a, b);
|
||||
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, c.x(), -2, 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, c.y(), 1, 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, c.z(), 3, 1e-7));
|
||||
}
|
||||
test "vec3Dot dots properly" {
|
||||
const a = Vec3F32.init(1, 2, 3);
|
||||
const b = Vec3F32.init(3, 1, 0);
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, vec3Dot(a, b), 5, 1e-7));
|
||||
}
|
||||
test "vec3Cross crosses properly" {
|
||||
const a = Vec3F32.init(1, 2, 3);
|
||||
const b = Vec3F32.init(3, 1, 0);
|
||||
|
||||
const c = vec3Cross(a, b);
|
||||
|
||||
try std.testing.expect(c.x() == -3);
|
||||
try std.testing.expect(c.y() == 9);
|
||||
try std.testing.expect(c.z() == -5);
|
||||
}
|
||||
|
||||
test "Mat3 add works" {
|
||||
const a: Mat3F32 = .{
|
||||
.row1 = Vec3F32.init(1, 2, 3),
|
||||
.row2 = Vec3F32.init(0, 1, 5),
|
||||
.row3 = Vec3F32.init(0, 0, 9),
|
||||
};
|
||||
const b: Mat3F32 = .{
|
||||
.row1 = Vec3F32.init(0, 1, 0),
|
||||
.row2 = Vec3F32.init(0, 1, 1),
|
||||
.row3 = Vec3F32.init(0, 0, 1),
|
||||
};
|
||||
|
||||
const c = mat3Add(a, b);
|
||||
|
||||
try std.testing.expect(c.row1.x() == 1);
|
||||
try std.testing.expect(c.row1.y() == 3);
|
||||
try std.testing.expect(c.row1.z() == 3);
|
||||
try std.testing.expect(c.row2.x() == 0);
|
||||
try std.testing.expect(c.row2.y() == 2);
|
||||
try std.testing.expect(c.row2.z() == 6);
|
||||
try std.testing.expect(c.row3.x() == 0);
|
||||
try std.testing.expect(c.row3.y() == 0);
|
||||
try std.testing.expect(c.row3.z() == 10);
|
||||
}
|
||||
|
||||
test "Mat3 sub works" {
|
||||
const a: Mat3F32 = .{
|
||||
.row1 = Vec3F32.init(1, 2, 3),
|
||||
.row2 = Vec3F32.init(0, 1, 5),
|
||||
.row3 = Vec3F32.init(0, 0, 9),
|
||||
};
|
||||
const b: Mat3F32 = .{
|
||||
.row1 = Vec3F32.init(0, 1, 0),
|
||||
.row2 = Vec3F32.init(0, 1, 1),
|
||||
.row3 = Vec3F32.init(0, 0, 1),
|
||||
};
|
||||
|
||||
const c = mat3Sub(a, b);
|
||||
|
||||
try std.testing.expect(c.row1.x() == 1);
|
||||
try std.testing.expect(c.row1.y() == 1);
|
||||
try std.testing.expect(c.row1.z() == 3);
|
||||
try std.testing.expect(c.row2.x() == 0);
|
||||
try std.testing.expect(c.row2.y() == 0);
|
||||
try std.testing.expect(c.row2.z() == 4);
|
||||
try std.testing.expect(c.row3.x() == 0);
|
||||
try std.testing.expect(c.row3.y() == 0);
|
||||
try std.testing.expect(c.row3.z() == 8);
|
||||
}
|
||||
|
||||
test "Mat3 mul works" {
|
||||
const a: Mat3F32 = .{
|
||||
.row1 = Vec3F32.init(1, 2, 3),
|
||||
.row2 = Vec3F32.init(0, 1, 5),
|
||||
.row3 = Vec3F32.init(0, 0, 9),
|
||||
};
|
||||
const b: Mat3F32 = .{
|
||||
.row1 = Vec3F32.init(0, 1, 0),
|
||||
.row2 = Vec3F32.init(0, 1, 1),
|
||||
.row3 = Vec3F32.init(0, 0, 1),
|
||||
};
|
||||
|
||||
const c = mat3Mul(a, b);
|
||||
|
||||
try std.testing.expect(c.row1.x() == 0);
|
||||
try std.testing.expect(c.row1.y() == 3);
|
||||
try std.testing.expect(c.row1.z() == 5);
|
||||
try std.testing.expect(c.row2.x() == 0);
|
||||
try std.testing.expect(c.row2.y() == 1);
|
||||
try std.testing.expect(c.row2.z() == 6);
|
||||
try std.testing.expect(c.row3.x() == 0);
|
||||
try std.testing.expect(c.row3.y() == 0);
|
||||
try std.testing.expect(c.row3.z() == 9);
|
||||
}
|
||||
|
||||
test "vec3 mul mat3 works" {
|
||||
const b: Mat3F32 = .{
|
||||
.row1 = Vec3F32.init(0, 1, 0),
|
||||
.row2 = Vec3F32.init(0, 1, 1),
|
||||
.row3 = Vec3F32.init(0, 0, 1),
|
||||
};
|
||||
const a = Vec3F32.init(1, 2, 3);
|
||||
|
||||
const c = vec3MulMat3(b, a);
|
||||
|
||||
try std.testing.expect(c.x() == 2);
|
||||
try std.testing.expect(c.y() == 5);
|
||||
try std.testing.expect(c.z() == 3);
|
||||
}
|
||||
|
||||
test "quat magnitude" {
|
||||
const q: QuatF32 = .init(1.0, 2.0, 3.0, 4.0);
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, q.mag(), std.math.sqrt(30.0), 1e-7));
|
||||
}
|
||||
|
||||
test "quat normalized" {
|
||||
const q: QuatF32 = .init(1.0, 2.0, 3.0, 4.0);
|
||||
const expected: QuatF32 = .init(
|
||||
1.0 / std.math.sqrt(30.0),
|
||||
2.0 / std.math.sqrt(30.0),
|
||||
3.0 / std.math.sqrt(30.0),
|
||||
4.0 / std.math.sqrt(30.0),
|
||||
);
|
||||
|
||||
const normalized = q.normalized();
|
||||
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.x(), expected.x(), 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.y(), expected.y(), 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.z(), expected.z(), 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.w(), expected.w(), 1e-7));
|
||||
}
|
||||
|
||||
test "quat mul" {
|
||||
const a: QuatF32 = .init(2, 3, 4, 1);
|
||||
const b: QuatF32 = .init(0, 1, 0, 1);
|
||||
|
||||
const c = quatMul(a, b);
|
||||
|
||||
try std.testing.expect(c.w() == -2);
|
||||
try std.testing.expect(c.x() == -2);
|
||||
try std.testing.expect(c.y() == 4);
|
||||
try std.testing.expect(c.z() == 6);
|
||||
}
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn Vec3(comptime T: type) type {
|
||||
return struct { x: T, y: T, z: T };
|
||||
}
|
||||
|
||||
pub fn vec3Add(comptime T: type, a: Vec3(T), b: Vec3(T)) Vec3(T) {
|
||||
return .{
|
||||
.x = a.x + b.x,
|
||||
.y = a.y + b.y,
|
||||
.z = a.z + b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn vec3Sub(comptime T: type, a: Vec3(T), b: Vec3(T)) Vec3(T) {
|
||||
return .{
|
||||
.x = a.x - b.x,
|
||||
.y = a.y - b.y,
|
||||
.z = a.z - b.z,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn vec3Dot(comptime T: type, a: Vec3(T), b: Vec3(T)) T {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
pub fn vec3Cross(comptime T: type, a: Vec3(T), b: Vec3(T)) Vec3(T) {
|
||||
const x = a.y * b.z - a.z * b.y;
|
||||
const y = a.z * b.x - a.x * b.z;
|
||||
const z = a.x * b.y - a.y * b.x;
|
||||
return .{ .x = x, .y = y, .z = z };
|
||||
}
|
||||
|
||||
pub fn Mat3(comptime T: type) type {
|
||||
return struct {
|
||||
row1: Vec3(T),
|
||||
row2: Vec3(T),
|
||||
row3: Vec3(T),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mat3Add(comptime T: type, a: Mat3(T), b: Mat3(T)) Mat3(T) {
|
||||
return .{
|
||||
.row1 = vec3Add(T, a.row1, b.row1),
|
||||
.row2 = vec3Add(T, a.row2, b.row2),
|
||||
.row3 = vec3Add(T, a.row3, b.row3),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mat3Sub(comptime T: type, a: Mat3(T), b: Mat3(T)) Mat3(T) {
|
||||
return .{
|
||||
.row1 = vec3Sub(T, a.row1, b.row1),
|
||||
.row2 = vec3Sub(T, a.row2, b.row2),
|
||||
.row3 = vec3Sub(T, a.row3, b.row3),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn mat3Mul(comptime T: type, a: Mat3(T), b: Mat3(T)) Mat3(T) {
|
||||
const c_row1: Vec3(T) = .{
|
||||
.x = a.row1.x * b.row1.x + a.row1.y * b.row2.x + a.row1.z * b.row3.x,
|
||||
.y = a.row1.x * b.row1.y + a.row1.y * b.row2.y + a.row1.z * b.row3.y,
|
||||
.z = a.row1.x * b.row1.z + a.row1.y * b.row2.z + a.row1.z * b.row3.z,
|
||||
};
|
||||
|
||||
const c_row2: Vec3(T) = .{
|
||||
.x = a.row2.x * b.row1.x + a.row2.y * b.row2.x + a.row2.z * b.row3.x,
|
||||
.y = a.row2.x * b.row1.y + a.row2.y * b.row2.y + a.row2.z * b.row3.y,
|
||||
.z = a.row2.x * b.row1.z + a.row2.y * b.row2.z + a.row2.z * b.row3.z,
|
||||
};
|
||||
|
||||
const c_row3: Vec3(T) = .{
|
||||
.x = a.row3.x * b.row1.x + a.row3.y * b.row2.x + a.row3.z * b.row3.x,
|
||||
.y = a.row3.x * b.row1.y + a.row3.y * b.row2.y + a.row3.z * b.row3.y,
|
||||
.z = a.row3.x * b.row1.z + a.row3.y * b.row2.z + a.row3.z * b.row3.z,
|
||||
};
|
||||
|
||||
return .{ .row1 = c_row1, .row2 = c_row2, .row3 = c_row3 };
|
||||
}
|
||||
|
||||
pub fn vec3MulMat3(comptime T: type, a: Vec3(T), b: Mat3(T)) Vec3(T) {
|
||||
return .{
|
||||
.x = a.x * b.row1.x + a.y * b.row2.x + a.z * b.row3.x,
|
||||
.y = a.x * b.row1.y + a.y * b.row2.y + a.z * b.row3.y,
|
||||
.z = a.x * b.row1.z + a.y * b.row2.z + a.z * b.row3.z,
|
||||
};
|
||||
}
|
||||
|
||||
// Uses the Quaternion definition of q = w + xi + yj + zk
|
||||
// and with i^2 = j^2 = k^2 = ijk = -1
|
||||
// I grabbed a lot of this math from https://imadrahmoune.com/rotations-with-quaternions/
|
||||
pub fn Quat(comptime T: type) type {
|
||||
return struct {
|
||||
w: T,
|
||||
x: T,
|
||||
y: T,
|
||||
z: T,
|
||||
|
||||
pub fn mag(q: Quat(T)) T {
|
||||
return std.math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
|
||||
}
|
||||
|
||||
pub fn normalized(q: Quat(T)) Quat(T) {
|
||||
const magnitude = q.mag();
|
||||
return .{
|
||||
.x = q.x / magnitude,
|
||||
.y = q.y / magnitude,
|
||||
.z = q.z / magnitude,
|
||||
.w = q.w / magnitude,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn quatMul(comptime T: type, a: Quat(T), b: Quat(T)) Quat(T) {
|
||||
return .{
|
||||
.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
|
||||
.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
||||
.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
||||
.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
|
||||
};
|
||||
}
|
||||
|
||||
test "vec3Add adds properly" {
|
||||
const a: Vec3(i8) = .{ .x = 1, .y = 2, .z = 3 };
|
||||
const b: Vec3(i8) = .{ .x = 3, .y = 1, .z = 0 };
|
||||
const c = vec3Add(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.x == 4);
|
||||
try std.testing.expect(c.y == 3);
|
||||
try std.testing.expect(c.z == 3);
|
||||
}
|
||||
test "vec3Sub subs properly" {
|
||||
const a: Vec3(i8) = .{ .x = 1, .y = 2, .z = 3 };
|
||||
const b: Vec3(i8) = .{ .x = 3, .y = 1, .z = 0 };
|
||||
const c = vec3Sub(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.x == -2);
|
||||
try std.testing.expect(c.y == 1);
|
||||
try std.testing.expect(c.z == 3);
|
||||
}
|
||||
test "vec3Dot dots properly" {
|
||||
const a: Vec3(i8) = .{ .x = 1, .y = 2, .z = 3 };
|
||||
const b: Vec3(i8) = .{ .x = 3, .y = 1, .z = 0 };
|
||||
try std.testing.expect(vec3Dot(i8, a, b) == 5);
|
||||
}
|
||||
test "vec3Cross crosses properly" {
|
||||
const a: Vec3(i8) = .{ .x = 1, .y = 2, .z = 3 };
|
||||
const b: Vec3(i8) = .{ .x = 3, .y = 1, .z = 0 };
|
||||
|
||||
const c = vec3Cross(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.x == -3);
|
||||
try std.testing.expect(c.y == 9);
|
||||
try std.testing.expect(c.z == -5);
|
||||
}
|
||||
|
||||
test "Mat3 add works" {
|
||||
const a: Mat3(i8) = .{
|
||||
.row1 = .{ .x = 1, .y = 2, .z = 3 },
|
||||
.row2 = .{ .x = 0, .y = 1, .z = 5 },
|
||||
.row3 = .{ .x = 0, .y = 0, .z = 9 },
|
||||
};
|
||||
const b: Mat3(i8) = .{
|
||||
.row1 = .{ .x = 0, .y = 1, .z = 0 },
|
||||
.row2 = .{ .x = 0, .y = 1, .z = 1 },
|
||||
.row3 = .{ .x = 0, .y = 0, .z = 1 },
|
||||
};
|
||||
|
||||
const c = mat3Add(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.row1.x == 1);
|
||||
try std.testing.expect(c.row1.y == 3);
|
||||
try std.testing.expect(c.row1.z == 3);
|
||||
try std.testing.expect(c.row2.x == 0);
|
||||
try std.testing.expect(c.row2.y == 2);
|
||||
try std.testing.expect(c.row2.z == 6);
|
||||
try std.testing.expect(c.row3.x == 0);
|
||||
try std.testing.expect(c.row3.y == 0);
|
||||
try std.testing.expect(c.row3.z == 10);
|
||||
}
|
||||
|
||||
test "Mat3 sub works" {
|
||||
const a: Mat3(i8) = .{
|
||||
.row1 = .{ .x = 1, .y = 2, .z = 3 },
|
||||
.row2 = .{ .x = 0, .y = 1, .z = 5 },
|
||||
.row3 = .{ .x = 0, .y = 0, .z = 9 },
|
||||
};
|
||||
const b: Mat3(i8) = .{
|
||||
.row1 = .{ .x = 0, .y = 1, .z = 0 },
|
||||
.row2 = .{ .x = 0, .y = 1, .z = 1 },
|
||||
.row3 = .{ .x = 0, .y = 0, .z = 1 },
|
||||
};
|
||||
|
||||
const c = mat3Sub(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.row1.x == 1);
|
||||
try std.testing.expect(c.row1.y == 1);
|
||||
try std.testing.expect(c.row1.z == 3);
|
||||
try std.testing.expect(c.row2.x == 0);
|
||||
try std.testing.expect(c.row2.y == 0);
|
||||
try std.testing.expect(c.row2.z == 4);
|
||||
try std.testing.expect(c.row3.x == 0);
|
||||
try std.testing.expect(c.row3.y == 0);
|
||||
try std.testing.expect(c.row3.z == 8);
|
||||
}
|
||||
|
||||
test "Mat3 mul works" {
|
||||
const a: Mat3(i8) = .{
|
||||
.row1 = .{ .x = 1, .y = 2, .z = 3 },
|
||||
.row2 = .{ .x = 0, .y = 1, .z = 5 },
|
||||
.row3 = .{ .x = 0, .y = 0, .z = 9 },
|
||||
};
|
||||
const b: Mat3(i8) = .{
|
||||
.row1 = .{ .x = 0, .y = 1, .z = 0 },
|
||||
.row2 = .{ .x = 0, .y = 1, .z = 1 },
|
||||
.row3 = .{ .x = 0, .y = 0, .z = 1 },
|
||||
};
|
||||
|
||||
const c = mat3Mul(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.row1.x == 0);
|
||||
try std.testing.expect(c.row1.y == 3);
|
||||
try std.testing.expect(c.row1.z == 5);
|
||||
try std.testing.expect(c.row2.x == 0);
|
||||
try std.testing.expect(c.row2.y == 1);
|
||||
try std.testing.expect(c.row2.z == 6);
|
||||
try std.testing.expect(c.row3.x == 0);
|
||||
try std.testing.expect(c.row3.y == 0);
|
||||
try std.testing.expect(c.row3.z == 9);
|
||||
}
|
||||
|
||||
test "vec3 mul mat3 works" {
|
||||
const a: Vec3(i8) = .{ .x = 1, .y = 2, .z = 3 };
|
||||
|
||||
const b: Mat3(i8) = .{
|
||||
.row1 = .{ .x = 0, .y = 1, .z = 0 },
|
||||
.row2 = .{ .x = 0, .y = 1, .z = 1 },
|
||||
.row3 = .{ .x = 0, .y = 0, .z = 1 },
|
||||
};
|
||||
|
||||
const c = vec3MulMat3(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.x == 0);
|
||||
try std.testing.expect(c.y == 3);
|
||||
try std.testing.expect(c.z == 5);
|
||||
}
|
||||
|
||||
test "quat magnitude" {
|
||||
const q: Quat(f32) = .{ .x = 1.0, .y = 2.0, .z = 3.0, .w = 4.0 };
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, q.mag(), std.math.sqrt(30.0), 1e-7));
|
||||
}
|
||||
|
||||
test "quat normalized" {
|
||||
const q: Quat(f32) = .{ .x = 1.0, .y = 2.0, .z = 3.0, .w = 4.0 };
|
||||
const expected: Quat(f32) = .{
|
||||
.x = 1.0 / std.math.sqrt(30.0),
|
||||
.y = 2.0 / std.math.sqrt(30.0),
|
||||
.z = 3.0 / std.math.sqrt(30.0),
|
||||
.w = 4.0 / std.math.sqrt(30.0),
|
||||
};
|
||||
|
||||
const normalized = q.normalized();
|
||||
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.x, expected.x, 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.y, expected.y, 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.z, expected.z, 1e-7));
|
||||
try std.testing.expect(std.math.approxEqAbs(f32, normalized.w, expected.w, 1e-7));
|
||||
}
|
||||
|
||||
test "quat mul" {
|
||||
const a: Quat(i8) = .{ .w = 1, .x = 2, .y = 3, .z = 4 };
|
||||
const b: Quat(i8) = .{ .w = 1, .x = 0, .y = 1, .z = 0 };
|
||||
|
||||
const c = quatMul(i8, a, b);
|
||||
|
||||
try std.testing.expect(c.w == -2);
|
||||
try std.testing.expect(c.x == -2);
|
||||
try std.testing.expect(c.y == 4);
|
||||
try std.testing.expect(c.z == 6);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue