Hi. I’ve been working a bit on an import script for a binary model format.
I can now import the meshes with textures, even tho I’m probably mishandling things rather badly.
Next step is probably gonna be importing the skeleton.
To be able to do this, I need some help with deciphering the bone format used in those binary files.
I’ve done a dump of a skeleton and placed it here.
Each line in the file, containing 16 decimal values, is a bone.
Hopefully someone who has a bit more experience with 3d modeling than me can take a look and bring a bit more understanding to the values.
After some experimenting, this code at least gives me valid coordinates for the bones.
data_chunk = file_object.read(64) # Read bone data
m1 = Blender.Mathutils.Vector(struct.unpack_from('<3f', data_chunk)) #values 0-2
m2 = Blender.Mathutils.Vector(struct.unpack_from('<3f', data_chunk,16)) #values 4-6
m3 = Blender.Mathutils.Vector(struct.unpack_from('<3f', data_chunk,32)) #values 8-10
rmat= Blender.Mathutils.Matrix(m1,m2,m3)
pos = rmat*Blender.Mathutils.Vector(struct.unpack_from('<3f', data_chunk,48)) #values 12-14
pos[1]=0-pos[1]
pos[2]=0-pos[2]
The question is, can I get anything more from this, like the length/direction of the bone? (Total noob when it comes to 3d modeling in general, and the blender API in particular).
And yes, this is for blender 2.49 'cause that is what I have.
Having 2.49, does not mean that getting 2.53 is impossible?!
My opinion: only for not yet converted ‘big’ scripts i use 2.49 otherwise 2.53 is preferred!
Gah. Here I was happy that I got a response, and it’s only a comment on the blender version
sigh
Anyone who has any idea how to turn a bone format like this into something blender can understand?
Tell us where the bineray format file of bones comes from, and give us (me) an (mini) example of such a file … (for me only 2.53 …)
I can give you an example of the bone part of the binary format: A link right here in my first post in this topic.
It’s not the binary format, but it’s exactly the same values in text-format, one line per bone.
(My code is of course for the bone part of the binary format, the only difference is in how the data is read in from the file, not the mathematical handling of the bone data)
If you get it to work, you will notice that
- The skeleton is a bit interesting because there are bones not just for the human body, but also for hair, a hair ribbon, and a long skirt (It’s a female character).
- The coordinate system is probably not how blender expects to see it (i.e. wrong axis for ‘Up’.)
Most important question is how to see which bones are connected. I suspect it should be possible to tell the direction from the rotation matrix, but can the bone length be calculated as well? If it can, then we ought to be able to calculate start and end points, and therefore see which bone we end up connected with. If not, then perhaps it will be enough to see if we are on the right direction from a previous bone.
Can we use the matrix (called rmat in my code above) to calculate a direction?
Today no time … thursday … I will search for chreating ‘bones’ with the info …
Realizing: what is with ‘number’ at place 7 and 11 ??? There are 16 numbers per row, interpretation of those is?
I think, you should add, where the info comes from (coming from Blender 2.49?)
No clue really, but from what I can see, positions 3,7,and 11 (starting from zero) always contains 0.0000, and position 15 (the last position) always 1.0000
As always, I have no clue how bones work, which makes trying to understand this particular bone format something of a pain.
I think, you should add, where the info comes from (coming from Blender 2.49?)
http://code.google.com/p/open-pl2/wiki/FileFormatTMB and some further experimenting on my own. I’ve tried mailing the guy who wrote that page and asking if he has any more clues for the bone format beyond the “Bunch of matrices (4x4)”, but haven’t gotten any reply.
Oh that helps, your bones ‘example’ is maybe clear for a 4x4 matrix you need 16 numbers as are in each row!
(tomorrow further)
Is it coming from the ‘japanese’ game … pl2?
Yes. However, I believe I was able to locate another source of info for how the bones are connected to each other, and will most likely just use a list to lookup which bone is the parent of the current bone. This should simplify things a lot.
I still need your help in confirming my earlier findings, namely the 4x4 matrix format.
What I’ve been able to work out through observation and experimentation:
rrr0
rrr0
rrr0
xyz1
Where the ‘r’ values make a rotation matrix, and ‘xyz’ are the (rotated and inverted) xyz coordinates for the end of the bone.
The bone API confuses me, so it would be really helpful seeing code to create bones using this data, connecting each bone to the previous (except the first bone, whose other end is origo). I can then add in an exception list for the bones who should have a different parent myself.
Blender 2.5
Make a bone and subdivide (edit-mode) such that get 5 bones
Look here:
import bpy
b = bpy.context.active_object
bbones = b.pose.bones
for el in bbones: print(el.name)
print(bbones[4].child)
for i in range(len(bbones)):
tmp = [[i,el.child.name] for i, el in enumerate(bbones) if not el.child == None]
print (tmp)
''' printed results:
Bone
Bone.004
Bone.003
Bone.002
Bone.001
None
[[0, 'Bone.004'], [1, 'Bone.003'], [2, 'Bone.002'], [3, 'Bone.001']]
'''
each ‘bone’ has a ‘head’ and a ‘tail’ (3D Vectors!)
So you can easily see who is connected to whom and its place in the 3DView
EDIT
The information about the 16 values is not sufficient.
Not all those many lines (bones) are connected, are they?
The matrix of a ‘bone’ looks like this (in my experiments)
0001
The first 3x3 part is the rotationmatrix(to_3x3) the last column is the translationpart …
parentlink=[0,1,2,3,4,4,6,7,4,4,10,10,4,13,4,15,16,16,15,19,19,4,4,4,24,24,4,27,27,4,30,31,32,30,34,35,30,37,38,30,40,41,42,30,44,45,46,30,48,49,50,51,30,53,54,55,56,4,58,59,60,61,58,63,64,65,58,67,68,69,58,71,72,73,74,4,76,77,76,79,76,76,4,2,84,85,86,87,88,89,87,91,92,87,94,95,87,97,98,87,100,101,85,84,2,105,106,107,108,109,110,108,112,113,108,115,116,108,118,119,108,121,122,106,105,2,126,2,128,2,130,0,132,133,134,135,136,132,138,139,140,141,132,132,132,132,132,147,148,147,150,147,147,147,154,147,156,132,158,159,160,161,162,163,158,165,166,167,168,169,158,171,172,173,174,175,158,177,178,179,180,181,158,183,184,185,186,187,158,189,190,191,192,193]
# skeleton structure for girl body. List starting with bone 1, since bone 0 has no parent.
if index>0: bone[index].parent=bone[parentlink[index-1]]
The matrix of a ‘bone’ looks like this (in my experiments)
0001
The first 3x3 part is the rotationmatrix(to_3x3) the last column is the translationpart …
Are you talking about some sort of ‘standard blender’ bone here?
This looks rather similar to my drawing above, except for being flipped diagonally.
(Not sure what a ‘translationpart’ is supposed to be, tho)
Blender 2.5
Make a bone and subdivide (edit-mode) such that get 5 bones
Look here:
import bpy
b = bpy.context.active_object
bbones = b.pose.bones
for el in bbones: print(el.name)
print(bbones[4].child)
for i in range(len(bbones)):
tmp = [[i,el.child.name] for i, el in enumerate(bbones) if not el.child == None]
print (tmp)
‘’’ printed results:
Bone
Bone.004
Bone.003
Bone.002
Bone.001
None
[[0, ‘Bone.004’], [1, ‘Bone.003’], [2, ‘Bone.002’], [3, ‘Bone.001’]]
‘’’
each 'bone' has a 'head' and a 'tail' (3D Vectors!) So you can easily see who is connected to whom and its place in the 3DView
This code seems like it inspects bones that are already created.
What I’m after is creating the bones programmatically (it is for an import script after all)
Yes, you want to create bones from …
But to eventually succeed, the information of the list has to be known ‘exactly’ …
next days I will go on further with your latest info … (or earlier )
EDIT
from the a text …
import bpy
fp = open("C:/Users/Peter/25Blender/tests/bonestests/bonesinfo.txt","r")
res = fp.read().split('
')
print(res[0])
row0 = res[0].split(" ")
print(row0)
res0f = map(float,row0)
rawlist = []
for el in res0f: rawlist.append(el)
from mathutils import *
print(rawlist)
r0 = [[rawlist[i] for i in range(el,el+4)] for el in range(0,15,4)]
print(r0)
mat = Matrix(r0[0],r0[1],r0[2],r0[3])
print(mat.transpose())
Save your file with the bones info …
This is how to get to the floating point numbers … and further
Not yet totally clear:
The list describes ONE Armature with 195 bones (0 … 194), right?
If I think of spine, arms, legs, head etc, those parts are ‘connected’ what you describe with
the parentlink.
It means, that that list decides indirect which bones are directly (so to say) connected (form the bones of an arm, hand???) ?
Yes, that’s right.
If I think of spine, arms, legs, head etc, those parts are ‘connected’ what you describe with
the parentlink.
It means, that that list decides indirect which bones are directly (so to say) connected (form the bones of an arm, hand???) ?
This list describes/decides which bones are connected together, yes.
I experimented a bit with your last code example, added these lines:
m2=mat.transpose()
rm=m2.rotationPart()
print (rm)
tm=m2.translationPart()
print (tm)
print (rm*tm)
The last 2 prints always gives [0.000000, 0.000000, 0.000000]<Vector>
The trouble here seems to be that .translationPart() (at least for me in 2.49) gets its values from the wrong part of the matrix. Should another function be used instead?
Change to 2.53 SVN >= 31853 !!!
I do not want to learn if and how bones etc. are done in 2.49.
Translating my info to 2.49 is not what I want to do …, sorry.
I use 2.49 only for rather big and very good scripts not yet ported to 2.5* …
Hi FriarTuck,
for your information:
object orientation matrix in Blender looks like this, 4x4:
[
[a,b,c,0], #rotation and scale of X axis relative to parent space
[c,d,e,0], #rotation and scale of y axis relative to parent space
[f,g,h,0], #rotation and scale of Z axis relative to parent space
[x,y,z,1], #translation from 0,0,0 relative to parent space
]
matrix1.translationPart() is is a vector [x,y,z]
matrix1.rotationPart() is is a matrix 3x3:
[
[a,b,c], #rotation and scale of X axis relative to parent space
[c,d,e], #rotation and scale of y axis relative to parent space
[f,g,h], #rotation and scale of Z axis relative to parent space
]
Now THIS is the kind of response I’ve been hoping for This is valid for all versions of blender?
So, the 4x4 matrices in the file format is infact more or less in blender fashion already.
If I leave out mat.transpose() from PKHGs code, the [x,y,z] vector ends up in the right positions.
If I look at the matrix of a bone in Blender 2.54 (!!! since today)
I see this:
Matrix((1.000000, 0.000000, 0.000000, 0.262986), (0.000000, 0.000000, -1.000000, 1.364082), (0.000000, 1.000000, 0.000000, 0.623520), (0.000000, 0.000000, 0.000000, 1.000000))
Meaning it is different! the translation part is on the last column not row!!!
USE this!!! 2.49 will be outdated later or earlier!
if you want to test on 2.49, get this
# routine to import bones from txt file
#input format: lines of 16 floats describing bones orientation matrices
import Blender
from Blender.Mathutils import *
print '
--start----------'
parentlink=[0,1,2,3,4,4,6,7,4,4,10,10,4,13,4,15,16,16,15,19,19,4,4,4,24,24,4,27,27,4,30,31,32,30,
34,35,30,37,38,30,40,41,42,30,44,45,46,30,48,49,50,51,30,53,54,55,56,4,58,59,60,61,58,63,64,
65,58,67,68,69,58,71,72,73,74,4,76,77,76,79,76,76,4,2,84,85,86,87,88,89,87,91,92,87,94,95,87,
97,98,87,100,101,85,84,2,105,106,107,108,109,110,108,112,113,108,115,116,108,118,119,108,
121,122,106,105,2,126,2,128,2,130,0,132,133,134,135,136,132,138,139,140,141,132,132,132,132,
132,147,148,147,150,147,147,147,154,147,156,132,158,159,160,161,162,163,158,165,166,167,168,
169,158,171,172,173,174,175,158,177,178,179,180,181,158,183,184,185,186,187,158,189,190,191,
192,193]
# skeleton structure for girl body. List starting with bone 1, since bone 0 has no parent.
#if index>0: bone[index].parent=bone[parentlink[index-1]]
def read_data(filepath):
fp = open(filepath,"r")
lines = fp.read().split('
')
#print(lines[0])
fp.close()
#raw0 = res[-1].split(" ")
#print(raw0)
raws = []
for nr,line in enumerate(lines):
line_strings = line.split(" ")
if len(line_strings)==16:
raw_floats = map(float,line_strings)
raws.append(raw_floats)
else:
print 'erronous dada in line ', nr
#print 'raws=
', raws
return raws
def get_matrices(raws):
matrices_list = []
for r in raws:
rotXvec = r[:4]
rotYvec = r[4:8]
rotZvec = r[8:12]
locXYZvec = r[12:16]
mat = Matrix(rotXvec,rotYvec,rotZvec,locXYZvec)
matrices_list.append(mat)
#print 'matrices_list=
', matrices_list
return matrices_list
def draw_bones(mat_list, parentlink):
scn = Blender.Scene.GetCurrent()
obj = scn.objects.active
scn.objects.selected = []
obj.sel = 1
mat = mat_list.pop(0) #matrix for root bone
obj.setMatrix(mat)
parents_list = [obj]
for mat, parent_id in zip(mat_list,parentlink):
Blender.Object.Duplicate() # Duplicate selected
parent_obj = parents_list[parent_id]
obj = scn.objects.active
obj.setMatrix(mat)
#maybe this one ? obj.setMatrix(mat * parent_obj.mat)
parents_list.append(obj)
#syntax .makeParent([obj], noninverse=1, fast=0)
#parent_obj.makeParent([obj], 1, 0)
raws = read_data("bones_test1.txt")
mat_list = get_matrices(raws)
draw_bones(mat_list, parentlink)