* added armature (bones) support to the fbx exporter. Only rest state, no animation yet.

* fix for PLY from 2.44
This commit is contained in:
2007-08-06 20:20:20 +00:00
parent 2e6fd021b8
commit b3eb06f8a9
2 changed files with 162 additions and 39 deletions

View File

@@ -48,6 +48,41 @@ import BPySys
import BPyMessages
import time
from math import degrees, atan, pi
from Blender.Mathutils import Matrix, Vector, Euler, RotationMatrix
# Change the order rotation is applied.
'''
ROT_ORDER = [\
(0,1,2),\
(1,2,0),\
(2,0,1),\
(2,1,0),\
(1,0,2),\
(0,2,1),\
]
MATRIX_IDENTITY_3x3 = Matrix([1,0,0],[0,1,0],[0,0,1])
MATRIX_IDENTITY_4x4 = Matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])
def eulerRotate(x,y,z, rot_order):
# Clamp all values between 0 and 360, values outside this raise an error.
mats=[RotationMatrix(x%360,3,'x'), RotationMatrix(y%360,3,'y'), RotationMatrix(z%360,3,'z')]
# print rot_order
# Standard BVH multiplication order, apply the rotation in the order Z,X,Y
return (mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))).toEuler()
def eulerMat(mat, rot_order):
x,y,z = tuple(mat.toEuler())
# Clamp all values between 0 and 360, values outside this raise an error.
mats=[RotationMatrix(x%360,3,'x'), RotationMatrix(y%360,3,'y'), RotationMatrix(z%360,3,'z')]
# print rot_order
# Standard BVH multiplication order, apply the rotation in the order Z,X,Y
return mats[rot_order[2]]*(mats[rot_order[1]]* (mats[rot_order[0]]* MATRIX_IDENTITY_3x3))
'''
# Used to add the scene name into the filename without using odd chars
sane_name_mapping_ob = {}
@@ -118,6 +153,31 @@ def write_header(file):
mtx_z90 = RotationMatrix(90, 3, 'z')
mtx_x90 = RotationMatrix(90, 3, 'x')
# testing
mtx_x90 = RotationMatrix( 90, 3, 'x')
mtx_x90n = RotationMatrix(-90, 3, 'x')
mtx_y90 = RotationMatrix( 90, 3, 'y')
mtx_y90n = RotationMatrix(-90, 3, 'y')
mtx_z90 = RotationMatrix( 90, 3, 'z')
mtx_z90n = RotationMatrix(-90, 3, 'z')
mtx4_x90 = RotationMatrix( 90, 4, 'x')
mtx4_x90n = RotationMatrix(-90, 4, 'x')
mtx4_y90 = RotationMatrix( 90, 4, 'y')
mtx4_y90n = RotationMatrix(-90, 4, 'y')
mtx4_z90 = RotationMatrix( 90, 4, 'z')
mtx4_z90n = RotationMatrix(-90, 4, 'z')
XVEC = Vector(1, 0, 0)
XVECN = Vector(-1, 0, 0)
YVEC = Vector(0, 1, 0)
YVECN = Vector(0, -1, 0)
ZVEC = Vector(0, 0, 1)
ZVECN = Vector(0, 0, -1)
def write_scene(file, sce, world):
@@ -125,33 +185,49 @@ def write_scene(file, sce, world):
'''
We have loc to set the location if non blender objects that have a location
'''
if ob and not matrix: matrix = ob.matrixWorld
matrix_rot = matrix
#if matrix:
# matrix = matrix_scale * matrix
if matrix:
loc = tuple(matrix.translationPart())
scale = tuple(matrix.scalePart())
if type(ob) == Blender.Types.BoneType:
# we know we have a matrix
matrix = mtx4_z90 * ob.matrix['ARMATURESPACE']
parent = ob.parent
if parent:
par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'].copy()
matrix = matrix * par_matrix.copy().invert()
matrix_rot = matrix.rotationPart()
loc = tuple(matrix.translationPart())
scale = tuple(matrix.scalePart())
rot = tuple(matrix_rot.toEuler())
matrix_rot = matrix.rotationPart()
# Lamps need to be rotated
if ob and ob.type =='Lamp':
matrix_rot = Blender.Mathutils.RotationMatrix(90, 4, 'x') * matrix
rot = tuple(matrix_rot.toEuler())
elif ob and ob.type =='Camera':
y = Blender.Mathutils.Vector(0,1,0) * matrix_rot
matrix_rot = matrix_rot * Blender.Mathutils.RotationMatrix(90, 3, 'r', y)
rot = tuple(matrix_rot.toEuler())
else:
rot = tuple(matrix_rot.toEuler())
else:
if not loc:
loc = 0,0,0
scale = 1,1,1
rot = 0,0,0
if ob and not matrix: matrix = ob.matrixWorld
matrix_rot = matrix
#if matrix:
# matrix = matrix_scale * matrix
if matrix:
loc = tuple(matrix.translationPart())
scale = tuple(matrix.scalePart())
matrix_rot = matrix.rotationPart()
# Lamps need to be rotated
if ob and ob.type =='Lamp':
matrix_rot = mtx_x90 * matrix.rotationPart()
rot = tuple(matrix_rot.toEuler())
elif ob and ob.type =='Camera':
y = Vector(0,1,0) * matrix_rot
matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y)
rot = tuple(matrix_rot.toEuler())
else:
rot = tuple(matrix_rot.toEuler())
else:
if not loc:
loc = 0,0,0
scale = 1,1,1
rot = 0,0,0
# print rot
file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc)
file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot)
file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale)
@@ -248,6 +324,25 @@ def write_scene(file, sce, world):
return loc, rot, scale, matrix, matrix_rot
# -------------------------------------------- Armatures
def write_bone(bone, name):
file.write('\n\tModel: "Model::%s", "Limb" {' % name)
file.write('\n\t\tVersion: 232')
write_object_props(bone)
file.write('\n\t\t\tProperty: "Size", "double", "",100')
file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' % (bone.head['ARMATURESPACE']-bone.tail['ARMATURESPACE']).length)
file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8')
file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
file.write('\n\t\t}')
file.write('\n\t\tMultiLayer: 0')
file.write('\n\t\tMultiTake: 1')
file.write('\n\t\tShading: Y')
file.write('\n\t\tCulling: "CullingOff"')
file.write('\n\t\tTypeFlags: "Skeleton"')
file.write('\n\t}')
def write_camera_switch():
file.write('''
Model: "Model::Camera Switcher", "CameraSwitcher" {
@@ -471,8 +566,8 @@ def write_scene(file, sce, world):
file.write('\n\t\tTypeFlags: "Camera"')
file.write('\n\t\tGeometryVersion: 124')
file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc)
file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Blender.Mathutils.Vector(0,1,0) * matrix_rot) )
file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Blender.Mathutils.Vector(0,0,-1)*matrix_rot) )
file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) )
file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) )
#file.write('\n\t\tUp: 0,0,0' )
#file.write('\n\t\tLookAt: 0,0,0' )
@@ -702,11 +797,12 @@ def write_scene(file, sce, world):
ob_meshes = []
ob_lights = []
ob_cameras = []
ob_bones = [] # in fbx we treat bones as root level objects - be carefull!
materials = {}
textures = {}
armatures = [] # We should export standalone armatures also
armatures_totbones = 0 # we need this because each bone is a model
ob_type = None # incase no objects are exported, so as not to raise an error
ob_type = None # incase no objects are exported, so as not to raise an error
for ob_base in sce.objects.context:
for ob, mtx in BPyObject.getDerivedObjects(ob_base):
#for ob in [ob_base,]:
@@ -740,9 +836,14 @@ def write_scene(file, sce, world):
if arm:
armname = sane_obname(arm)
bones = arm.bones.values()
armatures_totbones += len(bones)
armatures.append((arm, armname, bones))
bones = arm.data.bones.values()
# armatures.append((arm, armname, bones))
# arm_name = BPySys.cleanName(arm.name)
for b in bones:
#name = sane_obname(arm_name + ' ' + b.name)
name = sane_obname(b)
ob_bones.append( (name, b) )
else:
armname = None
@@ -752,6 +853,8 @@ def write_scene(file, sce, world):
ob_meshes.append( (sane_obname(ob), ob, mtx, me, mats, arm, armname) )
del ob_type
#print ob_bones
materials = [(sane_matname(mat), mat) for mat in materials.itervalues()]
textures = [(sane_texname(img), img) for img in textures.itervalues()]
@@ -789,8 +892,7 @@ Definitions: {
len(ob_meshes)+\
len(ob_lights)+\
len(ob_cameras)+\
len(armatures)+\
armatures_totbones+\
len(ob_bones)+\
len(materials)+\
(len(textures)*2))) # add 1 for the root model 1 for global settings
@@ -802,8 +904,7 @@ Definitions: {
len(ob_meshes)+\
len(ob_lights)+\
len(ob_cameras)+\
len(armatures)+\
armatures_totbones)) # add 1 for the root model
len(ob_bones))) # add 1 for the root model
file.write('''
ObjectType: "Geometry" {
@@ -840,6 +941,10 @@ Definitions: {
Objects: {''')
for obname, ob in ob_bones:
write_bone(ob, obname)
# To comply with other FBX FILES
write_camera_switch()
@@ -1248,6 +1353,10 @@ Objects: {''')
Relations: {''')
file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}')
for obname, ob in ob_bones:
file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % obname)
for obname, ob in ob_cameras:
file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % obname)
@@ -1295,6 +1404,16 @@ Connections: {''')
# write the fake root node
file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"')
for obname, ob in ob_bones:
blend_parent = ob.parent
if blend_parent:
file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (obname, sane_obname(blend_parent)) )
else:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
for obname, ob in ob_cameras:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
for obname, ob in ob_cameras:
file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
@@ -1398,4 +1517,4 @@ def write_ui(filename):
if __name__ == '__main__':
Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx'))
#write_ui('/test.fbx')
#write_ui('/scratch/test.fbx')

View File

@@ -199,10 +199,14 @@ def read(filename):
obj = obj_spec.load(format_specs[format], file)
except IOError, (errno, strerror):
file.close()
try: file.close()
except: pass
return None
file.close()
try: file.close()
except: pass
return (obj_spec, obj);