Преглед на файлове

Re-writing the mesh.py to automaticaly cat the mesh in UV seams

Panagiotis Christopoulos Charitos преди 15 години
родител
ревизия
6b9c78b937
променени са 1 файла, в които са добавени 191 реда и са изтрити 227 реда
  1. 191 227
      blenderscripts/mesh.py

+ 191 - 227
blenderscripts/mesh.py

@@ -1,295 +1,259 @@
 import sys
-from common import *
-reload( sys.modules["common"] )
+from copy import copy
+from Blender import Mathutils
+from Blender.Mathutils import *
+from Numeric import *
 
 
-#===================================================================================================
-# mesh_init_t                                                                                      =
-#===================================================================================================
-class mesh_init_t:
-	mesh = NULL
-	skeleton = NULL
-	material_filename = "*put material filename*"
-	write_comments = false
-	save_path = ""
+#=======================================================================================================================
+# MeshInitializer                                                                                                      =
+#=======================================================================================================================
+class MeshInitializer:
+	blMesh = 0  # Blender Mesh
+	blSkeleton = 0 # Blender Armature
+	mtlName = "" # Material name
+	saveDir = "" # the name of the saved file
 	
 
-#===================================================================================================
-# GetMesh                                                                                          =
-#===================================================================================================
-def GetMesh( obj ):
-	if( obj.__class__.__name__ != "Blender Object" ):
-		ERROR( "The given func param is not a \"Blender Object\" class but a \"" + obj.__class__.__name__ + "\"" )
-		return 0
+#=======================================================================================================================
+# Vert                                                                                                                 =
+#=======================================================================================================================
+class Vert:
+	x = 0.0
+	y = 0.0
+	z = 0.0
+	s = 0.0
+	t = 0.0
+	nextId = -1 # shows the next vertId. Is != -1 if the vert is problematic
+
+
+#=======================================================================================================================
+# Tri                                                                                                                  =
+#=======================================================================================================================
+class Tri:
+	vertIds[3]
+
+
+#=======================================================================================================================
+# getBlMeshFromBlObj                                                                                                   =
+#=======================================================================================================================
+def getBlMeshFromBlObj(obj):
+	if(obj.__class__.__name__ != "Blender Object"):
+		raise RuntimeError("The given func param is not a \"Blender Object\" class but a \"" + obj.__class__.__name__ + "\"")
 	
 	if obj.getType() != "Mesh": 
-		ERROR( "The obj \"" + obj.getName() + "\" must link to a mesh and not to a(n) " + obj.getType() )
-		return 0
+		raise RuntimeError("The obj \"" + obj.getName() + "\" must link to a mesh and not to a(n) " + obj.getType())
 
-	mesh = obj.getData( 0, 1 ) 
+	mesh = obj.getData(0, 1) 
 	return mesh
 
 
-#===================================================================================================
-# ScriptVWeights                                                                                   =
-#===================================================================================================
-def ScriptVWeights( mesh_init ):
-	mesh = mesh_init.mesh
-	skeleton = mesh_init.skeleton
-	b_cmnts = mesh_init.write_comments
-
-	#check if mesh is the correct class
-	if( mesh.__class__.__name__ != "Blender Mesh" ):
-		ERROR( "The given func param is not a \"Blender Mesh\" class but a \"" + mesh.__class__.__name__ + "\"" )
-		return "error"
-	
-	#check if skeleton is the correct class
-	if( skeleton.__class__.__name__ != "Armature" ):
-		ERROR( "The given func param is not a \"Armature\" class but a \"" + skeleton.__class__.__name__ + "\"" )
-		return "error"
-	
-	bone_names = skeleton.bones.keys()
-	bone_names.sort()
+#=======================================================================================================================
+# getAnkiVertWeights                                                                                                   =
+#=======================================================================================================================
+def getAnkiVertWeights(mesh, skeleton):
+	boneNames = skeleton.bones.keys()
+	boneNames.sort()
 	
 	# init text
 	ftxt = ""
 	
 	# link the vert groups to the bone ids
-	vgroup2bone_id = {}   # we give the vgroup name and we get the bone's id in the skeleton
-	vgroup_names = mesh.getVertGroupNames()
+	vgroup2boneId = {}   # we give the vgroup name and we get the bone's id in the skeleton
+	vgroupNames = mesh.getVertGroupNames()
 	
-	for vgroup_name in vgroup_names:
-		bone_id = -1
-		for bone_name in bone_names:
-			if bone_name == vgroup_name:
-				bone_id = bone_names.index( bone_name )
+	for vgroupName in vgroupNames:
+		boneId = -1
+		for boneName in boneNames:
+			if boneName == vgroupName:
+				boneId = boneNames.index(boneName)
 				break
 		
-		if bone_id == -1:
-			WARNING( "Vert group \"" + vgroup_name + "\" cant link to a bone" )
+		if boneId == -1:
+			print("Vert group \"" + vgroupName + "\" cant link to a bone")
 		
-		vgroup2bone_id[ vgroup_name ] = bone_id
-	
-	if( b_cmnts ):ftxt += "/*VERT_WEIGHTS*/ "
-	ftxt += str( len( mesh.verts ) ) + "\n"
+		vgroup2boneId[vgroupName] = boneId
+
+
+	# vert weights num
+	ftxt += str(len(mesh.verts)) + "\n"
 	
 	# for every vert do some shit
 	for vert in mesh.verts:
-		influences = mesh.getVertexInfluences( vert.index )
+		influences = mesh.getVertexInfluences(vert.index)
 		
-		influences_num = 0
+		influencesNum = 0
 		sumw = 0.0
-		# calc the influences num and the total weight (NOTE:we may have...
-		# ...a vert group that doesnt connect to a bone)
+		# calc the influences num and the total weight (NOTE:we may have a vert group that doesnt connect to a bone)
 		for influence in influences:
 			vgroup = influence[0]
 			weight = influence[1]
 			
-			if vgroup2bone_id[ vgroup ] != -1:
-				influences_num = influences_num + 1
+			if vgroup2boneId[vgroup] != -1:
+				influencesNum = influencesNum + 1
 				sumw = sumw + weight
 		
 		# a check
-		if( influences_num > 4 ):
-			ERROR( "Cannot have more than 4 bones per vert" );
-			return "error"
+		if(influencesNum > 4):
+			raise RuntimeError("Cannot have more than 4 bones per vert")
 	
-		# write to file
-		if( b_cmnts ): ftxt += "\t/*VERT_ID " + str( vert.index ) + "*/\n"
-		
-		if( b_cmnts ): ftxt += "\t/*BONE_CONNECTIONS*/ "
-		ftxt += str( influences_num ) + "\n"
+		# write influences num
+		ftxt += str(influencesNum) + "\n"
 				
 		for influence in influences:
 			vgroup = influence[0]
 			weight = influence[1]
 			
-			if vgroup2bone_id[ vgroup ] != -1:	
-				if( b_cmnts ): ftxt += "\t\t/*BONE_ID*/ "
-				ftxt += str( vgroup2bone_id[ vgroup ] ) + " "
-				if( b_cmnts ): ftxt += "/*WEIGHT*/ "
-				ftxt += str( weight/sumw ) + "\n"
+			if vgroup2boneId[vgroup] != -1:	
+				# write bone id
+				ftxt += str(vgroup2boneId[vgroup]) + " "
+				# write weight for that bone
+				ftxt += str(weight/sumw) + "\n"
 	# end for all verts
 	
 	return ftxt
 	
-		
-#===================================================================================================
-# ScriptMesh                                                                                       =
-#===================================================================================================
-def ScriptMesh( mesh_init ):
-	mesh = mesh_init.mesh
-	b_cmnts = mesh_init.write_comments
-	skeleton = mesh_init.skeleton
-
-	#check if mesh is the correct class
-	if( mesh.__class__.__name__ != "Blender Mesh" ):
-		ERROR( "The given func param is not a \"Blender Mesh\" class but a \"" + mesh.__class__.__name__ + "\"" )
-		return "error"
 
