This commit is contained in:
2025-11-12 01:56:08 +01:00
parent c11a384b27
commit 2e8cfd36fd
6 changed files with 597 additions and 9 deletions

259
src/math/Matrix4x4.zig Normal file
View File

@@ -0,0 +1,259 @@
const Vector3 = @import("Vector3.zig").Vector3;
const Vector4 = @import("Vector4.zig").Vector4;
const Quaternion = @import("Quaternion.zig").Quaternion;
pub const Matrix4x4 = extern struct {
i: Vector4,
j: Vector4,
k: Vector4,
t: Vector4,
pub const identity = Matrix4x4.init(
// zig fmt: off
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
// zig fmt: on
);
pub inline fn init(
// zig fmt: off
ix: f32, iy: f32, iz: f32, iw: f32,
jx: f32, jy: f32, jz: f32, jw: f32,
kx: f32, ky: f32, kz: f32, kw: f32,
tx: f32, ty: f32, tz: f32, tw: f32,
// zig fmt: on
) Matrix4x4 {
return .{
.i = .{ .vector = .{ ix, iy, iz, iw } },
.j = .{ .vector = .{ jx, jy, jz, jw } },
.k = .{ .vector = .{ kx, ky, kz, kw } },
.t = .{ .vector = .{ tx, ty, tz, tw } },
};
}
pub inline fn initVector(i: Vector4, j: Vector4, k: Vector4, t: Vector4) Matrix4x4 {
return .{ .i = i, .j = j, .k = k, .t = t };
}
pub inline fn initTranslation(translation: Vector3) Matrix4x4 {
return .{
.i = .{ .vector = .{ 1, 0, 0, 0 } },
.j = .{ .vector = .{ 0, 1, 0, 0 } },
.k = .{ .vector = .{ 0, 0, 1, 0 } },
.t = .{ .vector = translation.vector ++ .{1} },
};
}
pub inline fn initRotation(rotation: Quaternion) Matrix4x4 {
const xx = rotation.getX() * rotation.getX();
const xy = rotation.getX() * rotation.getY();
const xz = rotation.getX() * rotation.getZ();
const xw = rotation.getX() * rotation.getW();
const yy = rotation.getY() * rotation.getY();
const yz = rotation.getY() * rotation.getZ();
const yw = rotation.getY() * rotation.getW();
const zz = rotation.getZ() * rotation.getZ();
const zw = rotation.getZ() * rotation.getW();
return .{
.i = .{ .vector = .{ 1 - 2 * (yy + zz), 2 * (xy + zw), 2 * (xz - yw), 0 } },
.j = .{ .vector = .{ 2 * (xy - zw), 1 - 2 * (xx + zz), 2 * (yz + xw), 0 } },
.k = .{ .vector = .{ 2 * (xz + yw), 2 * (yz - xw), 1 - 2 * (xx + yy), 0 } },
.t = .{ .vector = .{ 0, 0, 0, 1 } },
};
}
pub inline fn initScale(scale: Vector3) Matrix4x4 {
return .{
.i = .{ .vector = .{ scale.getX(), 0, 0, 0 } },
.j = .{ .vector = .{ 0, scale.getY(), 0, 0 } },
.k = .{ .vector = .{ 0, 0, scale.getZ(), 0 } },
.t = .{ .vector = .{ 0, 0, 0, 1 } },
};
}
pub inline fn initTranslationRotationScale(translation: Vector3, rotation: Quaternion, scale: Vector3) Matrix4x4 {
const xx = rotation.getX() * rotation.getX();
const xy = rotation.getX() * rotation.getY();
const xz = rotation.getX() * rotation.getZ();
const xw = rotation.getX() * rotation.getW();
const yy = rotation.getY() * rotation.getY();
const yz = rotation.getY() * rotation.getZ();
const yw = rotation.getY() * rotation.getW();
const zz = rotation.getZ() * rotation.getZ();
const zw = rotation.getZ() * rotation.getW();
const scale_x: Vector4.Vector = @splat(scale.getX());
const scale_y: Vector4.Vector = @splat(scale.getY());
const scale_z: Vector4.Vector = @splat(scale.getZ());
const rotation_i: Vector4.Vector = .{ (1 - 2 * (yy + zz)), 2 * (xy + zw), 2 * (xz - yw), 0 };
const rotation_j: Vector4.Vector = .{ 2 * (xy - zw), (1 - 2 * (xx + zz)), 2 * (yz + xw), 0 };
const rotation_k: Vector4.Vector = .{ 2 * (xz + yw), 2 * (yz - xw), (1 - 2 * (xx + yy)), 0 };
return .{
.i = .{ .vector = scale_x * rotation_i },
.j = .{ .vector = scale_y * rotation_j },
.k = .{ .vector = scale_z * rotation_k },
.t = .{ .vector = translation.vector ++ .{1} },
};
}
pub inline fn add(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .{
.i = .{ .vector = self.i.vector + other.i.vector },
.j = .{ .vector = self.j.vector + other.j.vector },
.k = .{ .vector = self.k.vector + other.k.vector },
.t = .{ .vector = self.t.vector + other.t.vector },
};
}
pub inline fn sub(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .{
.i = .{ .vector = self.i.vector - other.i.vector },
.j = .{ .vector = self.j.vector - other.j.vector },
.k = .{ .vector = self.k.vector - other.k.vector },
.t = .{ .vector = self.t.vector - other.t.vector },
};
}
pub inline fn mulScalar(self: Matrix4x4, scalar: f32) Matrix4x4 {
const scalar_vector: Vector4.Vector = @splat(scalar);
return .{
.i = .{ .vector = self.i.vector * scalar_vector },
.j = .{ .vector = self.j.vector * scalar_vector },
.k = .{ .vector = self.k.vector * scalar_vector },
.t = .{ .vector = self.t.vector * scalar_vector },
};
}
pub inline fn divScalar(self: Matrix4x4, scalar: f32) Matrix4x4 {
const inv_scalar_vector: Vector4.Vector = @splat(1 / scalar);
return .{
.i = .{ .vector = self.i * inv_scalar_vector },
.j = .{ .vector = self.j * inv_scalar_vector },
.k = .{ .vector = self.k * inv_scalar_vector },
.t = .{ .vector = self.t * inv_scalar_vector },
};
}
pub inline fn negate(self: Matrix4x4) Matrix4x4 {
return .{
.i = .{ .vector = -self.i.vector },
.j = .{ .vector = -self.j.vector },
.k = .{ .vector = -self.k.vector },
.t = .{ .vector = -self.t.vector },
};
}
pub inline fn mulMatrix(self: Matrix4x4, other: Matrix4x4) Matrix4x4 {
return .{
.i = self.i.mulScalar(other.i.getX())
.add(self.j.mulScalar(other.i.getY()))
.add(self.k.mulScalar(other.i.getZ()))
.add(self.t.mulScalar(other.i.getW())),
.j = self.i.mulScalar(other.j.getX())
.add(self.j.mulScalar(other.j.getY()))
.add(self.k.mulScalar(other.j.getZ()))
.add(self.t.mulScalar(other.j.getW())),
.k = self.i.mulScalar(other.k.getX())
.add(self.j.mulScalar(other.k.getY()))
.add(self.k.mulScalar(other.k.getZ()))
.add(self.t.mulScalar(other.k.getW())),
.t = self.i.mulScalar(other.t.getX())
.add(self.j.mulScalar(other.t.getY()))
.add(self.k.mulScalar(other.t.getZ()))
.add(self.t.mulScalar(other.t.getW())),
};
}
pub inline fn inverseAffine(self: Matrix4x4) Matrix4x4 {
// zig fmt: off
const det = self.i.getX() * self.j.getY() * self.k.getZ()
+ self.i.getY() * self.j.getZ() * self.k.getX()
+ self.i.getZ() * self.j.getX() * self.k.getY()
- self.i.getX() * self.j.getZ() * self.k.getY()
- self.i.getY() * self.j.getX() * self.k.getZ()
- self.i.getZ() * self.j.getY() * self.k.getX();
// zig fmt: on
const inv_det = 1 / det;
const i = Vector3.init(
self.j.getY() * self.k.getZ() - self.j.getZ() * self.k.getY(),
self.i.getZ() * self.k.getY() - self.i.getY() * self.k.getZ(),
self.i.getY() * self.j.getZ() - self.i.getZ() * self.j.getY(),
).mulScalar(inv_det);
const j = Vector3.init(
self.j.getZ() * self.k.getX() - self.j.getX() * self.k.getZ(),
self.i.getX() * self.k.getZ() - self.i.getZ() * self.k.getX(),
self.i.getZ() * self.j.getX() - self.i.getX() * self.j.getZ(),
).mulScalar(inv_det);
const k = Vector3.init(
self.j.getX() * self.k.getY() - self.j.getY() * self.k.getX(),
self.i.getY() * self.k.getX() - self.i.getX() * self.k.getY(),
self.i.getX() * self.j.getY() - self.i.getY() * self.j.getX(),
).mulScalar(inv_det);
const t = self.i.asVector3().mulScalar(self.t.getX())
.add(self.j.asVector3().mulScalar(self.t.getY()))
.add(self.k.asVector3().mulScalar(self.t.getZ()))
.negate();
return .{
.i = .{ .vector = i ++ .{0} },
.j = .{ .vector = j ++ .{0} },
.k = .{ .vector = k ++ .{0} },
.t = .{ .vector = t ++ .{1} },
};
}
pub inline fn inverseTransposeAffine(self: Matrix4x4) Matrix4x4 {
// zig fmt: off
const det = self.i.getX() * self.j.getY() * self.k.getZ()
+ self.i.getY() * self.j.getZ() * self.k.getX()
+ self.i.getZ() * self.j.getX() * self.k.getY()
- self.i.getX() * self.j.getZ() * self.k.getY()
- self.i.getY() * self.j.getX() * self.k.getZ()
- self.i.getZ() * self.j.getY() * self.k.getX();
// zig fmt: on
const inv_det = 1 / det;
const i = Vector3.init(
self.j.getY() * self.k.getZ() - self.j.getZ() * self.k.getY(),
self.j.getZ() * self.k.getX() - self.j.getX() * self.k.getZ(),
self.j.getX() * self.k.getY() - self.j.getY() * self.k.getX(),
).mulScalar(inv_det);
const j = Vector3.init(
self.i.getZ() * self.k.getY() - self.i.getY() * self.k.getZ(),
self.i.getX() * self.k.getZ() - self.i.getZ() * self.k.getX(),
self.i.getY() * self.k.getX() - self.i.getX() * self.k.getY(),
).mulScalar(inv_det);
const k = Vector3.init(
self.i.getY() * self.j.getZ() - self.i.getZ() * self.j.getY(),
self.i.getZ() * self.j.getX() - self.i.getX() * self.j.getZ(),
self.i.getX() * self.j.getY() - self.i.getY() * self.j.getX(),
).mulScalar(inv_det);
const t = self.i.asVector3().mulScalar(self.t.getX())
.add(self.j.asVector3().mulScalar(self.t.getY()))
.add(self.k.asVector3().mulScalar(self.t.getZ()))
.negate();
return .{
.i = .{ .vector = i ++ .{0} },
.j = .{ .vector = j ++ .{0} },
.k = .{ .vector = k ++ .{0} },
.t = .{ .vector = t ++ .{1} },
};
}
pub inline fn asArray(self: Matrix4x4) [16]f32 {
return @bitCast(self);
}
};

