added bone transform reading, interpolation not fully tested
This commit is contained in:
parent
129385c55e
commit
15fff69e75
15
LICENSE
15
LICENSE
@ -1,15 +1,8 @@
|
||||
WARNING, THIS LICENSE DOES NOT AND IS NOT INTENDED TO APPLY FOR FILES WHICH
|
||||
HAVE A "License.md", "LICENSE", "License.txt" "LICENSE.txt" OR ANY FILE NAMED
|
||||
AFTER THE WORD "license" IN THEIR SHARED DIRECTORY;
|
||||
"/modlib/" sub directory: Copright (c) respective owner(s), see the directory
|
||||
for it's respective license (License.txt). Once again note that the "/modlib/"
|
||||
directory in this case is explicitly exempt from the following MIT License.
|
||||
|
||||
IF A FILE IS IN THE SAME DIRECTORY AS A FILE NAMED ANY FORM OF THE WORD LICENSE
|
||||
IN ANY COMBINATION WITH OR WITHOUT AN EXTENSION, THEN SOLEY THAT LICENSE IS TO
|
||||
APPLY TO THOSE FILES.
|
||||
|
||||
IF A DIRECTORY DOES NOT CONTAIN A LICENSE, THE FOLLOWING LICENSE AGREEMENT APPLIES.
|
||||
|
||||
TO BE EXPLICIT, THE "modlib" DIRECTORY HAS IT'S OWN DISTINCT LICENSE AND COPYRIGHT
|
||||
HOLDER. Please see it's own "License.txt"
|
||||
for all other files outside of "/modlib/" directory:
|
||||
|
||||
MIT License
|
||||
|
||||
|
260
b3d_specification.txt
Normal file
260
b3d_specification.txt
Normal file
@ -0,0 +1,260 @@
|
||||
************************************************************************************
|
||||
* Blitz3d file format V0.01 *
|
||||
************************************************************************************
|
||||
|
||||
This document and the information contained within is placed in the Public Domain.
|
||||
|
||||
Please visit http://www.blitzbasic.co.nz for the latest version of this document.
|
||||
|
||||
Please contact marksibly@blitzbasic.co.nz for more information and general inquiries.
|
||||
|
||||
|
||||
|
||||
************************************************************************************
|
||||
* Introduction *
|
||||
************************************************************************************
|
||||
|
||||
The Blitz3D file format specifies a format for storing texture, brush and entity descriptions for
|
||||
use with the Blitz3D programming language.
|
||||
|
||||
The rationale behind the creation of this format is to allow for the generation of much richer and
|
||||
more complex Blitz3D scenes than is possible using established file formats - many of which do not
|
||||
support key features of Blitz3D, and all of which miss out on at least some features!
|
||||
|
||||
A Blitz3D (.b3d) file is split up into a sequence of 'chunks', each of which can contain data
|
||||
and/or other chunks.
|
||||
|
||||
Each chunk is preceded by an eight byte header:
|
||||
|
||||
char tag[4] ;4 byte chunk 'tag'
|
||||
int length ;4 byte chunk length (not including *this* header!)
|
||||
|
||||
If a chunk contains both data and other chunks, the data always appears first and is of a fixed
|
||||
length.
|
||||
|
||||
A file parser should ignore unrecognized chunks.
|
||||
|
||||
Blitz3D files are stored little endian (intel) style.
|
||||
|
||||
Many aspects of the file format are not quite a 'perfect fit' for the way Blitz3D works. This has
|
||||
been done mainly to keep the file format simple, and to make life easier for the authors of third
|
||||
party importers/exporters.
|
||||
|
||||
|
||||
|
||||
************************************************************************************
|
||||
* Chunk Types *
|
||||
************************************************************************************
|
||||
|
||||
This lists the types of chunks that can appear in a b3d file, and the data they contain.
|
||||
|
||||
Color values are always in the range 0 to 1.
|
||||
|
||||
string (char[]) values are 'C' style null terminated strings.
|
||||
|
||||
Quaternions are used to specify general orientations. The first value is the quaternion 'w' value,
|
||||
the next 3 are the quaternion 'vector'. A 'null' rotation should be specified as 1,0,0,0.
|
||||
|
||||
Anything that is referenced 'by index' always appears EARLIER in the file than anything that
|
||||
references it.
|
||||
|
||||
brush_id references can be -1: no brush.
|
||||
|
||||
In the following descriptions, {} is used to signify 'repeating until end of chunk'. Also, a chunk
|
||||
name enclosed in '[]' signifies the chunk is optional.
|
||||
|
||||
Here we go!
|
||||
|
||||
|
||||
BB3D
|
||||
int version ;file format version: default=1
|
||||
[TEXS] ;optional textures chunk
|
||||
[BRUS] ;optional brushes chunk
|
||||
[NODE] ;optional node chunk
|
||||
|
||||
The BB3D chunk appears first in a b3d file, and its length contains the rest of the file.
|
||||
|
||||
Version is in major*100+minor format. To check the version, just divide by 100 and compare it with
|
||||
the major version your software supports, eg:
|
||||
|
||||
if file_version/100>my_version/100
|
||||
RuntimeError "Can't handle this file version!"
|
||||
EndIf
|
||||
|
||||
if file_version Mod 100>my_version Mod 100
|
||||
;file is a more recent version, but should still be backwardly compatbile with what we can
|
||||
handle!
|
||||
EndIf
|
||||
|
||||
|
||||
TEXS
|
||||
{
|
||||
char file[] ;texture file name
|
||||
int flags,blend ;blitz3D TextureFLags and TextureBlend: default=1,2
|
||||
float x_pos,y_pos ;x and y position of texture: default=0,0
|
||||
float x_scale,y_scale ;x and y scale of texture: default=1,1
|
||||
float rotation ;rotation of texture (in radians): default=0
|
||||
}
|
||||
|
||||
The TEXS chunk contains a list of all textures used in the file.
|
||||
|
||||
The flags field value can conditional an additional flag value of '65536'. This is used to indicate that the texture uses secondary UV values, ala the TextureCoords command. Yes, I forgot about this one.
|
||||
|
||||
|
||||
BRUS
|
||||
int n_texs
|
||||
{
|
||||
char name[] ;eg "WATER" - just use texture name by default
|
||||
float red,green,blue,alpha ;Blitz3D Brushcolor and Brushalpha: default=1,1,1,1
|
||||
float shininess ;Blitz3D BrushShininess: default=0
|
||||
int blend,fx ;Blitz3D Brushblend and BrushFX: default=1,0
|
||||
int texture_id[n_texs] ;textures used in brush
|
||||
}
|
||||
|
||||
The BRUS chunk contains a list of all brushes used in the file.
|
||||
|
||||
|
||||
VRTS:
|
||||
int flags ;1=normal values present, 2=rgba values present
|
||||
int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8
|
||||
int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4
|
||||
{
|
||||
float x,y,z ;always present
|
||||
float nx,ny,nz ;vertex normal: present if (flags&1)
|
||||
float red,green,blue,alpha ;vertex color: present if (flags&2)
|
||||
float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords
|
||||
}
|
||||
|
||||
The VRTS chunk contains a list of vertices. The 'flags' value is used to indicate how much extra
|
||||
data (normal/color) is stored with each vertex, and the tex_coord_sets and tex_coord_set_size
|
||||
values describe texture coordinate information stored with each vertex.
|
||||
|
||||
|
||||
TRIS:
|
||||
int brush_id ;brush applied to these TRIs: default=-1
|
||||
{
|
||||
int vertex_id[3] ;vertex indices
|
||||
}
|
||||
|
||||
The TRIS chunk contains a list of triangles that all share a common brush.
|
||||
|
||||
|
||||
MESH:
|
||||
int brush_id ;'master' brush: default=-1
|
||||
VRTS ;vertices
|
||||
TRIS[,TRIS...] ;1 or more sets of triangles
|
||||
|
||||
The MESH chunk describes a mesh. A mesh only has one VRTS chunk, but potentially many TRIS chunks.
|
||||
|
||||
|
||||
BONE:
|
||||
{
|
||||
int vertex_id ;vertex affected by this bone
|
||||
float weight ;how much the vertex is affected
|
||||
}
|
||||
|
||||
The BONE chunk describes a bone. Weights are applied to the mesh described in the enclosing ANIM -
|
||||
in 99% of cases, this will simply be the MESH contained in the root NODE chunk.
|
||||
|
||||
|
||||
KEYS:
|
||||
int flags ;1=position, 2=scale, 4=rotation
|
||||
{
|
||||
int frame ;where key occurs
|
||||
float position[3] ;present if (flags&1)
|
||||
float scale[3] ;present if (flags&2)
|
||||
float rotation[4] ;present if (flags&4)
|
||||
}
|
||||
|
||||
The KEYS chunk is a list of animation keys. The 'flags' value describes what kind of animation
|
||||
info is stored in the chunk - position, scale, rotation, or any combination of.
|
||||
|
||||
|
||||
ANIM:
|
||||
int flags ;unused: default=0
|
||||
int frames ;how many frames in anim
|
||||
float fps ;default=60
|
||||
|
||||
The ANIM chunk describes an animation.
|
||||
|
||||
|
||||
NODE:
|
||||
char name[] ;name of node
|
||||
float position[3] ;local...
|
||||
float scale[3] ;coord...
|
||||
float rotation[4] ;system...
|
||||
[MESH|BONE] ;what 'kind' of node this is - if unrecognized, just use a Blitz3D
|
||||
pivot.
|
||||
[KEYS[,KEYS...]] ;optional animation keys
|
||||
[NODE[,NODE...]] ;optional child nodes
|
||||
[ANIM] ;optional animation
|
||||
|
||||
The NODE chunk describes a Blitz3D Entity. The scene hierarchy is expressed by the nesting of NODE
|
||||
chunks.
|
||||
|
||||
NODE kinds are currently mutually exclusive - ie: a node can be a MESH, or a BONE, but not both!
|
||||
However, it can be neither...if no kind is specified, the node is just a 'null' node - in Blitz3D
|
||||
speak, a pivot.
|
||||
|
||||
The presence of an ANIM chunk in a NODE indicates that an animation starts here in the hierarchy.
|
||||
This allows animations of differing speeds/lengths to be potentially nested.
|
||||
|
||||
There are many more 'kind' chunks coming, including camera, light, sprite, plane etc. For now, the
|
||||
use of a Pivot in cases where the node kind is unknown will allow for backward compatibility.
|
||||
|
||||
|
||||
|
||||
************************************************************************************
|
||||
* Examples *
|
||||
************************************************************************************
|
||||
|
||||
A typical b3d file will contain 1 TEXS chunk, 1 BRUS chunk and 1 NODE chunk, like this:
|
||||
|
||||
BB3D
|
||||
1
|
||||
TEXS
|
||||
...list of textures...
|
||||
BRUS
|
||||
...list of brushes...
|
||||
NODE
|
||||
...stuff in the node...
|
||||
|
||||
A simple, non-animating, non-textured etc mesh might look like this:
|
||||
|
||||
BB3D
|
||||
1 ;version
|
||||
NODE
|
||||
"root_node" ;node name
|
||||
0,0,0 ;position
|
||||
1,1,1 ;scale
|
||||
1,0,0,0 ;rotation
|
||||
MESH ;the mesh
|
||||
-1 ;brush: no brush
|
||||
VRTS ;vertices in the mesh
|
||||
0 ;no normal/color info in verts
|
||||
0,0 ;no texture coords in verts
|
||||
{x,y,z...} ;vertex coordinates
|
||||
TRIS ;triangles in the mesh
|
||||
-1 ;no brush for this triangle
|
||||
{v0,v1,v2...} ;vertices
|
||||
|
||||
|
||||
A more complex 'skinned mesh' might look like this (only chunks shown):
|
||||
|
||||
BB3D
|
||||
TEXS ;texture list
|
||||
BRUS ;brush list
|
||||
NODE ;root node
|
||||
MESH ;mesh - the 'skin'
|
||||
ANIM ;anim
|
||||
NODE ;first child of root node - eg: "pelvis"
|
||||
BONE ;vertex weights for pelvis
|
||||
KEYS ;anim keys for pelvis
|
||||
NODE ;first child of pelvis - eg: "left-thigh"
|
||||
BONE ;bone
|
||||
KEYS ;anim keys for left-thigh
|
||||
NODE ;second child of pelvis - eg: "right-thigh"
|
||||
BONE ;vertex weights for right-thigh
|
||||
KEYS ;anim keys for right-thigh
|
||||
|
||||
...and so on.
|
26
init.lua
26
init.lua
@ -1,12 +1,32 @@
|
||||
|
||||
--[[
|
||||
this library provides two modules:
|
||||
b3d
|
||||
b3d_nodes
|
||||
|
||||
b3d_nodes is for reading and interperetting b3d objects from the b3d module.
|
||||
the b3d module is a heavily modified version of Modlib's b3d reader, and as such
|
||||
has it's own respective directory for licensing purposes.
|
||||
]]
|
||||
|
||||
mtul.b3d = {}
|
||||
mtul.loaded_modules.b3d = true
|
||||
|
||||
local modpath = minetest.get_modpath("mtul_b3d")
|
||||
--placed in a seperate directory for the license
|
||||
dofile(modpath.."/modlib/read_b3d.lua")
|
||||
dofile(modpath.."/modlib/write_b3d.lua") --this is untested, could be very broken.
|
||||
--these modules are disabled, refactoring is needed.
|
||||
if mtul.math.cpml_loaded then
|
||||
dofile(modpath.."/read_b3d_bone")
|
||||
|
||||
--prevent accidental access of unavailable features:
|
||||
if mtul.loaded_modules.cpml then
|
||||
mtul.b3d_nodes = dofile(modpath.."/nodes.lua")
|
||||
mtul.loaded_modules.b3d_nodes = true
|
||||
else
|
||||
mtul.b3d_nodes = {}
|
||||
setmetatable(mtul.b3d_nodes, {
|
||||
__index = function()
|
||||
error("MTUL-CPML not present, b3d_nodes module inaccessible.")
|
||||
end
|
||||
})
|
||||
end
|
||||
--dofile(modpath.."/read_b3d_bone.lua"
|
@ -1,12 +1,61 @@
|
||||
|
||||
--this reader has been heavily modified to implement additional needed features.
|
||||
--implementations include:
|
||||
|
||||
--mtul.b3d.read_model()
|
||||
--ignore_chunks parameter,
|
||||
--node.parent,
|
||||
--node.path
|
||||
--b3d.node_paths
|
||||
|
||||
-- Localize globals
|
||||
local read_int, read_single = mtul.binary.read_int, mtul.binary.read_single
|
||||
--+ Reads a single BB3D chunk from a stream
|
||||
--+ Doing `assert(stream:read(1) == nil)` afterwards is recommended
|
||||
--+ See `b3d_specification.txt` as well as https://github.com/blitz-research/blitz3d/blob/master/blitz3d/loader_b3d.cpp
|
||||
--> B3D model
|
||||
function mtul.b3d.read(stream)
|
||||
|
||||
--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]
|
||||
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()
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
--"ignore_chunks" is a list of chunks to ignore when reading- as for various applications it may be uncessary or otherwise redundant
|
||||
--note that this does not increase runtime spead as chunks still must be read before we know what they are (currently)
|
||||
--chunk types: "BB3D", "TEXS", "BRUS", "TRIS", "MESH", "BONE", "ANIM", "KEYS", "VRTS", "NODE"
|
||||
--this specifies what chunks can be found inside eachother
|
||||
--MESH subtypes: VRTS, TRIS
|
||||
--BB3D subtypes: TEXS, NODE
|
||||
--NODE subtypes: KEYS, ANIM, NODE, BONE, MESH
|
||||
|
||||
--node_paths is a table of nodes indexed by a table containing a hierarchal list of nodes to get to that node (including itself).
|
||||
--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.
|
||||
|
||||
function mtul.b3d.read_from_stream(stream, ignore_chunks)
|
||||
local left = 8
|
||||
|
||||
local ignored = {}
|
||||
if ignore_chunks then
|
||||
for i, v in pairs(ignore_chunks) do
|
||||
ignored[v] = true
|
||||
end
|
||||
assert(not ignored.BB3D, "reader cannot not ignore entire model. (ignore_chunks contained BB3D)")
|
||||
assert(not ignored.NODE, "reader cannot not ignore entire model. (ignore_chunks contained NODE)")
|
||||
end
|
||||
local function byte()
|
||||
left = left - 1
|
||||
return assert(stream:read(1):byte())
|
||||
@ -80,6 +129,10 @@ function mtul.b3d.read(stream)
|
||||
return left ~= 0
|
||||
end
|
||||
|
||||
local node_chunk_types = {
|
||||
|
||||
}
|
||||
|
||||
local chunk
|
||||
local chunks = {
|
||||
TEXS = function()
|
||||
@ -220,7 +273,9 @@ function mtul.b3d.read(stream)
|
||||
node.name = string()
|
||||
node.position = vector3()
|
||||
node.scale = vector3()
|
||||
node.keys = {}
|
||||
if not ignored.KEYS then
|
||||
node.keys = {}
|
||||
end
|
||||
node.rotation = quaternion()
|
||||
node.children = {}
|
||||
local node_type
|
||||
@ -228,25 +283,30 @@ function mtul.b3d.read(stream)
|
||||
-- Order is not validated; double occurrences of mutually exclusive node def are
|
||||
while content() do
|
||||
local elem, type = chunk()
|
||||
if type == "MESH" then
|
||||
assert(not node_type)
|
||||
node_type = "mesh"
|
||||
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
|
||||
table.insert(node.children, elem)
|
||||
elseif type == "ANIM" then
|
||||
node.animation = elem
|
||||
else
|
||||
assert(not node_type)
|
||||
node_type = "pivot"
|
||||
if not ignored[type] then
|
||||
if type == "MESH" then
|
||||
assert(not node_type)
|
||||
node_type = "mesh"
|
||||
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
|
||||
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
|
||||
-- Ensure frames are sorted ascendingly
|
||||
table.sort(node.keys, function(a, b)
|
||||
assert(a.frame ~= b.frame, "duplicate frame")
|
||||
@ -261,18 +321,20 @@ function mtul.b3d.read(stream)
|
||||
major = math.floor(version / 100),
|
||||
minor = version % 100,
|
||||
},
|
||||
textures = {},
|
||||
brushes = {}
|
||||
}
|
||||
if not ignored.TEXS then self.textures = {} end
|
||||
if not ignored.BRUS then self.brushes = {} end
|
||||
assert(self.version.major <= 2, "unsupported version: " .. self.version.major)
|
||||
while content() do
|
||||
local field, type = chunk{TEXS = true, BRUS = true, NODE = true}
|
||||
if type == "TEXS" then
|
||||
mtul.tbl.append(self.textures, field)
|
||||
elseif type == "BRUS" then
|
||||
mtul.tbl.append(self.brushes, field)
|
||||
else
|
||||
self.node = field
|
||||
if not ignored[type] then
|
||||
if type == "TEXS" then
|
||||
mtul.tbl.append(self.textures, field)
|
||||
elseif type == "BRUS" then
|
||||
mtul.tbl.append(self.brushes, field)
|
||||
else
|
||||
self.node = field
|
||||
end
|
||||
end
|
||||
end
|
||||
return self
|
||||
@ -297,6 +359,32 @@ function mtul.b3d.read(stream)
|
||||
return res, type
|
||||
end
|
||||
|
||||
--due to the nature of how the b3d is read, paths have to be built by recursively iterating the table in post.
|
||||
--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)
|
||||
local copy_path = mtul.table and mtul.table.shallow_copy or function(tbl)
|
||||
local new_table = {}
|
||||
for i, v in pairs(tbl) do
|
||||
new_table[i] = v
|
||||
end
|
||||
return new_table
|
||||
end
|
||||
local function make_paths(node, path, node_paths)
|
||||
local new_path = copy_path(path)
|
||||
table.insert(new_path, node)
|
||||
node_paths[new_path] = node --this will create a list of paths
|
||||
for i, next_node in pairs(node.children) do
|
||||
make_paths(next_node, new_path, node_paths)
|
||||
end
|
||||
node.path = new_path
|
||||
end
|
||||
|
||||
local self = chunk{BB3D = true}
|
||||
return setmetatable(self, mtul.b3d)
|
||||
self.node_paths = {}
|
||||
make_paths(self.node, {}, self.node_paths)
|
||||
|
||||
--b3d metatable unimplemented
|
||||
return setmetatable(self, mtul._b3d_metatable or {})
|
||||
end
|
100
nodes.lua
Normal file
100
nodes.lua
Normal file
@ -0,0 +1,100 @@
|
||||
--gets node by name
|
||||
--this breaks if you have multiple nodes with the same name.
|
||||
--if there are meshes that go by the same name, you can set "bone" param to true.
|
||||
local b3d_nodes = {}
|
||||
function b3d_nodes.get_node_by_name(self, node_name, is_bone)
|
||||
for i, this_node in pairs(self.node_paths) do
|
||||
if ( (not is_bone) or (this_node.type=="bone") ) and (this_node.name == node_name) then
|
||||
return this_node
|
||||
end
|
||||
end
|
||||
error("MTUL-b3d, b3d_nodes: no node found by the name '"..node_name.."'")
|
||||
end
|
||||
|
||||
--non-methods:
|
||||
local interpolate = function(a, b, ratio)
|
||||
local out = {}
|
||||
for i, v in pairs(a) do
|
||||
out[i] = a[i]-((a[i]-b[i])*ratio)
|
||||
end
|
||||
return out
|
||||
end
|
||||
function b3d_nodes.get_animated_local_transform(node, target_frame)
|
||||
local frames = node.keys
|
||||
local key_index_before = 0 --index of the key before the target_frame.
|
||||
for i, key in ipairs(frames) do
|
||||
--pick the closest frame we find that's less then the target
|
||||
if key.frame < target_frame then
|
||||
key_index_before = i
|
||||
else
|
||||
break --we've reached the end of our possible frames to use.
|
||||
end
|
||||
end
|
||||
--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.
|
||||
end
|
||||
--no point in interpolating if it's all the same...
|
||||
if frame_after_tbl then
|
||||
local f1 = frame_before_tbl.frame or -1
|
||||
local f2 = frame_after_tbl.frame --if there's no frame after that then
|
||||
local ratio = (f1-target_frame)/(f1-f2) --find the interpolation ratio
|
||||
return
|
||||
interpolate(frame_before_tbl.position, frame_after_tbl.position, ratio),
|
||||
interpolate(frame_before_tbl.rotation, frame_after_tbl.rotation, ratio),
|
||||
interpolate(frame_before_tbl.scale, frame_after_tbl.scale, ratio)
|
||||
else
|
||||
return
|
||||
table.copy(frame_before_tbl.position),
|
||||
table.copy(frame_before_tbl.rotation),
|
||||
table.copy(frame_before_tbl.scale)
|
||||
end
|
||||
end
|
||||
local mat4 = mtul.math.mat4
|
||||
local quat = mtul.math.quat
|
||||
function b3d_nodes.get_node_global_transform(node, frame)
|
||||
local global_transform
|
||||
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
|
||||
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
|
||||
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)
|
||||
if type(node) == "string" then
|
||||
node = b3d_nodes.get_node_by_name(self, node)
|
||||
end
|
||||
local transform = b3d_nodes.get_node_global_transform(node, frame)
|
||||
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()
|
||||
end
|
||||
return b3d_nodes
|
@ -1,14 +0,0 @@
|
||||
|
||||
|
||||
--INACTIVE FILE
|
||||
|
||||
|
||||
local binary_search_frame = modlib.table.binary_search_comparator(function(a, b)
|
||||
return modlib.table.default_comparator(a, b.frame)
|
||||
end)
|
||||
|
||||
--> list of { bone_name = string, parent_bone_name = string, position = vector, rotation = quaternion, scale = vector }
|
||||
function mtul.b3d:get_bone_global_transform(self, node_name)
|
||||
|
||||
end
|
||||
function mtul.b3d:get_bone
|
Loading…
x
Reference in New Issue
Block a user