+#=======================================================================================================================
+# getAnkiMeshScript                                                                                                    =
+#=======================================================================================================================
+def	getAnkiMeshScript(mesh, skeleton, mtlName)
 	# check verts number
-	if len(mesh.verts) < 3:
-		ERROR( "The mesh named \"" + mesh.name + "\" has insufficient vert num. Skipping" )
-		return "error"
-
-	# check UVs
-	"""if not mesh.faceUV:
-		ERROR( "The mesh named \"" + mesh.name + "\" doesnt have UVs" )
-		return "error"""
+	vertsNum = len(mesh.verts)
+	if vertsNum < 3:
+		raise RuntimeError("The mesh named \"" + mesh.name + "\" has insufficient vert num")
 	
-	# init txt
-	ftxt = ""
-	
-	# material
-	if(b_cmnts): ftxt += "/*MATERIAL*/ "
-	ftxt += "\"" + mesh_init.material_filename + "\"\n"
-	
-	# the verts
-	if(b_cmnts): ftxt += "/*VERTS*/ "
-	
-	ftxt += str( len(mesh.verts) ) + "\n"
-	
-	for vert in mesh.verts:
-		vec = Vector( vert.co )
-		
-		if(b_cmnts): ftxt += "\t/*VERT_ID "+str(vert.index)+" COORDS*/ "
-		
-		ftxt += str( vec.x ) + " " + str( vec.y ) + " " + str( vec.z ) + "\n"
+	# declare some vars
+	ankiVerts = {}
+	ankiTris = {}
+	hasUvs = 0
 
-	
-	# the faces
-	# first calc the triangles num
-	tris_num = 0
-	for face in mesh.faces:
-		if len(face.v) == 3:
-			tris_num = tris_num + 1 # if tris
-		else:
-			tris_num = tris_num + 2 # if quad
 
-	if(b_cmnts): ftxt += "/*FACES*/ "
-	ftxt += str( tris_num ) + "\n"
-	
-	# for every face
-	i = 0
-	for face in mesh.faces:
-		
-		if(b_cmnts): ftxt += "\t/*FACE_ID " + str(i) + " VERT_IDS*/ "
-		
-		order = [0,1,2]
-		# print index
-		for j in order:
-			ftxt += str( face.v[j].index ) + " "
-		
-		i = i+1
-		
-		ftxt += "\n"
-		
-		# if the face is quad then triangulate
-		if( len( face.v ) == 4 ):
-			order = [0,2,3]
+	# if it has UVs	
+	if mesh.faceUV:
+		hasUvs = 1
 		
-			if(b_cmnts): ftxt += "\t/*FACE_ID " + str(i) + " VERT_IDS*/ "
+		# for all faces
+		for i in range(len(mesh.faces)):
+			face = mesh.faces[i]
+			if len(face.verts) != 3:
+				raise RuntimeError("Only triangles are accepted")
+			
+			ankiTris[i] = Tris() # create new tri
 			
-			for j in order:
-				ftxt += str( face.v[j].index ) + " "
+			# for verts in the face
+			for j in [0, 1, 2]:
+				vertId = face.verts[j].index
+			
+				# vert does not exist
+				if not ankiVerts.has_key(vertId)
+					ankiVerts[vertId] = Vert()
+					ankiVerts[vertId].x = mesh.verts[vertId].co.x
+					ankiVerts[vertId].y = mesh.verts[vertId].co.y
+					ankiVerts[vertId].z = mesh.verts[vertId].co.z
+					ankiVerts[vertId].s = face.uv[j].x
+					ankiVerts[vertId].t = face.uv[j].y
+					ankiVerts[vertId].nextId = -1
 				
-			ftxt += "\n"
-			i = i+1
-	
-
-	# the uvs
-	# create and populate the vertuvs array
-	vertuvs = {}
-	
-	# if has UVs
-	if mesh.faceUV:
-		for vert in mesh.verts:
-			vertuvs[ vert.index ] = [ -1000.0, -1000.0 ]
+					ankiTris[i].vertIds[j] = vertId
+				else:
+					while 1:
+						# if in end of the list, create new vert and link list
+						if vertId == -1:
+							ankiVerts[vertsNum] = copy(ankiVerts[vertId])
+							ankiVerts[vertsNum].s = face.uv[j].x
+							ankiVerts[vertsNum].t = face.uv[j].y
+							ankiVerts[vertsNum].nextId = -1
 	
-		for face in mesh.faces:
-			
-			order = [0,1,2] # verts order
+							ankiVerts[vertId].nextId = vertsNum
+						
+							ankiTris[i].vertIds[j] = vertsNum
+						
+							vertsNum = vertsNum + 1
+							break
+						# a vert with the same UVs exists
+						elif ankiVerts[vertId].s == face.uv[j].x and ankiVerts[vertId].t == face.uv[j].y:
+							ankiTris[i].vertIds[j] = vertId
+							break;
+						# move to next node
+						else:
+							vertId = ankiVerts[vertId].nextId
+	# no UVs
+	else:
+		hasUvs = 0
 		
-			for j in order:
-				vert_id = face.verts[j].index
+		# set the verts
+		for i in range(len(mesh.verts)):
+			vert = mesh.verts[i]
 			
-				uvx = face.uv[j].x
-				uvy = face.uv[j].y
+			ankiVerts[i] = Vert()
+			ankiVerts[i].x = vert.co.x
+			ankiVerts[i].y = vert.co.y
+			ankiVerts[i].z = vert.co.z
+		
+		# set the faces
+		for i in range(len(mesh.faces)):
+			face = mesh.faces[i]
 			
-				# if we put a new value in the array OR the values already set and they are the same then
-				if vertuvs[ vert_id ][0]==-1000.0 or ( vertuvs[ vert_id ][0] == uvx and vertuvs[ vert_id ][1] == uvy ):
-					vertuvs[ vert_id ][0] = uvx
-					vertuvs[ vert_id ][1] = uvy
-				else:
-					ERROR( "The mesh \"" + mesh.name + "\" More than 1 coords for the " + str(vert_id) + " vert" )
-					mesh.verts[vert_id].sel=1
-					#return "error"
-					print " %f %f %f %f" % ( vertuvs[ vert_id ][0], vertuvs[ vert_id ][1], uvx, uvy )
+			if len(face.verts) != 3:
+				raise RuntimeError("Only triangles are accepted")
 			
-			# do the same if quat for the other forming triangle
-			if( len( face.verts ) == 4 ):
-				order = [0,2,3]
+			ankiTris[i] = Tri()
 			
-				for j in order:
-					vert_id = face.verts[j].index
-				
-					uvx = face.uv[j].x
-					uvy = face.uv[j].y
-				
-					# if we put a new value in the array OR the values already set and they are the same then
-					if vertuvs[ vert_id ][0]==-1000.0 or ( vertuvs[ vert_id ][0] == uvx and vertuvs[ vert_id ][1] == uvy ):
-						vertuvs[ vert_id ][0] = uvx
-						vertuvs[ vert_id ][1] = uvy
-					else:
-						ERROR( "The mesh \"" + mesh.name + "\" More than 1 coords for the " + str(vert_id) + " vert" )
-						mesh.verts[vert_id].sel=1
-						#return "error"
-						print " %f %f %f %f" % ( vertuvs[ vert_id ][0], vertuvs[ vert_id ][1], uvx, uvy )
-	# endif has UVs
-				
-	# now put the UVs in the ftxt
-	if(b_cmnts): ftxt += "/*VERT_TEX_COORDS*/ "
-		
-	ftxt += str( len(vertuvs) ) + "\n"
+			for j in [0, 1, 2]:
+				ankiTris[i].vertIds[j] = face.verts[j].index
 	