114
src/math/Quaternion.zig Normal file
View File

@@ -0,0 +1,114 @@
const std = @import("std");
pub const Quaternion = extern struct {
vector: Vector,
pub const Vector = @Vector(4, f32);
pub const zero = Quaternion.init(0, 0, 0, 0);
pub const one = Quaternion.init(1, 1, 1, 1);
pub const identity = Quaternion.init(0, 0, 0, 1);
pub inline fn init(x: f32, y: f32, z: f32, w: f32) Quaternion {
return .{ .vector = .{ x, y, z, w } };
}
pub inline fn initRotationXY(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
return .{ .vector = .{ 0, 0, @sin(half_angle_rad), @cos(half_angle_rad) } };
}
pub inline fn initRotationXZ(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
return .{ .vector = .{ 0, -@sin(half_angle_rad), 0, @cos(half_angle_rad) } };
}
pub inline fn initRotationYX(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
return .{ .vector = .{ 0, 0, -@sin(half_angle_rad), @cos(half_angle_rad) } };
}
pub inline fn initRotationYZ(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
return .{ .vector = .{ @sin(half_angle_rad), 0, 0, @cos(half_angle_rad) } };
}
pub inline fn initRotationZX(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
return .{ .vector = .{ 0, @sin(half_angle_rad), 0, @cos(half_angle_rad) } };
}
pub inline fn initRotationZY(angle_rad: f32) Quaternion {
const half_angle_rad = 0.5 * angle_rad;
return .{ .vector = .{ -@sin(half_angle_rad), 0, 0, @cos(half_angle_rad) } };
}
pub inline fn getX(self: Quaternion) f32 {
return self.vector[0];
}
pub inline fn getY(self: Quaternion) f32 {
return self.vector[1];
}
pub inline fn getZ(self: Quaternion) f32 {
return self.vector[2];
}
pub inline fn getW(self: Quaternion) f32 {
return self.vector[3];
}
pub inline fn setX(self: Quaternion, x: f32) Quaternion {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(Vector, self, x_vector, .{ ~@as(i32, 0), 1, 2, 3 }) };
}
pub inline fn setY(self: Quaternion, y: f32) Quaternion {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(Vector, self, y_vector, .{ 0, ~@as(i32, 1), 2, 3 }) };
}
pub inline fn setZ(self: Quaternion, z: f32) Quaternion {
const z_vector: Vector = @splat(z);
return .{ .vector = @shuffle(Vector, self, z_vector, .{ 0, 1, ~@as(i32, 2), 3 }) };
}
pub inline fn setW(self: Quaternion, w: f32) Quaternion {
const w_vector: Vector = @splat(w);
return .{ .vector = @shuffle(Vector, self, w_vector, .{ 0, 1, 2, ~@as(i32, 3) }) };
}
pub inline fn add(self: Quaternion, other: Quaternion) Quaternion {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Quaternion, other: Quaternion) Quaternion {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Quaternion, other: Quaternion) Quaternion {
return .{ .vector = self.vector * other.vector };
}
pub inline fn div(self: Quaternion, other: Quaternion) Quaternion {
return .{ .vector = self.vector / other.vector };
}
pub inline fn mulScalar(self: Quaternion, scalar: f32) Quaternion {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn divScalar(self: Quaternion, scalar: f32) Quaternion {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector / scalar_vector };
}
pub inline fn lerp(self: Quaternion, other: Quaternion, t: f32) Quaternion {
const s = 1.0 - t;
const t_vector: Vector = @splat(t);
const s_vector: Vector = @splat(s);
return .{ .vector = self * t_vector + other * s_vector };
}
};

