2021-02-02 15:44:58 +01:00
|
|
|
function multiply(self, other)
|
2021-02-02 10:38:21 +01:00
|
|
|
return {
|
2021-02-02 15:44:58 +01:00
|
|
|
other[1] * self[1] - other[2] * self[2] - other[3] * self[3] - other[4] * self[4],
|
|
|
|
other[1] * self[2] + other[2] * self[1] - other[3] * self[4] + other[4] * self[3],
|
|
|
|
other[1] * self[3] + other[2] * self[4] + other[3] * self[1] - other[4] * self[2],
|
|
|
|
other[1] * self[4] - other[2] * self[3] + other[3] * self[2] + other[4] * self[1]
|
2021-02-02 10:38:21 +01:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
function normalize(self)
|
|
|
|
local len = math.sqrt(self[1] ^ 2 + self[2] ^ 2 + self[3] ^ 2 + (q[4] ^ 4))
|
|
|
|
local res = {}
|
|
|
|
for key, value in pairs(self) do
|
|
|
|
res[key] = value / len
|
2021-02-02 10:38:21 +01:00
|
|
|
end
|
2021-02-02 15:44:58 +01:00
|
|
|
return res
|
2021-02-02 10:38:21 +01:00
|
|
|
end
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
function negate(self)
|
|
|
|
for key, value in pairs(self) do
|
|
|
|
self[key] = -value
|
2021-02-02 10:38:21 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
function dot(self, other)
|
|
|
|
return self[1] * other[1] + self[2] * other[2] + self[3] * other[3] + self[4] * other[4]
|
2021-02-02 10:38:21 +01:00
|
|
|
end
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
--: self normalized quaternion
|
|
|
|
--: other normalized quaternion
|
|
|
|
function slerp(self, other, ratio)
|
|
|
|
local d = dot(self, other)
|
2021-02-02 10:38:21 +01:00
|
|
|
if d < 0 then
|
|
|
|
d = -d
|
2021-02-02 15:44:58 +01:00
|
|
|
negate(other)
|
2021-02-02 10:38:21 +01:00
|
|
|
end
|
|
|
|
-- Threshold beyond which linear interpolation is used
|
|
|
|
if d > 1 - 1e-10 then
|
2021-02-02 15:44:58 +01:00
|
|
|
return modlib.vector.interpolate(self, other, ratio)
|
2021-02-02 10:38:21 +01:00
|
|
|
end
|
|
|
|
local theta_0 = math.acos(d)
|
2021-02-02 15:44:58 +01:00
|
|
|
local theta = theta_0 * ratio
|
2021-02-02 10:38:21 +01:00
|
|
|
local sin_theta = math.sin(theta)
|
|
|
|
local sin_theta_0 = math.sin(theta_0)
|
|
|
|
local s_1 = sin_theta / sin_theta_0
|
|
|
|
local s_0 = math.cos(theta) - d * s_1
|
2021-02-02 15:44:58 +01:00
|
|
|
return modlib.vector.add(modlib.vector.multiply_scalar(self, s_0), modlib.vector.multiply_scalar(other, s_1))
|
2021-02-02 10:38:21 +01:00
|
|
|
end
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
--> {x, y, z} euler rotation in degrees
|
|
|
|
function to_euler_rotation(self)
|
2021-02-02 10:38:21 +01:00
|
|
|
local rotation = {}
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
local sinr_cosp = 2 * (self[4] * self[1] + self[2] * self[3])
|
|
|
|
local cosr_cosp = 1 - 2 * (self[1] * self[1] + self[2] * self[2])
|
2021-02-02 10:38:21 +01:00
|
|
|
rotation.x = math.atan2(sinr_cosp, cosr_cosp)
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
local sinp = 2 * (self[4] * self[2] - self[3] * self[1])
|
2021-02-02 10:38:21 +01:00
|
|
|
if sinp <= -1 then
|
|
|
|
rotation.y = -math.pi/2
|
|
|
|
elseif sinp >= 1 then
|
|
|
|
rotation.y = math.pi/2
|
|
|
|
else
|
|
|
|
rotation.y = math.asin(sinp)
|
|
|
|
end
|
|
|
|
|
2021-02-02 15:44:58 +01:00
|
|
|
local siny_cosp = 2 * (self[4] * self[3] + self[1] * self[2])
|
|
|
|
local cosy_cosp = 1 - 2 * (self[2] * self[2] + self[3] * self[3])
|
2021-02-02 10:38:21 +01:00
|
|
|
rotation.z = math.atan2(siny_cosp, cosy_cosp)
|
|
|
|
|
|
|
|
return vector.apply(rotation, math.deg)
|
|
|
|
end
|