Created
June 6, 2024 20:21
-
-
Save radda-ui/9025e80dcd73688fc2d4a1bc91e5ee54 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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