93
src/math/Vector3.zig Normal file
View File

@@ -0,0 +1,93 @@
const Vector4 = @import("Vector4.zig").Vector4;
pub const Vector3 = extern struct {
vector: Vector,
pub const Vector = @Vector(3, f32);
pub const zero = Vector3.init(0, 0, 0);
pub const one = Vector3.init(1, 1, 1);
pub const unit_x = Vector3.init(1, 0, 0);
pub const unit_y = Vector3.init(0, 1, 0);
pub const unit_z = Vector3.init(0, 0, 1);
pub inline fn init(x: f32, y: f32, z: f32) Vector3 {
return .{ .vector = .{ x, y, z } };
}
pub inline fn getX(self: Vector3) f32 {
return self.vector[0];
}
pub inline fn getY(self: Vector3) f32 {
return self.vector[1];
}
pub inline fn getZ(self: Vector3) f32 {
return self.vector[2];
}
pub inline fn setX(self: Vector3, x: f32) Vector3 {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(Vector, self, x_vector, .{ ~@as(i32, 0), 1, 2 }) };
}
pub inline fn setY(self: Vector3, y: f32) Vector3 {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(Vector, self, y_vector, .{ 0, ~@as(i32, 1), 2 }) };
}
pub inline fn setZ(self: Vector3, z: f32) Vector3 {
const z_vector: Vector = @splat(z);
return .{ .vector = @shuffle(Vector, self, z_vector, .{ 0, 1, ~@as(i32, 2) }) };
}
pub inline fn add(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector * other.vector };
}
pub inline fn div(self: Vector3, other: Vector3) Vector3 {
return .{ .vector = self.vector / other.vector };
}
pub inline fn mulScalar(self: Vector3, scalar: f32) Vector3 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn divScalar(self: Vector3, scalar: f32) Vector3 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector / scalar_vector };
}
pub inline fn negate(self: Vector3) Vector3 {
return .{ .vector = -self.vector };
}
pub inline fn lerp(self: Vector3, other: Vector3, t: f32) Vector3 {
const s = 1.0 - t;
const t_vector: Vector = @splat(t);
const s_vector: Vector = @splat(s);
return .{ .vector = self * t_vector + other * s_vector };
}
pub inline fn swizzle3(self: Vector3, comptime mask: @Vector(3, i32)) Vector3 {
return .{ .vector = @shuffle(Vector, self, undefined, mask) };
}
pub inline fn swizzle4(self: Vector3, comptime mask: @Vector(4, i32)) Vector4 {
return .{ .vector = @shuffle(Vector4.Vector, self, undefined, mask) };
}
pub inline fn asArray(self: Vector3) [3]f32 {
return self.vector;
}
};

