Skip to content

Instantly share code, notes, and snippets.

@appgurueu
Created February 20, 2025 19:08
-- See https://github.com/luanti-org/luanti/issues/15692
-- Identifies possibly affected bones and prints scales to be used for the described "negative scale" workaround
assert(modlib.version >= 103)
local media_paths = modlib.minetest.media.paths
local function nodes(filepath)
local stream = assert(io.open(filepath, "rb"))
local model = assert(modlib.b3d.read(stream))
stream:close()
return coroutine.wrap(function()
local function visit(node)
coroutine.yield(node)
for _, child in ipairs(node.children) do
visit(child)
end
end
visit(model.node)
end)
end
local function isclose(a, b)
return math.abs(a - b) < 1e-3
end
for name, path in pairs(media_paths) do
if name:match"%.b3d$" then
local first = true
local _, it = xpcall(function() return nodes(path) end, function(err)
core.log("warning", ("Failed to read model %s: %s"):format(name, err))
return function() end
end)
for node in it do
local rot_quat = node.rotation
local rot_mat = modlib.matrix4.rotation(rot_quat)
local rxx, ryy, rzz = rot_mat[1][1], rot_mat[2][2], rot_mat[3][3]
local function abs1(x) return isclose(math.abs(x), 1) end
local is_scaling = abs1(rxx) and abs1(ryy) and abs1(rzz)
local flips_axis = isclose(rxx, -1) or isclose(ryy, -1) or isclose(rzz, -1)
if is_scaling and flips_axis then
if first then
print(("Possibly affected bones in `%s`:"):format(name))
end
first = false
local sx, sy, sz = unpack(node.scale)
-- Suggest scales for the negative scale workaround
print(("Bone %s should get a scale of (%.01f, %.01f %.01f)"):format(
node.name, sx * rxx, sy * ryy, sz * rzz))
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment