add basic rotation operations to matrices

This commit is contained in:
FatalErr42O 2024-12-19 18:21:45 -08:00
parent 9501462e51
commit 63cafc0bda
3 changed files with 101 additions and 19 deletions

View File

@ -254,10 +254,76 @@ local abs = math.abs
-- @function set_rot_luanti_entity
mat4.set_rot_luanti_entity = mat4.set_rot_zxy
--- rotates a matrix on the ZX matrix (otherwise known as yaw in coordinate systems where Y is up)
function mat4.rotate_Y(m, r, use_identity)
local cy = cos(r)
local sy = sin(r)
tm4[1] = m[3]*sy + m[1]*cy
tm4[2] = m[2]
tm4[3] = m[3]*cy - m[1]*sy
tm4[4] = m[4]
tm4[5] = m[7]*sy + m[5]*cy
tm4[6] = m[6]
tm4[7] = m[7]*cy - m[5]*sy
tm4[8] = m[8]
tm4[9] = m[11]*sy + m[9]*cy
tm4[10] = m[10]
tm4[11] = m[11]*cy - m[9]*sy
tm4[12] = m[12]
for i = 1, 12 do
m[i] = tm4[i]
end
return m
end
function mat4.rotate_Z(m, r, use_identity)
local cz = cos(r)
local sz = sin(r)
tm4[1] = m[1]*cz - m[2]*sz
tm4[2] = m[1]*sz + m[2]*cz
tm4[3] = m[3]
tm4[4] = m[4]
tm4[5] = m[5]*cz - m[6]*sz
tm4[6] = m[5]*sz + m[6]*cz
tm4[7] = m[7]
tm4[8] = m[8]
tm4[9] = m[9]*cz - m[10]*sz
tm4[10] = m[9]*sz + m[10]*cz
tm4[11] = m[11]
tm4[12] = m[12]
for i = 1, 12 do
m[i] = tm4[i]
end
return m
end
function mat4.rotate_X(m, r, use_identity)
local cz = cos(r)
local sz = sin(r)
tm4[1] = m[1]
tm4[2] = m[2]*cz - m[3]*sz
tm4[3] = m[2]*sz + m[3]*cz
tm4[4] = m[4]
tm4[5] = m[5]
tm4[6] = m[6]*cz - m[7]*sz
tm4[7] = m[6]*sz + m[7]*cz
tm4[8] = m[8]
tm4[9] = m[9]
tm4[10] = m[10]*cz - m[11]*sz
tm4[11] = m[10]*sz + m[11]*cz
tm4[12] = m[12]
for i = 1, 12 do
m[i] = tm4[i]
end
return m
end
--- get the ZXY euler rotation of the given matrix. This is the order that minetest entities are rotated in.
-- @tparam matrix the matrix to get the rotation of
@ -287,9 +353,6 @@ end
mat4.get_rot_luanti_entity = mat4.get_rot_zxy
--- set the rotation of a given matrix in euler in the XYZ application order. This is the rotation order irrlicht uses (i.e. for bones in Luanti)
-- @tparam float pitch the clockwise pitch in radians
-- @tparam float yaw the clockwise yaw in radians
@ -522,6 +585,8 @@ function mul_internal(out, a, b)
end
end
local mul_tm4 = mat4.new()
--- Multiply N matrices.
-- @tparam mat4 out Matrix to store the result
-- @tparam table a a mat4 or a list of mat4s
@ -535,16 +600,23 @@ function mat4.mul(out, a, b)
if #a == 0 then
error("incorrect operand, expected two mat4s or list of mat4s but recieved empty table.")
else
local new_mat = a[#a]
for i = #a-1, 1, -1 do
new_mat = a[i]*new_mat
mul_internal(mul_tm4, a[#a-1], a[#a])
for i = #a-2, 1, -1 do
mul_internal(mul_tm4, a[i], mul_tm4)
end
for i=1,16 do
out[i] = new_mat[i]
out[i] = mul_tm4[i]
end
end
return out
end
--- Multiply N matrices.
-- @tparam mat4 out Matrix to store the result
-- @tparam table a a mat4 or a list of mat4s
-- @tparam mat4 b right operand used if param a is a mat4
-- @treturn mat4 out multiplied matrix result
-- @function multiply
mat4.multiply = mat4.mul
--- Multiply a matrix and a vec3, with perspective division.
-- This function uses an implicit 1 for the fourth component.

View File

@ -1,10 +1,9 @@
local cos = math.cos
local sin = math.sin
local m = leef.math
local mat4 = leef.math.mat4
local pitch_ZY = function(a)
local temp = mat4.new()
local temp = mat4.identity()
temp[6] = cos(a)
temp[7] = sin(a)
temp[10] = -sin(a)
@ -12,7 +11,7 @@ local pitch_ZY = function(a)
return temp
end
local pitch_ZY2 = function(a)
local temp = mat4.new()
local temp = mat4.identity()
temp[6] = cos(a)
temp[7] = -sin(a)
temp[10] = sin(a)
@ -21,7 +20,7 @@ local pitch_ZY2 = function(a)
end
local roll_XY = function(a)
local temp = mat4.new()
local temp = mat4.identity()
temp[1] = cos(a)
temp[2] = sin(a)
temp[5] = -sin(a)
@ -29,7 +28,7 @@ local roll_XY = function(a)
return temp
end
local roll_XY2 = function(a)
local temp = mat4.new()
local temp = mat4.identity()
temp[1] = cos(a)
temp[2] = -sin(a)
temp[5] = sin(a)
@ -37,7 +36,7 @@ local roll_XY2 = function(a)
return temp
end
local yaw_ZX = function(a)
local temp = mat4.new()
local temp = mat4.identity()
temp[1] = cos(a)
temp[3] = -sin(a)
temp[9] = sin(a)
@ -45,7 +44,7 @@ local yaw_ZX = function(a)
return temp
end
local yaw_ZX2 = function(a)
local temp = mat4.new()
local temp = mat4.identity()
temp[1] = cos(a)
temp[3] = sin(a)
temp[9] = -sin(a)
@ -100,7 +99,7 @@ end
function leef.math.find_matrix_rotation_order(check_func)
--x,y,z
local euler = {(math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4}
local output = check_func(mat4.new(), euler[1],euler[2],euler[3])
local output = check_func(mat4.identity(), euler[1],euler[2],euler[3])
local iter = 0
local running_order
for _, p_tf in pairs(pitch_transforms) do
@ -111,7 +110,7 @@ function leef.math.find_matrix_rotation_order(check_func)
iter = iter + 1
--intrinsic order is pitch yaw roll for this check, meaning that 1 is assigned to pitch and so fourth.
local matrices = {p_tf, y_tf, r_tf}
local active_mat = mat4.new()
local active_mat = mat4.identity()
running_order = nil
for i=1,3 do
local func = matrices[order[i]]
@ -134,14 +133,23 @@ print("================== BEGINNING LUANTI AND IRRLICHT UNIT TESTs =============
local find_rot_order = leef.math.find_matrix_rotation_order
print("\n checking sanity of tests:")
local _tempeuler = {(math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4, (math.random()-.5)*math.pi*4}
local _testmatrix = leef.math.mat4.set_rot_zxy(mat4.new(), _tempeuler[1],_tempeuler[2],_tempeuler[3])
local _testmatrix = leef.math.mat4.set_rot_zxy(mat4.identity(), _tempeuler[1],_tempeuler[2],_tempeuler[3])
print("matrix equality check func is sane:", check_matrix_equality(_testmatrix,_testmatrix))
print("matrix equality check func tolerance:", matrix_tolerance)
print("\n Checking rotation orders. Rotation application order is in reverse, these are the literal matrix multiplication order. ")
--[[print("\n Checking rotation orders. Rotation application order is in reverse, these are the literal matrix multiplication order. ")
print("checking rotation matrix `set_rot_luanti_entity`")
find_rot_order(leef.math.mat4.set_rot_luanti_entity)
print("checking `set_rot_irrlicht_bone`")
find_rot_order(leef.math.mat4.set_rot_irrlicht_bone)
find_rot_order(leef.math.mat4.set_rot_irrlicht_bone)]]
print("checking rotation axis functions `rotate_X` `rotate_Y` and `rotate_Z`")
find_rot_order(function(m, x,y,z)
return m:rotate_X(x):rotate_Y(y):rotate_Z(z)
end)
local t = (math.random()-.5)*math.pi*4
print("checking `rotate_X`", check_matrix_equality(pitch_ZY(t), mat4.identity():rotate_X(t)))
print("checking `rotate_Y`", check_matrix_equality(yaw_ZX(t), mat4.identity():rotate_Y(t)))
print("checking `rotate_Z`", check_matrix_equality(roll_XY(t), mat4.identity():rotate_Z(t)))
print("================== ENDING LUANTI AND IRRLICHT UNIT TESTs =======================")

View File

@ -51,6 +51,8 @@ print("checking rotation matrix `set_rot_luanti_entity`")
find_rot_order(leef.math.mat4.set_rot_luanti_entity)
print("checking `set_rot_irrlicht_bone`")
find_rot_order(leef.math.mat4.set_rot_irrlicht_bone)
print("checking that mul(out, {mat, mat, mat}) performs in correct order. Inputting `XYZ`")
find_rot_order(function(m,x,y,z) return mat4.multiply(mat4.identity(), {mat4.identity():rotate_X(x), mat4.identity():rotate_Y(y), mat4.identity():rotate_Z(z)}) end)
--[[print("check in euler out euler for minetest entitiy matrix rotations")
local x,y,z =(math.random()-.5)*math.pi*4,(math.random()-.5)*math.pi*4,(math.random()-.5)*math.pi*4