107
src/math/Vector4.zig Normal file
View File

@@ -0,0 +1,107 @@
const Vector3 = @import("Vector3.zig").Vector3;
pub const Vector4 = extern struct {
vector: Vector,
pub const Vector = @Vector(4, f32);
pub const zero = Vector4.init(0, 0, 0, 0);
pub const one = Vector4.init(1, 1, 1, 1);
pub const unit_x = Vector4.init(1, 0, 0, 0);
pub const unit_y = Vector4.init(0, 1, 0, 0);
pub const unit_z = Vector4.init(0, 0, 1, 0);
pub const unit_w = Vector4.init(0, 0, 0, 1);
pub inline fn init(x: f32, y: f32, z: f32, w: f32) Vector4 {
return .{ .vector = .{ x, y, z, w } };
}
pub inline fn getX(self: Vector4) f32 {
return self.vector[0];
}
pub inline fn getY(self: Vector4) f32 {
return self.vector[1];
}
pub inline fn getZ(self: Vector4) f32 {
return self.vector[2];
}
pub inline fn getW(self: Vector4) f32 {
return self.vector[3];
}
pub inline fn setX(self: Vector4, x: f32) Vector4 {
const x_vector: Vector = @splat(x);
return .{ .vector = @shuffle(Vector, self, x_vector, .{ ~@as(i32, 0), 1, 2, 3 }) };
}
pub inline fn setY(self: Vector4, y: f32) Vector4 {
const y_vector: Vector = @splat(y);
return .{ .vector = @shuffle(Vector, self, y_vector, .{ 0, ~@as(i32, 1), 2, 3 }) };
}
pub inline fn setZ(self: Vector4, z: f32) Vector4 {
const z_vector: Vector = @splat(z);
return .{ .vector = @shuffle(Vector, self, z_vector, .{ 0, 1, ~@as(i32, 2), 3 }) };
}
pub inline fn setW(self: Vector4, w: f32) Vector4 {
const w_vector: Vector = @splat(w);
return .{ .vector = @shuffle(Vector, self, w_vector, .{ 0, 1, 2, ~@as(i32, 3) }) };
}
pub inline fn add(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector + other.vector };
}
pub inline fn sub(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector - other.vector };
}
pub inline fn mul(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector * other.vector };
}
pub inline fn div(self: Vector4, other: Vector4) Vector4 {
return .{ .vector = self.vector / other.vector };
}
pub inline fn mulScalar(self: Vector4, scalar: f32) Vector4 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector * scalar_vector };
}
pub inline fn divScalar(self: Vector4, scalar: f32) Vector4 {
const scalar_vector: Vector = @splat(scalar);
return .{ .vector = self.vector / scalar_vector };
}
pub inline fn negate(self: Vector4) Vector4 {
return .{ .vector = -self.vector };
}
pub inline fn lerp(self: Vector4, other: Vector4, t: f32) Vector4 {
const s = 1.0 - t;
const t_vector: Vector = @splat(t);
const s_vector: Vector = @splat(s);
return .{ .vector = self * t_vector + other * s_vector };
}
pub inline fn asVector3(self: Vector4) Vector3 {
return .{ .vector = @shuffle(Vector3.Vector, self.vector, undefined, .{ 0, 1, 2 }) };
}
pub inline fn swizzle3(self: Vector4, comptime mask: @Vector(3, i32)) Vector3 {
return .{ .vector = @shuffle(Vector3.Vector, self.vector, undefined, mask) };
}
pub inline fn swizzle4(self: Vector4, comptime mask: @Vector(4, i32)) Vector4 {
return .{ .vector = @shuffle(Vector, self.vector, undefined, mask) };
}
pub inline fn asArray(self: Vector4) [4]f32 {
return self.vector;
}
};