| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- import sys
- import common
- import os
- from copy import copy
- from Blender import Mathutils
- from Blender.Mathutils import *
- from Numeric import *
- #=======================================================================================================================
- # Initializer =
- #=======================================================================================================================
- class Initializer:
- def __init__(self):
- self.blMesh = None # Blender Mesh
- self.blSkeleton = None # Blender Armature
- self.mtlName = "" # Material name
- self.saveDir = "" # the name of the saved file
- self.flipYZ = 0
-
- #=======================================================================================================================
- # Vert =
- #=======================================================================================================================
- class Vert:
- def __init__(self):
- self.x = 0.0
- self.y = 0.0
- self.z = 0.0
- self.s = 0.0
- self.t = 0.0
- self.bonesNum = 0
- self.boneIds = [-1, -1, -1, -1]
- self.weights = [-1.0, -1.0, -1.0, -1.0]
- self.nextId = -1 # shows the next vertId. Is != -1 if the vert is problematic
- #=======================================================================================================================
- # Tri =
- #=======================================================================================================================
- class Tri:
- def __init__(self):
- self.vertIds = [-1, -1, -1]
- #=======================================================================================================================
- # 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":
- raise RuntimeError("The obj \"" + obj.getName() + "\" must link to a mesh and not to a(n) " + obj.getType())
- mesh = obj.getData(0, 1)
- return mesh
- #=======================================================================================================================
- # updateAnkiVertsWithBoneWeights =
- #=======================================================================================================================
- def updateAnkiVertsWithBoneWeights(mesh, skeleton, ankiVerts):
- boneNames = skeleton.bones.keys()
- boneNames.sort()
-
- # init text
- ftxt = ""
-
- # link the vert groups to the bone ids
- vgroup2boneId = {} # we give the vgroup name and we get the bone's id in the skeleton
- vgroupNames = mesh.getVertGroupNames()
-
- for vgroupName in vgroupNames:
- boneId = -1
- for boneName in boneNames:
- if boneName == vgroupName:
- boneId = boneNames.index(boneName)
- break
-
- if boneId == -1:
- print("Vert group \"" + vgroupName + "\" cant link to a bone")
-
- vgroup2boneId[vgroupName] = boneId
- # for every non problematic vert do some shit
- for i in range(len(mesh.verts)):
- vert = mesh.verts[i]
- influences = mesh.getVertexInfluences(vert.index)
-
- 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)
- for influence in influences:
- vgroup = influence[0]
- weight = influence[1]
-
- if vgroup2boneId[vgroup] != -1:
- influencesNum = influencesNum + 1
- sumw = sumw + weight
-
- # a check
- if influencesNum > 4:
- raise RuntimeError("Cannot have more than 4 bones per vert")
-
- # write influences num
- ankiVerts[i].bonesNum = influencesNum
-
- for j in range(len(influences)):
- influence = influences[j]
- vgroup = influence[0]
- weight = influence[1]
-
- if vgroup2boneId[vgroup] != -1:
- # write bone id
- ankiVerts[i].boneIds[j] = vgroup2boneId[vgroup]
- # write weight for that bone
- ankiVerts[i].weights[j] = weight/sumw
- # end for all non problematic verts
-
-
- # for every canonical ankiVert fill the problematics
- for i in range(len(mesh.verts)):
- ankiVert = ankiVerts[i]
-
- cid = i # current id
- nid = ankiVert.nextId # next id
-
- if nid == -1:
- continue
-
- while nid != -1:
- # copy vert weight data
- ankiVerts[nid].bonesNum = ankiVerts[cid].bonesNum
- ankiVerts[nid].boneIds = copy.copy(ankiVerts[cid].boneIds)
- ankiVerts[nid].weights = copy.copy(ankiVerts[cid].weights)
-
- cid = nid
- nid = ankiVerts[nid].nextId
-
-
-
- #=======================================================================================================================
- # getAnkiMeshScript =
- #=======================================================================================================================
- def getAnkiMeshScript(mesh, skeleton, mtlName, flipYZ):
- # check verts number
- vertsNum = len(mesh.verts)
- if vertsNum < 3:
- raise RuntimeError("The mesh named \"" + mesh.name + "\" has insufficient vert num")
-
- # declare some vars
- ankiVerts = {}
- ankiTris = [Tri() for tri in range(len(mesh.faces))]
- hasUvs = 0
- # if it has UVs
- if mesh.faceUV:
- hasUvs = 1
-
- # 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] = Tri() # create new tri
-
- # 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
-
- ankiTris[i].vertIds[j] = vertId
- else:
- prevId = -1
- while 1:
- # if in end of the list, create new vert and link list
- if vertId == -1:
- ankiVerts[vertsNum] = copy.copy(ankiVerts[prevId])
- ankiVerts[vertsNum].s = face.uv[j].x
- ankiVerts[vertsNum].t = face.uv[j].y
- ankiVerts[vertsNum].nextId = -1
-
- ankiVerts[prevId].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:
- prevId = vertId
- vertId = ankiVerts[vertId].nextId
- # no UVs
- else:
- hasUvs = 0
-
- # set the verts
- for i in range(len(mesh.verts)):
- vert = mesh.verts[i]
-
- 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 len(face.verts) != 3:
- raise RuntimeError("Only triangles are accepted")
-
- for j in [0, 1, 2]:
- ankiTris[i].vertIds[j] = face.verts[j].index
-
-
- # write to ftxt
-
- # write mtl name
- ftxt = "\"" + mtlName + "\"\n"
-
- # write verts
- ftxt += str(len(ankiVerts)) + "\n"
- for i in range(len(ankiVerts)):
- ankiVert = ankiVerts[i]
- if flipYZ == 0:
- ftxt += str(ankiVert.x) + " " + str(ankiVert.y) + " " + str(ankiVert.z) + "\n"
- else:
- ftxt += str(ankiVert.x) + " " + str(ankiVert.z) + " " + str(ankiVert.y) + "\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"
-
- # write the UVs
- if hasUvs:
- ftxt += str(len(ankiVerts)) + "\n"
- for i in range(len(ankiVerts)):
- ftxt += str(ankiVerts[i].s) + " " + str(ankiVerts[i].t) + "\n"
- else:
- ftxt += "0\n"
-
- # write the vert weights
- if skeleton != None:
- updateAnkiVertsWithBoneWeights(mesh, skeleton, ankiVerts)
-
- ftxt += str(len(ankiVerts)) + "\n"
-
- for i in range(len(ankiVerts)):
- ankiVert = ankiVerts[i]
- ftxt += str(ankiVert.bonesNum) + "\n"
- for j in range(ankiVert.bonesNum):
- ftxt += str(ankiVert.boneIds[j]) + " " + str(ankiVert.weights[j]) + "\n"
- else:
- ftxt += "0\n"
- return ftxt
-
-
- #=======================================================================================================================
- # export =
- #=======================================================================================================================
- def export(meshInit):
- mesh = meshInit.blMesh
- skeleton = meshInit.blSkeleton
-
- #check if mesh is the correct class
- if mesh.__class__.__name__ != "Blender Mesh":
- raise RuntimeError("The given func param is not a \"Blender Mesh\" class but a \"" + mesh.__class__.__name__ + "\"")
-
- if skeleton != None:
- #check if skeleton is the correct class
- if(skeleton.__class__.__name__ != "Armature"):
- raise RuntimeError("The given func param is not a \"Armature\" class but a \"" + skeleton.__class__.__name__ + "\"")
-
- print("Trying to export mesh \"" + mesh.name + "\"")
- filename = os.path.abspath(meshInit.saveDir + mesh.name + ".mesh")
- common.WriteFile(filename, getAnkiMeshScript(mesh, skeleton, meshInit.mtlName, meshInit.flipYZ))
- print("Mesh exported!! \"" + filename + "\"")
|