[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [11525] trunk/blender: Mesh. c - getVertFromGroup ~25% speedup.

Campbell Barton cbarton at metavr.com
Thu Aug 9 15:34:45 CEST 2007


Revision: 11525
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=11525
Author:   campbellbarton
Date:     2007-08-09 15:34:44 +0200 (Thu, 09 Aug 2007)

Log Message:
-----------
Mesh.c - getVertFromGroup ~25% speedup.
export_fbx.py - initial support for bones applied to weighted meshes.

Modified Paths:
--------------
    trunk/blender/release/scripts/export_fbx.py
    trunk/blender/source/blender/python/api2_2x/Mesh.c

Modified: trunk/blender/release/scripts/export_fbx.py
===================================================================
--- trunk/blender/release/scripts/export_fbx.py	2007-08-09 09:09:25 UTC (rev 11524)
+++ trunk/blender/release/scripts/export_fbx.py	2007-08-09 13:34:44 UTC (rev 11525)
@@ -92,6 +92,7 @@
 def strip_path(p):
 	return p.split('\\')[-1].split('/')[-1]
 
+# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up.
 def sane_name(data, dct):
 	if not data: return None
 	name = data.name
@@ -107,6 +108,9 @@
 def sane_matname(data):		return sane_name(data, sane_name_mapping_mat)
 def sane_texname(data):		return sane_name(data, sane_name_mapping_tex)
 
+def mat4x4str(mat):
+	return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ])
+	
 # May use this later
 """
 # Auto class, use for datastorage only, a like a dictionary but with limited slots
@@ -181,17 +185,18 @@
 
 def write_scene(file, sce, world):
 	
-	def write_object_tx(ob, loc, matrix):
+	def object_tx(ob, loc, matrix, matrix_mod = None):
 		'''
-		We have loc to set the location if non blender objects that have a location
+		Matrix mod is so armature objects can modify their bone matricies
 		'''
-		if type(ob) == Blender.Types.BoneType:
+		if isinstance(ob, Blender.Types.BoneType):
+			
 			# we know we have a matrix
-			matrix = mtx4_z90 * ob.matrix['ARMATURESPACE']
+			matrix = mtx4_z90 * (matrix_mod * ob.matrix['ARMATURESPACE'])
 			
 			parent = ob.parent
 			if parent:
-				par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'].copy()
+				par_matrix = mtx4_z90 * (matrix_mod * parent.matrix['ARMATURESPACE'].copy())
 				matrix = matrix * par_matrix.copy().invert()
 				
 			matrix_rot =	matrix.rotationPart()
@@ -227,13 +232,23 @@
 				scale = 1,1,1
 				rot = 0,0,0
 		
+		return loc, rot, scale, matrix, matrix_rot
+	
+	def write_object_tx(ob, loc, matrix, matrix_mod= None):
+		'''
+		We have loc to set the location if non blender objects that have a location
+		
+		matrix_mod is only used for bones at the moment
+		'''
+		loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod)
+		
 		# 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)
 		return loc, rot, scale, matrix, matrix_rot
 	
-	def write_object_props(ob=None, loc=None, matrix=None):
+	def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None):
 		# if the type is 0 its an empty otherwise its a mesh
 		# only difference at the moment is one has a color
 		file.write('''
@@ -241,7 +256,7 @@
 			Property: "QuaternionInterpolate", "bool", "",0
 			Property: "Visibility", "Visibility", "A+",1''')
 		
-		loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix)
+		loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod)
 		
 		# Rotation order
 		# eEULER_XYZ
@@ -316,7 +331,7 @@
 			Property: "Show", "bool", "",1
 			Property: "NegativePercentShapeSupport", "bool", "",1
 			Property: "DefaultAttributeIndex", "int", "",0''')
-		if ob:
+		if ob and type(ob) != Blender.Types.BoneType:
 			# Only mesh objects have color 
 			file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
 			file.write('\n\t\t\tProperty: "Size", "double", "",100')
@@ -326,13 +341,16 @@
 	
 	
 	# -------------------------------------------- Armatures
-	def write_bone(bone, name):
-		file.write('\n\tModel: "Model::%s", "Limb" {' % name)
+	def write_bone(bone, name, matrix_mod):
+		file.write('\n\tModel: "Model::%s", "LimbNode" {' % 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)
+		write_object_props(bone, None, None, matrix_mod)
+		
+		file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % (bone.head['ARMATURESPACE']-bone.tail['ARMATURESPACE']).length)
+		#file.write('\n\t\t\tProperty: "Size", "double", "",1')
+		#file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' % (bone.head['ARMATURESPACE']-bone.tail['ARMATURESPACE']).length)
+		file.write('\n\t\t\tProperty: "LimbLength", "double", "",1')
 		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}')
@@ -634,13 +652,30 @@
 		file.write('\n\t\tGeometryVersion: 124')
 		file.write('\n\t}')
 	
+	def write_null(ob, name):
+		# ob can be null
+		file.write('\n\tModel: "Model::%s", "Null" {' % name)
+		file.write('\n\t\tVersion: 232')
+		write_object_props(ob)
+		file.write('''
+		}
+		MultiLayer: 0
+		MultiTake: 1
+		Shading: Y
+		Culling: "CullingOff"
+		TypeFlags: "Null"
+	}''')
+		
+		
+	
+	
+	
 	# Material Settings
 	if world:
 		world_amb = world.getAmb()
 	else:
 		world_amb = (0,0,0) # Default value
 	
-	
 	def write_material(matname, mat):
 		file.write('\n\tMaterial: "Material::%s", "" {' % matname)
 		
@@ -794,10 +829,81 @@
 		Cropping: 0,0,0,0
 	}''')
 	
+	
+	def write_deformer_skin(obname):
+		file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname)
+		file.write('''
+	Version: 100
+		MultiLayer: 0
+		Type: "Skin"
+		Properties60:  {
+		}
+		Link_DeformAcuracy: 50
+	}''')
+	
+	# in the example was 'Bip01 L Thigh_2'
+	def write_sub_deformer_skin(obname, group_name, bone, me):
+		file.write('\n\tDeformer: "SubDeformer::Cluster %s", "Cluster" {' % group_name)
+		file.write('''
+		Version: 100
+		MultiLayer: 0
+		Type: "Cluster"
+		Properties60:  {
+			Property: "SrcModel", "object", ""
+			Property: "SrcModelReference", "object", ""
+		}
+		UserData: "", ""''')
+		
+		try:
+			vgroup_data = me.getVertsFromGroup(bone.name, 1)
+		except:
+			vgroup_data = []
+		
+		file.write('\n\t\tIndexes: ')
+		
+		i = -1
+		for vg in vgroup_data:
+			if i == -1:
+				file.write('%i'  % vg[0])
+				i=0
+			else:
+				if i==38:
+					file.write('\n\t\t')
+					i=0
+				file.write(',%i' % vg[0])
+			i+=1
+		
+		file.write('\n\t\tWeights: ')
+		i = -1
+		for vg in vgroup_data:
+			if i == -1:
+				file.write('%.8f'  % vg[1])
+				i=0
+			else:
+				if i==38:
+					file.write('\n\t\t')
+					i=0
+				file.write(',%.8f' % vg[1])
+			i+=1
+		
+		m = mtx4_z90 * bone.matrix['ARMATURESPACE']
+		matstr = mat4x4str(m)
+		matstr_i = mat4x4str(m.invert())
+		#matstr = mat4x4str(Matrix())
+		
+		# It seems fine to have these matricies the same! - worldspace bone or pose locations?
+		file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/
+		file.write('\n\t\tTransformLink: %s' % matstr)
+		file.write('\n\t}')
+	
 	ob_meshes = []
 	ob_lights = []
 	ob_cameras = []
-	ob_bones = [] # in fbx we treat bones as root level objects - be carefull!
+	# in fbx we export bones as children of the mesh
+	# armatures not a part of a mesh, will be added to ob_arms
+	ob_bones = [] 
+	ob_arms = []
+	ob_null = [] # emptys
 	materials = {}
 	textures = {}
 	
@@ -811,7 +917,11 @@
 				ob_cameras.append((sane_obname(ob), ob))
 			elif ob_type == 'Lamp':
 				ob_lights.append((sane_obname(ob), ob))
-			
+			elif ob_type == 'Armature':
+				#ob_arms.append(sane_obname(ob), ob)
+				ob_arms.append(ob) # replace later.
+			elif ob_type == 'Empty':
+				ob_null.append((sane_obname(ob), ob))
 			else:
 				if ob_type == 'Mesh':	me = ob.getData(mesh=1)
 				else:					me = BPyMesh.getMeshFromObject(ob)
@@ -832,30 +942,45 @@
 							
 							me.activeUVLayer = uvlayer_orig
 					
-					arm = BPyObject.getObjectArmature(ob)
+					obname = sane_obname(ob)
 					
-					if arm:
-						armname = sane_obname(arm)
-						bones = arm.data.bones.values()
+					armob = BPyObject.getObjectArmature(ob)
+					
+					if armob:
+						armname = sane_obname(armob)
+						bones = armob.data.bones.values()
 						# armatures.append((arm, armname, bones))
 						# arm_name = BPySys.cleanName(arm.name)
 						
-						for b in bones:
+						for bone in bones:
 							#name = sane_obname(arm_name + ' ' + b.name)
-							name = sane_obname(b)
-							ob_bones.append( (name, b) )
+							ob_bones.append( (sane_obname(bone), bone, obname, me, armob) )
 					else:
 						armname = None
 					
 					#### me.transform(ob.matrixWorld) # Export real ob coords.
 					#### High Quality, not realy needed for now.
 					#BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
-					ob_meshes.append( (sane_obname(ob), ob, mtx, me, mats, arm, armname) )
+					ob_meshes.append( (obname, ob, mtx, me, mats, armob, armname) )
 	
 	del ob_type
 	#print ob_bones
 	
 	
+	# this sucks a bit, remove all armatures that are used by a mesh.
+	for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
+		if arm:
+			try:	ob_arms.remove(arm)
+			except:	pass
+	
+	# now we have removed, get the unique names
+	for i, ob in enumerate(ob_arms):
+		name = sane_obname(ob)
+		ob_arms[i] = name, ob
+		
+		for bone in ob.data.bones.values():
+			ob_bones.append( (sane_obname(bone), bone, name, None, ob) )
+	
 	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
@@ -892,6 +1017,8 @@
 		len(ob_meshes)+\
 		len(ob_lights)+\
 		len(ob_cameras)+\
+		len(ob_arms)+\
+		len(ob_null)+\
 		len(ob_bones)+\
 		len(materials)+\
 		(len(textures)*2))) # add 1 for the root model 1 for global settings
@@ -904,6 +1031,8 @@
 		len(ob_meshes)+\
 		len(ob_lights)+\
 		len(ob_cameras)+\
+		len(ob_arms)+\
+		len(ob_null)+\
 		len(ob_bones))) # add 1 for the root model
 	
 	file.write('''
@@ -927,42 +1056,55 @@
 		Count: %i
 	}''' % len(textures)) # add 1 for an empty tex
 	
+	tmp = 0
+	for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
+		if armname:
+			tmp+=1
+	
+	for bonename, bone, obname, me, armob in ob_bones:
+		if me:
+			tmp += 1
+	
+	if tmp:
+		file.write('''
+	ObjectType: "Deformer" {
+		Count: %i
+	}''' % tmp)
+	del tmp
+	
+	# we could avoid writing this possibly but for now just write it
+	"""
 	file.write('''
+	ObjectType: "Pose" {
+		Count: 1
+	}''')
+	"""
+	
+	file.write('''
 	ObjectType: "GlobalSettings" {
 		Count: 1
 	}
-}
-''')
+}''')
 	
-	file.write(\
-'''
+	file.write('''
+

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list