-	for i in range( 0, len(vertuvs) ):
-		if(b_cmnts): ftxt += "\t/*VERT_ID " + str(i) + " UV_COORDS*/ "
-				
-		ftxt += str( vertuvs[i][0] ) + " " + str( vertuvs[i][1] ) + "\n"
+	
+	# write to ftxt
+	
+	# write mtl name
+	ftxt = "\"" + mtlName + "\"\n"
+	
+	# write verts
+	ftxt += str(len(ankiVerts)) + "\n"
+	for ankiVert in ankiVerts:
+		ftxt += str(ankiVert.x) + " " + str(ankiVert.y) + " " + str(ankiVert.z) + "\n"
+		
+	# write the tris
+	ftxt += str(len(ankiTris)) + "\n"
+	for ankiTri in ankiTris:
+		ftxt += str(ankiTri.vertIds[0]) + " " + str(ankiTri.vertIds[1]) + " " + str(ankiTri.vertIds[2]) + "\n"
 		
-	# and now the vertex weights
-	if skeleton != NULL:
-		ftxt += ScriptVWeights( mesh_init )
+	# write the UVs
+	if hasUvs:
+		ftxt += str(len(ankiVerts)) + "\n"
+		for ankiVert in ankiVerts:
+			ftxt += str(ankiVert.s) + " " + str(ankiVert.t) + "\n"
 	else:
-		if b_cmnts:
-			ftxt += "/*VERT_WEIGHTS*/ "
-		ftxt += "0"
+		ftxt += "0\n"
 	
-	
-	return ftxt
-
-
-#===================================================================================================
-# ExportMesh                                                                                       =
-#===================================================================================================
-def ExportMesh( mesh_init ):
-	mesh = mesh_init.mesh
-	skeleton = mesh_init.skeleton
+	# write the vert weights
+	if skeleton != 0:
+		ftxt += getAnkiVertWeights(meshInit)
+	else:
+		ftxt += "0\n"
+			
+		
+#=======================================================================================================================
+# exportMesh                                                                                                           =
+#=======================================================================================================================
+def exportMesh(meshInit):
+	mesh = meshInit.mesh
+	skeleton = meshInit.skeleton
 	
 	#check if mesh is the correct class
 	if mesh.__class__.__name__ != "Blender Mesh":
-		ERROR( "The given func param is not a \"Blender Mesh\" class but a \"" + mesh.__class__.__name__ + "\"" )
+		raise RuntimeError("The given func param is not a \"Blender Mesh\" class but a \"" + mesh.__class__.__name__ + "\"")
 		return false
 	
-	if skeleton != NULL:
+	if skeleton != 0:
 		#check if skeleton is the correct class
-		if( skeleton.__class__.__name__ != "Armature" ):
-			ERROR( "The given func param is not a \"Armature\" class but a \"" + skeleton.__class__.__name__ + "\"" )
+		if(skeleton.__class__.__name__ != "Armature"):
+			raise RuntimeError("The given func param is not a \"Armature\" class but a \"" + skeleton.__class__.__name__ + "\"")
 			return false
 	
-	INFO( "Trying to export mesh \"" + mesh.name + "\"" )
-	filename = mesh_init.save_path + mesh.name + ".mesh"
-	WriteFile( filename, ScriptMesh( mesh_init ) )
-	INFO( "Mesh exported!! \"" + filename + "\"" )	
-	
-	
+	print("Trying to export mesh \"" + mesh.name + "\"")
+	filename = os.path.abspath(meshInit.saveDir + mesh.name + ".mesh")
+	WriteFile(filename, getAnkiMeshScript(mesh, skeleton, meshInit.mtlName))
+	print("Mesh exported!! \"" + filename + "\"")	
+