updated nodes library (unfinished), fixed dependency (mtul-cpml renamed)
This commit is contained in:
parent
15fff69e75
commit
220d837842
9
init.lua
9
init.lua
@ -21,11 +21,16 @@ dofile(modpath.."/modlib/write_b3d.lua") --this is untested, could be very broke
|
||||
if mtul.loaded_modules.cpml then
|
||||
mtul.b3d_nodes = dofile(modpath.."/nodes.lua")
|
||||
mtul.loaded_modules.b3d_nodes = true
|
||||
mtul.b3d_nodes.loaded = true
|
||||
else
|
||||
mtul.b3d_nodes = {}
|
||||
setmetatable(mtul.b3d_nodes, {
|
||||
__index = function()
|
||||
error("MTUL-CPML not present, b3d_nodes module inaccessible.")
|
||||
__index = function(_, k)
|
||||
if k ~= "loaded" then
|
||||
error("MTUL-CPML not present, b3d_nodes module inaccessible.")
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
2
mod.conf
2
mod.conf
@ -2,5 +2,5 @@ name = mtul_b3d
|
||||
title = MTUL b3d standalone
|
||||
description = a b3d reader for minetest, cloned from modlib. Requires MTUL-core, also requires MTUL-math for bone reading implementations.
|
||||
depends = mtul_core
|
||||
optional_depends = mtul_math_cpml
|
||||
optional_depends = mtul_cpml
|
||||
author = FatalError42O, Appgurue
|
@ -17,19 +17,18 @@ local read_int, read_single = mtul.binary.read_int, mtul.binary.read_single
|
||||
|
||||
--reads a model directly (based on name). Note that "node_only" abstracts chunks not necessary to finding the position/transform of a bone/node.
|
||||
function mtul.b3d.read_model(modelname, node_only)
|
||||
local path = mtul.media_paths[modelname]
|
||||
assert(modelname, "no modelname provided")
|
||||
local path = assert(mtul.media_paths[modelname], "no model found by the name "..modelname.."'")
|
||||
local out
|
||||
if path then
|
||||
local ignored
|
||||
if node_only then
|
||||
ignored = {"TEXS", "BRUS", "BONE", "MESH"}
|
||||
end
|
||||
local stream = io.open(path, "rb")
|
||||
if not stream then return end --if the file wasn't found we probably shouldnt just assert.
|
||||
out = mtul.b3d.read_from_stream(stream, ignored)
|
||||
assert(stream:read(1)==nil, "MTUL B3D: unknown error, EOF not reached")
|
||||
stream:close()
|
||||
local ignored
|
||||
if node_only then
|
||||
ignored = {"TEXS", "BRUS", "BONE", "MESH"}
|
||||
end
|
||||
local stream = io.open(path, "rb")
|
||||
if not stream then return end --if the file wasn't found we probably shouldnt just assert.
|
||||
out = mtul.b3d.read_from_stream(stream, ignored)
|
||||
assert(stream:read(1)==nil, "MTUL B3D: unknown error, EOF not reached")
|
||||
stream:close()
|
||||
return out
|
||||
end
|
||||
|
||||
@ -45,6 +44,7 @@ end
|
||||
--this is ideal if you need to, say, solve for the transform of a node- instead of iterating 100s of times to get every parent node
|
||||
--it's all provided for you. Note that it's from highest to lowest, where lowest of course is the current node, the last element.
|
||||
|
||||
--made originally by appgurueu
|
||||
function mtul.b3d.read_from_stream(stream, ignore_chunks)
|
||||
local left = 8
|
||||
|
||||
@ -283,30 +283,36 @@ function mtul.b3d.read_from_stream(stream, ignore_chunks)
|
||||
-- Order is not validated; double occurrences of mutually exclusive node def are
|
||||
while content() do
|
||||
local elem, type = chunk()
|
||||
if not ignored[type] then
|
||||
if type == "MESH" then
|
||||
assert(not node_type)
|
||||
node_type = "mesh"
|
||||
if type == "MESH" then
|
||||
assert(not node_type)
|
||||
node_type = "mesh"
|
||||
if not ignored[type] then
|
||||
node.mesh = elem
|
||||
elseif type == "BONE" then
|
||||
assert(not node_type)
|
||||
node_type = "bone"
|
||||
node.bone = elem
|
||||
elseif type == "KEYS" then
|
||||
mtul.tbl.append(node.keys, elem)
|
||||
elseif type == "NODE" then
|
||||
elem.parent = node
|
||||
table.insert(node.children, elem)
|
||||
elseif type == "ANIM" then
|
||||
node.animation = elem
|
||||
else
|
||||
assert(not node_type)
|
||||
node_type = "pivot"
|
||||
end
|
||||
elseif type == "BONE" then
|
||||
assert(not node_type)
|
||||
node_type = "bone"
|
||||
if not ignored[type] then
|
||||
node.bone = elem
|
||||
end
|
||||
elseif type == "KEYS" then
|
||||
if not ignored[type] then
|
||||
mtul.tbl.append(node.keys, elem)
|
||||
end
|
||||
elseif type == "NODE" then
|
||||
elem.parent = node
|
||||
table.insert(node.children, elem)
|
||||
elseif type == "ANIM" then
|
||||
if not ignored[type] then
|
||||
node.animation = elem
|
||||
end
|
||||
else
|
||||
assert(not node_type, "Appgurueu decided to not put actual messages, so I'm not sure, but your .b3d file is fscked up lol. I dont even think this assert is needed.")
|
||||
node_type = "pivot"
|
||||
end
|
||||
end
|
||||
--added because ignored nodes may unintentionally obfuscate the type of node- which could be necessary for finding bone "paths"
|
||||
node.type = node_type
|
||||
--added because ignored nodes may obfuscate the type of node- which could be necessary for finding bone "paths"
|
||||
node.type = node_type or "pivot"
|
||||
-- Ensure frames are sorted ascendingly
|
||||
table.sort(node.keys, function(a, b)
|
||||
assert(a.frame ~= b.frame, "duplicate frame")
|
||||
@ -363,7 +369,7 @@ function mtul.b3d.read_from_stream(stream, ignore_chunks)
|
||||
--luckily most of the ground work is layed out for us already.
|
||||
|
||||
--also, Fatal here: for the sake of my reputation (which is nonexistent), typically I wouldn't nest these functions
|
||||
--because I am not a physcopath and or a german named Lars, but for the sake of consistency it has to happen. (Not that its *always* a bad idea, but unless you're baking in parameters it's sort of awful)
|
||||
--because I am not a physcopath and or a german named Lars, but for the sake of consistency it has to happen. (Not that its *always* a bad idea, but unless you're baking in parameters it's sort of useless and potentially wasteful)
|
||||
local copy_path = mtul.table and mtul.table.shallow_copy or function(tbl)
|
||||
local new_table = {}
|
||||
for i, v in pairs(tbl) do
|
||||
@ -383,6 +389,7 @@ function mtul.b3d.read_from_stream(stream, ignore_chunks)
|
||||
|
||||
local self = chunk{BB3D = true}
|
||||
self.node_paths = {}
|
||||
self.excluded_chunks = ignore_chunks and table.copy(ignore_chunks) or {}
|
||||
make_paths(self.node, {}, self.node_paths)
|
||||
|
||||
--b3d metatable unimplemented
|
||||
|
81
nodes.lua
81
nodes.lua
@ -8,7 +8,7 @@ function b3d_nodes.get_node_by_name(self, node_name, is_bone)
|
||||
return this_node
|
||||
end
|
||||
end
|
||||
error("MTUL-b3d, b3d_nodes: no node found by the name '"..node_name.."'")
|
||||
error("MTUL-b3d, b3d_nodes: no node found by the name '"..tostring(node_name).."'")
|
||||
end
|
||||
|
||||
--non-methods:
|
||||
@ -33,7 +33,6 @@ function b3d_nodes.get_animated_local_transform(node, target_frame)
|
||||
--need this so we can replace it if before doesnt exist
|
||||
local frame_before_tbl = frames[key_index_before]
|
||||
local frame_after_tbl = frames[key_index_before+1] --frame to interpolate will be out immediate neighbor since we know its either the frame or after the frame.
|
||||
print(target_frame)
|
||||
--it may still be zero, indicating that the frame before doesnt exist.
|
||||
if not frame_before_tbl then
|
||||
frame_before_tbl = node --set it to the node so it pulls from PRS directly as that's it's default state.
|
||||
@ -56,45 +55,67 @@ function b3d_nodes.get_animated_local_transform(node, target_frame)
|
||||
end
|
||||
local mat4 = mtul.math.mat4
|
||||
local quat = mtul.math.quat
|
||||
function b3d_nodes.get_node_global_transform(node, frame)
|
||||
--param 3 (outputs) is either "rotation" or "transform"- determines what's calculated. You can use this if you dont want uncessary calculations. If nil outputs both
|
||||
function b3d_nodes.get_node_global_transform(node, frame, outputs)
|
||||
local global_transform
|
||||
local rotation
|
||||
for i, current_node in pairs(node.path) do
|
||||
local pos_vec, rot_vec, scl_vec = b3d_nodes.get_animated_local_transform(current_node, frame)
|
||||
--rot_vec = {rot_vec[2], rot_vec[3], rot_vec[4], rot_vec[1]}
|
||||
local local_transform = mat4.identity()
|
||||
--translate rotation by position
|
||||
local_transform = local_transform:translate(local_transform, {-pos_vec[1], pos_vec[2], pos_vec[3]})
|
||||
local_transform = local_transform*(mat4.from_quaternion(quat.new(-rot_vec[1], rot_vec[2], rot_vec[3], rot_vec[4]):normalize()))
|
||||
--scale the mat4.
|
||||
--local_transform = local_transform:scale(local_transform, {scl_vec[1], scl_vec[2], scl_vec[3]})
|
||||
--I dont really know why this works and the above doesn't, but at this point I'm done trying to figure it out...
|
||||
local identity = mat4.identity()
|
||||
local_transform = local_transform*identity:scale(identity, {scl_vec[1], scl_vec[2], scl_vec[3]})
|
||||
|
||||
--get new global trasnform with the local.
|
||||
if global_transform then
|
||||
global_transform=global_transform*local_transform
|
||||
else
|
||||
global_transform=local_transform
|
||||
--find the transform
|
||||
|
||||
if not (outputs and outputs ~= "transform") then
|
||||
--rot_vec = {rot_vec[2], rot_vec[3], rot_vec[4], rot_vec[1]}
|
||||
local local_transform = mat4.identity()
|
||||
local_transform = local_transform:translate(local_transform, {-pos_vec[1], pos_vec[2], pos_vec[3]})--not sure why x has to be inverted,
|
||||
local_transform = local_transform*(mat4.from_quaternion(quat.new(-rot_vec[1], rot_vec[2], rot_vec[3], rot_vec[4]):normalize())) --W has to be inverted
|
||||
|
||||
--for some reason the scaling has to be broken up, I can't be bothered to figure out why after the time I've spent trying.
|
||||
local identity = mat4.identity()
|
||||
local_transform = local_transform*identity:scale(identity, {scl_vec[1], scl_vec[2], scl_vec[3]})
|
||||
|
||||
--get new global trasnform with the local.
|
||||
if global_transform then
|
||||
global_transform=global_transform*local_transform
|
||||
else
|
||||
global_transform=local_transform
|
||||
end
|
||||
end
|
||||
|
||||
--find the rotation
|
||||
|
||||
if not (outputs and outputs ~= "rotation") then
|
||||
--find the rotation. Please note that modlib's code (in the b3d reader from mtul-b3d-standalone) converts xyzw to wxyz when reading b3ds
|
||||
if not rotation then
|
||||
rotation = quat.new(-rot_vec[1], rot_vec[2], rot_vec[3], rot_vec[4])
|
||||
else
|
||||
rotation = rotation*quat.new(-rot_vec[1], rot_vec[2], rot_vec[3], rot_vec[4])
|
||||
end
|
||||
end
|
||||
end
|
||||
--pos = global_transform:apply({pos[1], pos[2], pos[3], 1})
|
||||
--print(dump(global_transform))
|
||||
--return vector.new(pos[1], pos[2], pos[3])
|
||||
return global_transform
|
||||
--x needs to be inverted (as mentioned earlier.)
|
||||
if global_transform then
|
||||
global_transform[13] = -global_transform[13]
|
||||
end
|
||||
return global_transform, rotation
|
||||
end
|
||||
|
||||
--Returns X, Y, Z. is_bone is optional, if "node" is the name of a node (and not the node table), this is used to find it.
|
||||
function b3d_nodes.get_node_position(self, node, is_bone, frame)
|
||||
--Returns X, Y, Z. is_bone is optional, if "node" is the name of a node (and not the node table), parameter 1 (self) and parameter 3 (is_bone) is used to find it.
|
||||
function b3d_nodes.get_node_global_position(self, node, is_bone, frame)
|
||||
assert(self or not type(node)=="string")
|
||||
if type(node) == "string" then
|
||||
node = b3d_nodes.get_node_by_name(self, node)
|
||||
node = b3d_nodes.get_node_by_name(self, node, is_bone)
|
||||
end
|
||||
local transform = b3d_nodes.get_node_global_transform(node, frame)
|
||||
local transform = b3d_nodes.get_node_global_transform(node, frame, "transform")
|
||||
return transform[13], transform[14], transform[15]
|
||||
end
|
||||
|
||||
--since it's impossible to determine the difference between rotation
|
||||
--and non-uniform scaling, we have to use a different method for this.
|
||||
function b3d_nodes.get_node_rotation()
|
||||
--exactly like get_node_global_position, but it returns a vec3 quaternion.
|
||||
function b3d_nodes.get_node_rotation(self, node, is_bone, frame)
|
||||
assert(self or not type(node)=="string")
|
||||
if type(node) == "string" then
|
||||
node = b3d_nodes.get_node_by_name(self, node, is_bone)
|
||||
end
|
||||
local _, rotation = b3d_nodes.get_node_global_transform(node, frame, "rotation")
|
||||
return rotation
|
||||
end
|
||||
return b3d_nodes
|
Loading…
x
Reference in New Issue
Block a user