[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [11508] trunk/blender/release/scripts: * added armature (bones) support to the fbx exporter.

Campbell Barton cbarton at metavr.com
Mon Aug 6 22:20:20 CEST 2007


Revision: 11508
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=11508
Author:   campbellbarton
Date:     2007-08-06 22:20:20 +0200 (Mon, 06 Aug 2007)

Log Message:
-----------
* added armature (bones) support to the fbx exporter. Only rest state, no animation yet.
* fix for PLY from 2.44

Modified Paths:
--------------
    trunk/blender/release/scripts/export_fbx.py
    trunk/blender/release/scripts/ply_import.py

Modified: trunk/blender/release/scripts/export_fbx.py
===================================================================
--- trunk/blender/release/scripts/export_fbx.py	2007-08-06 18:13:08 UTC (rev 11507)
+++ trunk/blender/release/scripts/export_fbx.py	2007-08-06 20:20:20 UTC (rev 11508)
@@ -48,6 +48,41 @@
 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,40 +153,81 @@
 
 
 
+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):
 	
 	def write_object_tx(ob, loc, matrix):
 		'''
 		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']
 			
-			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())
+			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())
+			
+		else:
+			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:
-				rot = tuple(matrix_rot.toEuler())
-		else:
-			if not loc:
-				loc = 0,0,0
-			scale = 1,1,1
-			rot = 0,0,0
+				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)
@@ -190,7 +266,7 @@
 			Property: "TranslationMaxX", "bool", "",0
 			Property: "TranslationMaxY", "bool", "",0
 			Property: "TranslationMaxZ", "bool", "",0
-			Property: "RotationOrder", "enum", "",1
+			Property: "RotationOrder", "enum", "",0
 			Property: "RotationSpaceForLimitOnly", "bool", "",0
 			Property: "AxisLen", "double", "",10
 			Property: "PreRotation", "Vector3D", "",0,0,0
@@ -248,6 +324,25 @@
 		
 		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 @@
 		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 @@
 	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 @@
 					
 					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,7 +853,9 @@
 					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()]
 	materials.sort() # sort by name
@@ -789,8 +892,7 @@
 		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 @@
 		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 @@
 
 Objects:  {''')
 	
+	for obname, ob in ob_bones:
+		write_bone(ob, obname)
+	
+	
 	# To comply with other FBX FILES
 	write_camera_switch()
 	
@@ -1248,6 +1353,10 @@
 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,8 +1404,18 @@
 	# 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)
 	
 	for obname, ob in ob_lights:
 		file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % obname)
@@ -1398,4 +1517,4 @@
 
 if __name__ == '__main__':
 	Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx'))
-	#write_ui('/test.fbx')
+	#write_ui('/scratch/test.fbx')

Modified: trunk/blender/release/scripts/ply_import.py
===================================================================
--- trunk/blender/release/scripts/ply_import.py	2007-08-06 18:13:08 UTC (rev 11507)
+++ trunk/blender/release/scripts/ply_import.py	2007-08-06 20:20:20 UTC (rev 11508)
@@ -199,10 +199,14 @@
 		obj = obj_spec.load(format_specs[format], file)
 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list