Skip to content

Instantly share code, notes, and snippets.

@radda-ui
Created June 6, 2024 20:21
Show Gist options
  • Save radda-ui/9025e80dcd73688fc2d4a1bc91e5ee54 to your computer and use it in GitHub Desktop.
Save radda-ui/9025e80dcd73688fc2d4a1bc91e5ee54 to your computer and use it in GitHub Desktop.
local matrix4, vector2, vector3, vector4
matrix4 = {
__type = "matrix4",
__call = function(_, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16)
return setmetatable({
__type = "matrix4",
m01 = m1 or 0, m02 = m2 or 0, m03 = m3 or 0, m04 = m4 or 0,
m05 = m5 or 0, m06 = m6 or 0, m07 = m7 or 0, m08 = m8 or 0,
m09 = m9 or 0, m10 = m10 or 0, m11 = m11 or 0, m12 = m12 or 0,
m13 = m13 or 0, m14 = m14 or 0, m15 = m15 or 0, m16 = m16 or 0
}, matrix4)
end,
__mul = function (self, m)
if type(m) == "table" and m.__type == "matrix4" then
return self:multiply(m)
elseif type(m) == "table" and m.__type == "vector2" then
v = vector4(m.x,m.y,0,1)
v2 = self:transform_vector(v)
return vector2(v2.x,v.y)
elseif type(m) == "table" and m.__type == "vector3" then
v = vector4(m.x,m.y,m.y,1)
v3 = self:transform_vector(v)
return vector3(v3.x,v3.y,v3.z)
elseif type(m) == "table" and m.__type == "vector4" then
return self:transform_vector(m)
elseif type(m) == "number" then
return self:scale(m)
end
end,
__index = {
identity = function(self)
return matrix4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 )
end,
get = function(self)
return {self.m01, self.m02, self.m03, self.m04, self.m05, self.m06, self.m07, self.m08, self.m09, self.m10,
self.m11, self.m12, self.m13, self.m14, self.m15, self.m16}
end,
unpack = function(self)
return self.m01, self.m02, self.m03, self.m04, self.m05, self.m06, self.m07, self.m08, self.m09, self.m10,
self.m11, self.m12, self.m13, self.m14, self.m15, self.m16
end,
multiply = function(self, b)
m = self
return matrix4(
m.m01 * b.m01 + m.m02 * b.m05 + m.m03 * b.m09 + m.m04 * b.m13,
m.m01 * b.m02 + m.m02 * b.m06 + m.m03 * b.m10 + m.m04 * b.m14,
m.m01 * b.m03 + m.m02 * b.m07 + m.m03 * b.m11 + m.m04 * b.m15,
m.m01 * b.m04 + m.m02 * b.m08 + m.m03 * b.m12 + m.m04 * b.m16,
m.m05 * b.m01 + m.m06 * b.m05 + m.m07 * b.m09 + m.m08 * b.m13,
m.m05 * b.m02 + m.m06 * b.m06 + m.m07 * b.m10 + m.m08 * b.m14,
m.m05 * b.m03 + m.m06 * b.m07 + m.m07 * b.m11 + m.m08 * b.m15,
m.m05 * b.m04 + m.m06 * b.m08 + m.m07 * b.m12 + m.m08 * b.m16,
m.m09 * b.m01 + m.m10 * b.m05 + m.m11 * b.m09 + m.m12 * b.m13,
m.m09 * b.m02 + m.m10 * b.m06 + m.m11 * b.m10 + m.m12 * b.m14,
m.m09 * b.m03 + m.m10 * b.m07 + m.m11 * b.m11 + m.m12 * b.m15,
m.m09 * b.m04 + m.m10 * b.m08 + m.m11 * b.m12 + m.m12 * b.m16,
m.m13 * b.m01 + m.m14 * b.m05 + m.m15 * b.m09 + m.m16 * b.m13,
m.m13 * b.m02 + m.m14 * b.m06 + m.m15 * b.m10 + m.m16 * b.m14,
m.m13 * b.m03 + m.m14 * b.m07 + m.m15 * b.m11 + m.m16 * b.m15,
m.m13 * b.m04 + m.m14 * b.m08 + m.m15 * b.m12 + m.m16 * b.m16
)
end,
scale = function(self,scale)
self.m01, self.m02, self.m03, self.m04, self.m05, self.n06, self.m07, self.m08, self.m09, self.m10, self.m11, self.m12, self.m13, self.m14, self.m15, self.m16 = self.m01 * scale, self.m02 * scale, self.m03 * scale, self.m04 * scale,self.m05 * scale, self.n06 * scale, self.m07 * scale, self.m08 * scale, self.m09 * scale, self.m10 * scale, self.m11 * scale, self.m12 * scale, self.m13 * scale, self.m14 * scale, self.m15 * scale, self.m16 * scale
return self
end,
transpose = function(self)
return matrix4(
self.m01, self.m05, self.m09, self.m13,
self.m02, self.m06, self.m10, self.m14,
self.m03, self.m07, self.m11, self.m15,
self.m04, self.m08, self.m12, self.m16
)
end,
determinant = function(self)
local m = self
local det =
m.m01 * (m.m06 * (m.m11 * m.m16 - m.m12 * m.m15) - m.m07 * (m.m10 * m.m16 - m.m12 * m.m14) + m.m08 * (m.m10 * m.m15 - m.m11 * m.m14)) -
m.m02 * (m.m05 * (m.m11 * m.m16 - m.m12 * m.m15) - m.m07 * (m.m09 * m.m16 - m.m12 * m.m13) + m.m08 * (m.m09 * m.m15 - m.m11 * m.m13)) +
m.m03 * (m.m05 * (m.m10 * m.m16 - m.m11 * m.m14) - m.m06 * (m.m09 * m.m16 - m.m12 * m.m13) + m.m08 * (m.m09 * m.m14 - m.m10 * m.m13)) -
m.m04 * (m.m05 * (m.m10 * m.m15 - m.m11 * m.m14) - m.m06 * (m.m09 * m.m15 - m.m11 * m.m13) + m.m07 * (m.m09 * m.m14 - m.m10 * m.m13))
return det
end,
inverse = function(self)
local m = self
local det = m:determinant()
if det == 0 then
return nil
end
local invDet = 1 / det
return matrix4(
(m.m06 * (m.m11 * m.m16 - m.m12 * m.m15) - m.m07 * (m.m10 * m.m16 - m.m12 * m.m14) + m.m08 * (m.m10 * m.m15 - m.m11 * m.m14)) * invDet,
-(m.m02 * (m.m11 * m.m16 - m.m12 * m.m15) - m.m03 * (m.m10 * m.m16 - m.m12 * m.m14) + m.m04 * (m.m10 * m.m15 - m.m11 * m.m14)) * invDet,
(m.m02 * (m.m07 * m.m16 - m.m08 * m.m15) - m.m03 * (m.m06 * m.m16 - m.m08 * m.m14) + m.m04 * (m.m06 * m.m15 - m.m07 * m.m14)) * invDet,
-(m.m02 * (m.m07 * m.m12 - m.m08 * m.m11) - m.m03 * (m.m06 * m.m12 - m.m08 * m.m10) + m.m04 * (m.m06 * m.m11 - m.m07 * m.m10)) * invDet,
-(m.m05 * (m.m11 * m.m16 - m.m12 * m.m15) - m.m07 * (m.m09 * m.m16 - m.m12 * m.m13) + m.m08 * (m.m09 * m.m15 - m.m11 * m.m13)) * invDet,
(m.m01 * (m.m11 * m.m16 - m.m12 * m.m15) - m.m03 * (m.m09 * m.m16 - m.m12 * m.m13) + m.m04 * (m.m09 * m.m15 - m.m11 * m.m13)) * invDet,
-(m.m01 * (m.m07 * m.m16 - m.m08 * m.m15) - m.m03 * (m.m05 * m.m16 - m.m08 * m.m13) + m.m04 * (m.m05 * m.m15 - m.m07 * m.m13)) * invDet,
(m.m01 * (m.m07 * m.m12 - m.m08 * m.m11) - m.m03 * (m.m05 * m.m12 - m.m08 * m.m09) + m.m04 * (m.m05 * m.m11 - m.m07 * m.m09)) * invDet,
(m.m05 * (m.m10 * m.m16 - m.m12 * m.m14) - m.m06 * (m.m09 * m.m16 - m.m12 * m.m13) + m.m08 * (m.m09 * m.m14 - m.m10 * m.m13)) * invDet,
-(m.m01 * (m.m10 * m.m16 - m.m12 * m.m14) - m.m02 * (m.m09 * m.m16 - m.m12 * m.m13) + m.m04 * (m.m09 * m.m14 - m.m10 * m.m13)) * invDet,
(m.m01 * (m.m06 * m.m16 - m.m08 * m.m14) - m.m02 * (m.m05 * m.m16 - m.m08 * m.m13) + m.m04 * (m.m05 * m.m14 - m.m06 * m.m13)) * invDet,
-(m.m01 * (m.m06 * m.m12 - m.m08 * m.m10) - m.m02 * (m.m05 * m.m12 - m.m08 * m.m09) + m.m04 * (m.m05 * m.m10 - m.m06 * m.m09)) * invDet,
-(m.m05 * (m.m10 * m.m15 - m.m11 * m.m14) - m.m06 * (m.m09 * m.m15 - m.m11 * m.m13) + m.m07 * (m.m09 * m.m14 - m.m10 * m.m13)) * invDet,
(m.m01 * (m.m10 * m.m15 - m.m11 * m.m14) - m.m02 * (m.m09 * m.m15 - m.m11 * m.m13) + m.m03 * (m.m09 * m.m14 - m.m10 * m.m13)) * invDet,
-(m.m01 * (m.m06 * m.m15 - m.m07 * m.m14) - m.m02 * (m.m05 * m.m15 - m.m07 * m.m13) + m.m03 * (m.m05 * m.m14 - m.m06 * m.m13)) * invDet,
(m.m01 * (m.m06 * m.m11 - m.m07 * m.m10) - m.m02 * (m.m05 * m.m11 - m.m07 * m.m09) + m.m03 * (m.m05 * m.m10 - m.m06 * m.m09)) * invDet
)
end,
translation_matrix=function (self, v)
return matrix4(1,0,0,v.x, 0,1,0,v.y, 0,0,1,v.z, 0,0,0,1)
end,
scale_matrix = function (self,v)
return matrix4(v.x,0,0,0, 0,v.y,0,0, 0,0,v.z,0, 0,0,0,1)
end,
ortho = function (self, left, right, bottom, top, near, far)
local rl = right - left
local tb = top - bottom
local fn = far - near
return matrix4(
2 / rl, 0, 0, -(right + left) / rl,
0, 2 / tb, 0, -(top + bottom) / tb,
0, 0, -2 / fn, -(far + near) / fn,
0, 0, 0, 1
)
end,
prespective = function (self, fov, aspect, near, far)
local tan_half_fov = -math.abs(math.tan(fov * 0.5))
local range = near - far
return matrix4(
1 / (aspect * tan_half_fov), 0, 0, 0,
0, 1 / tan_half_fov, 0, 0,
0, 0, (far + near) / range, 2 * far * near / range,
0, 0, -1, 0
)
end,
lookAt = function (self, eye, center, up)
local f = (center - eye):normalize()
local s = f:cross(up):normalize()
local u = s:cross(f)
return matrix4(
s.x, s.y, s.z, -s:dot(eye),
u.x, u.y, u.z, -u:dot(eye),
-f.x, -f.y, -f.z, f:dot(eye),
0, 0, 0, 1
):transpose()
end,
transform_vector = function(self, vector)
return vector4(
self.m01 * vector.x + self.m02 * vector.y + self.m03 * vector.z + self.m04 * vector.w,
self.m05 * vector.x + self.m06 * vector.y + self.m07 * vector.z + self.m08 * vector.w,
self.m09 * vector.x + self.m10 * vector.y + self.m11 * vector.z + self.m12 * vector.w,
self.m13 * vector.x + self.m14 * vector.y + self.m15 * vector.z + self.m16 * vector.w
)
end,
shear = function(self, xy, xz, yx, yz, zx, zy)
local m = self
return matrix4(
m.m01 + m.m02 * xy + m.m03 * xz, m.m01 * yx + m.m02 + m.m03 * yz, m.m01 * zx + m.m02 * zy + m.m03, m.m04,
m.m05 + m.m06 * xy + m.m07 * xz, m.m05 * yx + m.m06 + m.m07 * yz, m.m05 * zx + m.m06 * zy + m.m07, m.m08,
m.m09 + m.m10 * xy + m.m11 * xz, m.m09 * yx + m.m10 + m.m11 * yz, m.m09 * zx + m.m10 * zy + m.m11, m.m12,
m.m13 + m.m14 * xy + m.m15 * xz, m.m13 * yx + m.m14 + m.m15 * yz, m.m13 * zx + m.m14 * zy + m.m15, m.m16
)
end,
translate = function(self, vector)
local m = self
return matrix4(
m.m01, m.m02, m.m03, m.m04 + vector.x,
m.m05, m.m06, m.m07, m.m08 + vector.y,
m.m09, m.m10, m.m11, m.m12 + vector.z,
m.m13, m.m14, m.m15, m.m16
)
end,
-- rotate = function(self, angle, axis)
-- if axis == vector3(1,0,0) then
-- self:rotate_x()
-- end
-- if axis == vector3(0,1,0) then
-- end
-- if axis == vector3(0,0,1) then
-- end
-- local rotation_matrix = matrix4(
-- cos_a + x * x * t, x * y * t - z * sin_a, x * z * t + y * sin_a, 0,
-- y * x * t + z * sin_a, cos_a + y * y * t, y * z * t - x * sin_a, 0,
-- z * x * t - y * sin_a, z * y * t + x * sin_a, cos_a + z * z * t, 0,
-- 0, 0, 0, 1
-- )
-- -- Apply rotation to the matrix by multiplying it with the rotation matrix
-- return rotation_matrix * m
-- end,
rotate_x = function(self, angle)
local s, c = math.sin(angle), math.cos(angle)
return matrix4(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1)
end,
rotate_y = function(self, angle)
local s, c = math.sin(angle), math.cos(angle)
return matrix4(c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1)
end,
rotate_z = function(self, angle)
local s, c = math.sin(angle), math.cos(angle)
return matrix4(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
end,
rotation_matrix = function(self, v)
local mz = self:rotate_z(v.z)
local my = self:rotate_y(v.y)
local mx = self:rotate_x(v.x)
out = mz * my * mx
return out
end,
}
}
vector2 = {
__type = "vector2",
__call = function(_, _x, _y)
return setmetatable({__type = "vector2", x = _x or 0, y = _y or 0}, vector2)
end,
__tostring = function(self)
return " ( x: " .. self.x .. ", y: " .. self.y .. ")"
end,
__add = function(self, v)
return vector2(self.x + v.x, self.y + v.y)
end,
__sub = function(self, v)
return vector2(self.x - v.x, self.y - v.y)
end,
__mul = function(self, v)
if type(v) == "table" then
if v.__type and v.__type == "vector2" then
return self:multiply(v)
elseif v.__type and v.__type == "matrix4" then
return v * self
end
elseif type(v) == "number" then
return self:scale(v)
else
error("unsupported type: "..type(v))
end
end,
__unm = function(self)
return self:scale(-1)
end,
__index = {
scale = function(self, s)
return vector2(self.x * s, self.y * s)
end,
multiply = function(self, v)
return vector2(self.x * v.x, self.y * v.y)
end,
add = function(self, v)
return vector2(self.x + v.x, self.y + v.y)
end,
sub = function(self, v)
return vector2(self.x - v.x, self.y - v.y)
end,
div = function(self, s)
return vector2(self.x / s, self.y / s)
end,
clone = function(self)
return vector2(self.x, self.y)
end,
unpack = function(self)
return self.x, self.y
end,
length = function(self)
return math.sqrt(self.x * self.x + self.y * self.y)
end,
normalize = function(self)
local len = self:length()
if len == 0 then
return vector2(0, 0)
else
return vector2(self.x / len, self.y / len)
end
end,
distance = function(self, v)
local dx, dy = self.x - v.x, self.y - v.y
return math.sqrt(dx * dx + dy * dy)
end,
angle = function(self, v)
return math.atan2(v.y - self.y, v.x - self.x)
end,
dot = function(self, v)
return self.x * v.x + self.y * v.y
end,
cross = function(self, v)
return self.x * v.y - self.y * v.x
end,
lerp = function(self, v, t)
return vector2(self.x + (v.x - self.x) * t, self.y + (v.y - self.y) * t)
end,
project = function(self, v)
local dp = self:dot(v)
local len_sq = v.x * v.x + v.y * v.y
return vector2(v.x * dp / len_sq, v.y * dp / len_sq)
end,
rotate = function(self, angle)
local cos_angle = math.cos(angle)
local sin_angle = math.sin(angle)
return vector2(
self.x * cos_angle - self.y * sin_angle,
self.x * sin_angle + self.y * cos_angle
)
end,
}
}
vector3 = {
__type = "vector3",
__call = function(_, _x, _y, _z)
return setmetatable({ __type = "vector3",x = _x or 0, y = _y or 0, z = _z or 0}, vector3)
end,
__tostring = function(self)
return " ( x: " .. self.x .. ", y:" .. self.y .. ", z:" .. self.z .. ")"
end,
__add = function(self, v)
return vector3(self.x + v.x, self.y + v.y, self.z + v.z)
end,
__sub = function(self, v)
return vector3(self.x - v.x, self.y - v.y, self.z - v.z)
end,
__mul = function(self, v)
if type(v) == "table" then
if v.__type and v.__type == "matrix4" then
local t = v * self
return vector3(t.x, t.y, t.z)
elseif v.__type and v.__type == "vector4" then
local t = vector4(self.x,self.y,self.y,0) * v
return vector3(t.x, t.y, t.z)
elseif v.__type and v.__type == "vector3" then
return vector3(self.x * v.x, self.y * v.y, self.z * v.z)
end
elseif type(v) == "number" then
return vector3(self.x * v, self.y * v, self.z * v)
else
error("unsupported type: "..type(v))
end
end,
__unm = function(self)
return self:scale(-1)
end,
__index = {
scale = function(self, s)
return vector3(self.x * s, self.y * s, self.z * s)
end,
multiply = function(self, v)
return vector3(self.x * v.x, self.y * v.y, self.z * v.z)
end,
add = function(self, v)
return vector3(self.x + v.x, self.y + v.y, self.z + v.z)
end,
sub = function(self, v)
return vector3(self.x - v.x, self.y - v.y, self.z - v.z)
end,
div = function(self, s)
return vector3(self.x / s, self.y / s, self.z / s)
end,
clone = function(self)
return vector3(self.x, self.y, self.z)
end,
unpack = function(self)
return self.x, self.y, self.z
end,
length = function(self)
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
end,
normalize = function(self)
local len = self:length()
if len == 0 then
return vector3(0, 0, 0)
else
return vector3(self.x / len, self.y / len, self.z / len)
end
end,
distance = function(self, v)
local dx, dy, dz = self.x - v.x, self.y - v.y, self.z - v.z
return math.sqrt(dx * dx + dy * dy + dz * dz)
end,
angle = function(self, v)
local dot_product = self:dot(v)
local lengths = self:length() * v:length()
return math.acos(dot_product / lengths)
end,
dot = function(self, v)
return self.x * v.x + self.y * v.y + self.z * v.z
end,
cross = function(self, v)
return vector3(
self.y * v.z - self.z * v.y,
self.z * v.x - self.x * v.z,
self.x * v.y - self.y * v.x
)
end,
lerp = function(self, v, t)
return vector3(
self.x + (v.x - self.x) * t,
self.y + (v.y - self.y) * t,
self.z + (v.z - self.z) * t
)
end,
project = function(self, v)
local dp = self:dot(v)
local len_sq = v.x * v.x + v.y * v.y + v.z * v.z
return vector3(v.x * dp / len_sq, v.y * dp / len_sq, v.z * dp / len_sq)
end,
rotate = function(self, axis, angle)
local cos_angle = math.cos(angle)
local sin_angle = math.sin(angle)
local dot = self:dot(axis)
local cross = self:cross(axis)
return vector3(
self.x * cos_angle + cross.x * sin_angle + axis.x * dot * (1 - cos_angle),
self.y * cos_angle + cross.y * sin_angle + axis.y * dot * (1 - cos_angle),
self.z * cos_angle + cross.z * sin_angle + axis.z * dot * (1 - cos_angle)
)
end,
}
}
vector4 = {
__type = "vector4",
__call = function(_, _x, _y, _z, _w)
return setmetatable({__type = "vector4",x = _x or 0, y = _y or 0, z = _z or 0, w = _w or 0}, vector4)
end,
__tostring = function(self)
return " (x: " .. self.x .. ", y: " .. self.y .. ", z: " .. self.z .. ", w: " .. self.w .. ")"
end,
__add = function(self, v)
return vector4(self.x + v.x, self.y + v.y, self.z + v.z, self.w + v.w)
end,
__sub = function(self, v)
return vector4(self.x - v.x, self.y - v.y, self.z - v.z, self.w - v.w)
end,
__mul = function(self, v)
if type(v) == "number" then
return vector4(self.x * v, self.y * v, self.z * v, self.w * v)
else
return vector4(self.x * v.x, self.y * v.y, self.z * v.z, self.w * v.w)
end
end,
__unm = function(self)
return vector4(-self.x, -self.y, -self.z, -self.w)
end,
__index = {
scale = function(self, s)
return vector4(self.x * s, self.y * s, self.z * s, self.w * s)
end,
multiply = function(self, v)
return vector4(self.x * v.x, self.y * v.y, self.z * v.z, self.w * v.w)
end,
add = function(self, v)
return vector4(self.x + v.x, self.y + v.y, self.z + v.z, self.w + v.w)
end,
sub = function(self, v)
return vector4(self.x - v.x, self.y - v.y, self.z - v.z, self.w - v.w)
end,
div = function(self, s)
return vector4(self.x / s, self.y / s, self.z / s, self.w / s)
end,
clone = function(self)
return vector4(self.x, self.y, self.z, self.w)
end,
unpack = function(self)
return self.x, self.y, self.z, self.w
end,
length = function(self)
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w)
end,
normalize = function(self)
local len = self:length()
if len == 0 then
return vector4(0, 0, 0, 0)
else
return vector4(self.x / len, self.y / len, self.z / len, self.w / len)
end
end,
distance = function(self, v)
local dx, dy, dz, dw = self.x - v.x, self.y - v.y, self.z - v.z, self.w - v.w
return math.sqrt(dx * dx + dy * dy + dz * dz + dw * dw)
end,
angle = function(self, v)
local dot_product = self:dot(v)
local lengths = self:length() * v:length()
return math.acos(dot_product / lengths)
end,
dot = function(self, v)
return self.x * v.x + self.y * v.y + self.z * v.z + self.w * v.w
end,
cross = function(self, v)
return nil
end,
lerp = function(self, v, t)
return vector4(
self.x + (v.x - self.x) * t,
self.y + (v.y - self.y) * t,
self.z + (v.z - self.z) * t,
self.w + (v.w - self.w) * t
)
end,
project = function(self, v)
local dp = self:dot(v)
local len_sq = v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w
return vector4(v.x * dp / len_sq, v.y * dp / len_sq, v.z * dp / len_sq, v.w * dp / len_sq)
end,
rotate = function(self, angle)
-- First, convert the 4D vector to a quaternion (0, x, y, z)
local qv = quaternion(0, self.x, self.y, self.z)
-- Create a quaternion representing the rotation
local rotation_quaternion = quaternion.from_axis_angle({x = 0, y = 0, z = 1}, angle) -- Assuming rotation around z-axis
-- Rotate the vector quaternion using the rotation quaternion
local rotated_quaternion = rotation_quaternion:multiply(qv):multiply(rotation_quaternion:conjugate())
-- Extract the rotated vector components from the quaternion
return {x = rotated_quaternion.x, y = rotated_quaternion.y, z = rotated_quaternion.z}
end,
}
}
quaternion = {
__type = "quaternion",
__call = function(_, _w, _x, _y, _z)
return setmetatable({__type = "quaternion",w = _w or 0, x = _x or 0, y = _y or 0, z = _z or 0}, quaternion)
end,
__tostring = function(self)
return " (w: " .. self.w .. ", x: " .. self.x .. ", y: " .. self.y .. ", z: " .. self.z .. ")"
end,
__add = function(self, q)
return quaternion(self.w + q.w, self.x + q.x, self.y + q.y, self.z + q.z)
end,
__sub = function(self, q)
return quaternion(self.w - q.w, self.x - q.x, self.y - q.y, self.z - q.z)
end,
__mul = function(self, q)
if type(q) == "number" then
return quaternion(self.w * q, self.x * q, self.y * q, self.z * q)
else
return quaternion(
self.w * q.w - self.x * q.x - self.y * q.y - self.z * q.z,
self.w * q.x + self.x * q.w + self.y * q.z - self.z * q.y,
self.w * q.y - self.x * q.z + self.y * q.w + self.z * q.x,
self.w * q.z + self.x * q.y - self.y * q.x + self.z * q.w
)
end
end,
__unm = function(self)
return quaternion(-self.w, -self.x, -self.y, -self.z)
end,
__index = {
scale = function(self, s)
return quaternion(self.w * s, self.x * s, self.y * s, self.z * s)
end,
add = function(self, q)
return quaternion(self.w + q.w, self.x + q.x, self.y + q.y, self.z + q.z)
end,
sub = function(self, q)
return quaternion(self.w - q.w, self.x - q.x, self.y - q.y, self.z - q.z)
end,
multiply = function(self, q)
return self * q
end,
div = function(self, s)
return quaternion(self.w / s, self.x / s, self.y / s, self.z / s)
end,
clone = function(self)
return quaternion(self.w, self.x, self.y, self.z)
end,
unpack = function(self)
return self.w, self.x, self.y, self.z
end,
length = function(self)
return math.sqrt(self.w * self.w + self.x * self.x + self.y * self.y + self.z * self.z)
end,
normalize = function(self)
local len = self:length()
if len == 0 then
return quaternion(0, 0, 0, 0)
else
return quaternion(self.w / len, self.x / len, self.y / len, self.z / len)
end
end,
conjugate = function(self)
return quaternion(self.w, -self.x, -self.y, -self.z)
end,
inverse = function(self)
local len_sq = self.w * self.w + self.x * self.x + self.y * self.y + self.z * self.z
if len_sq == 0 then
return quaternion(0, 0, 0, 0)
else
return quaternion(self.w / len_sq, -self.x / len_sq, -self.y / len_sq, -self.z / len_sq)
end
end,
dot = function(self, q)
return self.w * q.w + self.x * q.x + self.y * q.y + self.z * q.z
end,
lerp = function(self, q, t)
return quaternion(
self.w + (q.w - self.w) * t,
self.x + (q.x - self.x) * t,
self.y + (q.y - self.y) * t,
self.z + (q.z - self.z) * t
)
end,
slerp = function(self, q, t)
local dot = self:dot(q)
if dot < 0 then
q = q:scale(-1)
dot = -dot
end
if dot > 0.9995 then
return self:lerp(q, t):normalize()
end
local theta_0 = math.acos(dot)
local theta = theta_0 * t
local sin_theta = math.sin(theta)
local sin_theta_0 = math.sin(theta_0)
local s0 = math.cos(theta) - dot * sin_theta / sin_theta_0
local s1 = sin_theta / sin_theta_0
return self:scale(s0):add(q:scale(s1))
end,
rotate = function(self, v)
local qv = quaternion(0, v.x, v.y, v.z)
local qr = self:clone()
local qr_inv = qr:inverse()
local result = qr:multiply(qv):multiply(qr_inv)
return {x = result.x, y = result.y, z = result.z}
end,
from_axis_angle = function(axis, angle)
local half_angle = angle / 2
local s = math.sin(half_angle)
return quaternion(math.cos(half_angle), axis.x * s, axis.y * s, axis.z * s)
end,
to_axis_angle = function(self)
local angle = 2 * math.acos(self.w)
local s = math.sqrt(1 - self.w * self.w)
if s < 0.001 then
return {x = self.x, y = self.y, z = self.z}, angle
else
return {x = self.x / s, y = self.y / s, z = self.z / s}, angle
end
end
}
}
setmetatable(vector2, vector2)
setmetatable(vector3, vector3)
setmetatable(vector4, vector4)
setmetatable(quaternion, quaternion)
setmetatable(matrix4, matrix4)
_G.vector2 = vector2
_G.vector3 = vector3
_G.vector4 = vector4
_G.quaternion = quaternion
_G.matrix4 = matrix4
-----------------------------------------------------------------------------------------------------------------------------------------
--require "library"
Camera = {}
Camera.__index = Camera
function Camera.new(position, target, up)
local self = setmetatable({}, Camera)
self.position = position or vector3(0, 0, 0)
self.target = target or vector3(0, 0, -5)
self.up = up or vector3(0, 1, 0)
self.rotation = vector3(0, 0, 0)
self.fov = 90
self.aspect = lg.getWidth()/lg.getHeight()
self.shader = lg.newShader([[
#pragma language glsl3
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 model;
varying vec4 vpos;
#ifdef VERTEX
vec4 position(mat4 transformProjection, vec4 vertexPosition) {
vpos = viewMatrix * projectionMatrix * model * vertexPosition ;
return vpos ;
}
#endif
#ifdef PIXEL
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) {
vec4 texcolor = Texel(tex, texture_coords);
return texcolor * color;
}
#endif
]])
return self
end
function Camera:update(dt)
if love.keyboard.isDown("up") then
self.position = self.position + vector3(0,1,0)*dt
end
if love.keyboard.isDown("down") then
self.position = self.position + vector3(0,-1,0)*dt
end
if love.keyboard.isDown("right") then
self.position = self.position + vector3(1,0,0)*dt
end
if love.keyboard.isDown("left") then
self.position = self.position + vector3(-1,0,0)*dt
end
if love.keyboard.isDown("w") then
self.position = self.position + vector3(0,0,1)*dt
end
if love.keyboard.isDown("s") then
self.position = self.position + vector3(0,0,-1)*dt
end
if love.keyboard.isDown("a") then
self.rotation = self.rotation + vector3(0,1,0)*dt
end
if love.keyboard.isDown("d") then
self.rotation = self.rotation + vector3(0,-1,0)*dt
end
end
function clamp(fov)
if fov < 90 then
return 90
elseif fov > 180 then
return 180
else
return fov
end
end
function Camera:zoom(zoom)
self.fov = clamp(self.fov + zoom *0.1)
end
function Camera:show()
lg.setShader(self.shader)
self.shader:send("projectionMatrix", matrix4:prespective(self.fov,self.aspect,0.1,100):get())
model = matrix4:translation_matrix(self.position)* matrix4:rotation_matrix(self.rotation)* matrix4:scale_matrix(vector3(1/self.aspect,1/self.aspect,1))
self.shader:send("model", model:get())
self.shader:send("viewMatrix", (matrix4:lookAt(self.target,vector3(0,0,0),self.up)):get())
end
function Camera:unshow()
lg.setShader()
end
return Camera
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment