|
|
@@ -1,348 +0,0 @@
|
|
|
-import sys
|
|
|
-import os
|
|
|
-from struct import pack
|
|
|
-from copy import deepcopy
|
|
|
-from Blender import Mathutils
|
|
|
-from Blender.Mathutils import *
|
|
|
-
|
|
|
-
|
|
|
-#=======================================================================================================================
|
|
|
-# Initializer =
|
|
|
-#=======================================================================================================================
|
|
|
-class Initializer:
|
|
|
- def __init__(self):
|
|
|
- self.blMesh = None # Blender Mesh
|
|
|
- self.blSkeleton = None # Blender Armature
|
|
|
- self.saveDir = "" # the name of the saved file
|
|
|
- self.flipYZ = False #convert from bl to right handed coord system
|
|
|
-
|
|
|
-
|
|
|
-#=======================================================================================================================
|
|
|
-# 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 = deepcopy(ankiVerts[cid].boneIds)
|
|
|
- ankiVerts[nid].weights = deepcopy(ankiVerts[cid].weights)
|
|
|
-
|
|
|
- cid = nid
|
|
|
- nid = ankiVerts[nid].nextId
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-#=======================================================================================================================
|
|
|
-# getAnkiMeshScript =
|
|
|
-#=======================================================================================================================
|
|
|
-def getAnkiMeshScript(mesh, skeleton, meshName, 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] = deepcopy(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 = "mesh\n{\n"
|
|
|
- ftxt += "\tmaterial \"" + mtlName + "\"\n"
|
|
|
-
|
|
|
- # write verts
|
|
|
- ftxt += "\tvertsNum " + str(len(ankiVerts)) + "\n\tverts\n\t{\n"
|
|
|
- for i in range(len(ankiVerts)):
|
|
|
- ankiVert = ankiVerts[i]
|
|
|
- if flipYZ == 0:
|
|
|
- ftxt += "\t\tvert {" + str(ankiVert.x) + " " + str(ankiVert.y) + " " + str(ankiVert.z) + "}\n"
|
|
|
- else:
|
|
|
- ftxt += "\t\tvert {" + 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"""
|
|
|
-
|
|
|
- # Magic
|
|
|
- buff = pack("8s", "ANKIMESH")
|
|
|
-
|
|
|
- # Mesh name
|
|
|
- str_ = meshName
|
|
|
- buff += pack("I" + str(len(str_)) + "s", len(str_), str_)
|
|
|
-
|
|
|
- # Verts num
|
|
|
- buff += pack("I", len(ankiVerts))
|
|
|
-
|
|
|
- # Verts
|
|
|
- for i in range(len(ankiVerts)):
|
|
|
- ankiVert = ankiVerts[i]
|
|
|
- if not flipYZ:
|
|
|
- buff += pack("fff", ankiVert.x, ankiVert.y, ankiVert.z)
|
|
|
- else:
|
|
|
- buff += pack("fff", ankiVert.x, ankiVert.z, -ankiVert.y)
|
|
|
-
|
|
|
- # Tris num
|
|
|
- buff += pack("I", len(ankiTris))
|
|
|
-
|
|
|
- # Tris
|
|
|
- for ankiTri in ankiTris:
|
|
|
- buff += pack("III", int(ankiTri.vertIds[0]), int(ankiTri.vertIds[1]), int(ankiTri.vertIds[2]))
|
|
|
-
|
|
|
- # Tex coords
|
|
|
- if hasUvs:
|
|
|
- buff += pack("I", len(ankiVerts))
|
|
|
- for i in range(len(ankiVerts)):
|
|
|
- buff += pack("ff", ankiVerts[i].s, ankiVerts[i].t)
|
|
|
- else:
|
|
|
- buff += pack("I", 0)
|
|
|
-
|
|
|
- # Bone weights
|
|
|
- if skeleton != None:
|
|
|
- updateAnkiVertsWithBoneWeights(mesh, skeleton, ankiVerts)
|
|
|
-
|
|
|
- buff += pack("I", len(ankiVerts))
|
|
|
-
|
|
|
- for i in range(len(ankiVerts)):
|
|
|
- ankiVert = ankiVerts[i]
|
|
|
- buff += pack("I", ankiVert.bonesNum)
|
|
|
- for j in range(ankiVert.bonesNum):
|
|
|
- buff += pack("If", ankiVert.boneIds[j], ankiVert.weights[j])
|
|
|
- else:
|
|
|
- buff += pack("I", 0)
|
|
|
-
|
|
|
- return buff
|
|
|
-
|
|
|
-
|
|
|
-#=======================================================================================================================
|
|
|
-# 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")
|
|
|
- file = open(filename, "wb")
|
|
|
- file.write(getAnkiMeshScript(mesh, skeleton, mesh.name + ".mesh", meshInit.flipYZ))
|
|
|
- print("Mesh exported!! \"" + filename + "\"")
|
|
|
-
|