0 Members and 1 Guest are viewing this topic.
IMPORTANT: When posting problems, errors or support requests please reference the exact version of Blender used along with which script - not all versions, or combinations of either (Blender release candidates included) are supported so this information helps track issues.
Sadly not yet... I've been onto der_ton to see if he's had a chance to address this yet but so far he's not been able to do anything due to real life getting in the way. I think a number of these 'old' scripts are going to need the community to come up with the goods as the original authors of them have either lost interest and gone MIA or have other more pressing responsibilities - wife/baby/cat/goldfish [delete as appropriate].
__author__ = ["Paul Zirkle AKA Keless"]__version__ = '0.1'__url__ = ["www.blender.org","http://xreal.sourceforge.net","http://www.katsbits.com"]# referenced export_md3_12.py by Xembie"""Name: 'Quake Model 5 (.md5mesh/.md5anim)'Blender: 253Group: 'Export'Tooltip: 'Export a Md5 mesh/anim'"""import bpy,struct,math,os,timeMAX_QPATH = 64MD5_VER_TAG = "MD5Version"MD5_VERSION = 10class Md5Joint_t: name = "" #string parent = -1 #int pos = [] #float3 as vector3 orient = [] #float3 as quaternion3 (w is computed from xyz upon loading) def __init__(self): self.pos = [0.0, 0.0, 0.0] self.orient = [0.0, 0.0, 0.0] def GetSize(self): return struct.calcsize(self.binaryFormat) #serialize def Save(self, file, parentName): strOut = ' "' + self.name + '" ' + parent \ + ' ( ' + self.pos[0] + ' ' + self.pos[1] + ' ' + self.pos[2] + ' )' \ + ' ( ' + self.orient[0] + ' ' + self.orient[1] + ' ' + self.orient[2] + ' ) ' \ + ' // ' + parentName file.write(strOut) class Md5Vertex_t: u v boneWeight = 0 #int boneCount = 0 #int def __init__(self): self.u = 0.0 self.v = 0.0 def GetSize(self): return struct.calcsize(self.binaryFormat) #serialize def Save(self, file, index): strOut = ' vert ' + index \ + ' ( ' + self.u + ' ' + self.u + ' ) ' \ + self.boneWeight + ' ' + self.boneCount file.write(strOut) class Md5Triangle_t: indices = [] #int[3] vertex indicies __init__(self): self.indices = [ 0, 0, 0 ] def GetSize(self): return struct.calcsize(self.binaryFormat) #serialize def Save(self, file, index): strOut = ' tri ' + index + ' ' \ + self.indicies[0] + ' ' \ + self.indicies[1] + ' ' \ + self.indicies[2] file.write(strOut)
"Body2" 1 ( 0 0.0000023712 39.7816314697 ) ( -0.7071067095 0 0 ) // Body vert 4 ( 0.5554450154 0.2438279986 ) 13 4 tri 1 0 1 3
__author__ = ["Paul Zirkle AKA Keless"]__version__ = '0.1'__url__ = ["www.blender.org","http://xreal.sourceforge.net","http://www.katsbits.com"]# referenced export_md3_12.py by Xembie"""Name: 'Quake Model 5 (.md5mesh/.md5anim)'Blender: 253Group: 'Export'Tooltip: 'Export a Md5 mesh/anim'"""import bpy,struct,math,os,timeMAX_QPATH = 64MD5_COMMANDLINE = "created by Blender 2.53 with export_md5.py (v0.1) by Paul Zirkle"MD5_VERSION = 10class Md5Joint_t: name = "" #string parent = -1 #int parentName = "" #string pos = [] #float3 as vector3 orient = [] #float3 as quaternion3 (w is computed from xyz upon loading) def __init__(self): self.pos = [0.0, 0.0, 0.0] self.orient = [0.0, 0.0, 0.0] def GetSize(self): return struct.calcsize(self.binaryFormat) #serialize def Save(self, file): strOut = ' "%s" %d ( %f %f %f ) ( %f %f %f ) // %s ' % \ (self.name, parent, self.pos[0], self.pos[1], self.pos[2], \ self.orient[0], self.orient[1], self.orient[2], self.parentName ) #strOut = ' "' + self.name + '" ' + parent \ # + ' ( ' + self.pos[0] + ' ' + self.pos[1] + ' ' + self.pos[2] + ' )' \ # + ' ( ' + self.orient[0] + ' ' + self.orient[1] + ' ' + self.orient[2] + ' ) ' \ # + ' // ' + self.parentName file.write(strOut) #vertex texture and bone weight dataclass Md5Vertex_t: u = 0.0 #float v = 0.0 #float boneWeight = 0 #int boneCount = 0 #int def __init__(self): self.u = 0.0 self.v = 0.0 def GetSize(self): return struct.calcsize(self.binaryFormat) #serialize def Save(self, file, index): strOut = ' vert %d ( %f %f ) %d %d ' % \ ( index, self.u, self.v, self.boneWeight, self.boneCount) #strOut = ' vert ' + index \ # + ' ( ' + self.u + ' ' + self.v + ' ) ' \ # + self.boneWeight + ' ' + self.boneCount file.write(strOut + '\n') #triangle index data class Md5Triangle_t: indices = [] #int[3] vertex indicies def __init__(self): self.indices = [ 0, 0, 0 ] def GetSize(self): return struct.calcsize(self.binaryFormat) #serialize def Save(self, file, index): strOut = ' tri %d %d %d %d ' % \ ( index, self.indices[0], self.indices[1], self.indices[2] ) #strOut = ' tri ' + index + ' ' \ # + self.indicies[0] + ' ' \ # + self.indicies[1] + ' ' \ # + self.indicies[2] file.write(strOut + '\n') #weighted vertex data class Md5Weight_t: jointIdx = 0 #int bias = 0.0 #float pos = [] #float[3] vertex def __init__(self): self.pos = [ 0.0, 0.0, 0.0 ] def GetSize(self): return struct.calcsize(self.binaryFormat) #serialize def Save(self, file, index): strOut = ' weight %d %d %f ( %f %f %f ) ' % \ ( index, self.jointIdx, self.bias, self.pos[0], self.pos[1], self.pos[2] ) #strOut = ' weight ' + index + ' ' \ # + self.jointIdx + ' ' + self.bias \ # + ' ( ' + self.pos[0] + ' ' + self.pos[1] + ' ' + self.pos[2] + ' ) ' file.write(strOut + '\n')#holds verts, tris, and weightsclass Md5Mesh: name = "" shader = "" #string referencing skin file (dont appent ext) verts = [] # list of Md5Vertex_t tris = [] # list of Md5Triangle_t weights = [] # list of Md5Weight_t def __init__(self): self.numVerts = 0 self.numTris = 0 self.numWeights = 0 #serialize def Save(self, file): strOut = 'mesh { \n' strOut += ' // meshes: ' + self.name + '\n' strOut += ' shader "' + self.shader + '" \n' strOut += '\n' strOut += ' numVerts ' + str( len(self.verts) ) + '\n' file.write(strOut) for vi in range(len(self.verts)): self.verts[vi].Save(file, vi) strOut = '\n' strOut += ' numtris ' + str( len(self.tris) ) + '\n' file.write(strOut) for ti in range(len(self.tris)): self.tris[ti].Save(file, ti) strOut = '\n' strOut += ' numweights ' + str( len(self.weights) ) + '\n' file.write(strOut) for wi in range(len(self.weights)): self.weights[wi].Save(file, wi) strOut = '\n' strOut += '} \n\n' file.write(strOut) class md5meshFileObject: ver = 0 # should be "MD5Version 10" commandLine = "" # ignored, so insert blatant self-promotion skeleton = [] # list of Md5Joint_t meshes = [] # list of Md5Mesh def __init__(self): self.ver = MD5_VERSION self.commandLine = MD5_COMMANDLINE def Save(self, file): strOut = 'MD5Version ' + str(self.ver) + '\n' strOut += 'commandline "' + self.commandLine + '" \n' strOut += '\n' strOut += 'numJoints ' + str( len(self.skeleton) ) + '\n' strOut += 'numMeshes ' + str( len(self.meshes) ) + '\n' strOut += '\n' strOut += 'joints { \n' file.write(strOut) for joint in self.skeleton: joint.Save(file) strOut = '} \n' strOut += '\n' file.write(strOut) for mesh in self.meshes: mesh.Save(file) def message(log,msg): if log: log.write(msg + "\n") else: print(msg) class md5Settings: def __init__(self, savepath, name, logtype, scale=1.0, offsetx=0.0, offsety=0.0, offsetz=0.0): self.savepath = savepath self.name = name self.logtype = logtype self.scale = scale self.offsetx = offsetx self.offsety = offsety self.offsetz = offsetz #serializedef save_md5(settings): starttime = time.clock() #start timer newlogpath = os.path.splitext(settings.savepath)[0] + ".log" if settings.logtype == "append": log = open(newlogpath,"a") elif settings.logtype == "overwrite": log = open(newlogpath,"w") else: log = 0 message(log,"######################BEGIN######################") message(log,"Exporting selected objects...") bpy.ops.object.mode_set(mode='OBJECT') md5 = md5meshFileObject() for obj in bpy.context.selected_objects: if obj.type == 'MESH': bpy.context.scene.set_frame(bpy.context.scene.frame_start) #set timeline to 0 so we get clean mesh nobj = obj.create_mesh(bpy.context.scene,True,'PREVIEW') #make a copy of the pure mesh md5mesh = Md5Mesh() md5mesh.name = obj.name md5.meshes.append( md5mesh ) try: md5mesh.shader = obj["md5shader"] #pull from custom property except: md5mesh.shader = "" #we will store a list of unique vertex indicies here as we iterate the mesh's faces vertlist = [] for f,face in enumerate(nobj.faces): #iterate each triangle face md5tri = Md5Triangle_t() if len(face.verts) != 3: message(log,"WARNING: Skipping a non-triangle face in object " + obj.name) continue for v,vert_index in enumerate(face.verts): uv_u = round(nobj.active_uv_texture.data[f].uv[v][0],5) uv_v = round(nobj.active_uv_texture.data[f].uv[v][1],5) match = 0 #boolean, true if this is a non-unique vertex match_index = 0 #int, index of vertex if already listed for i,vi in enumerate(vertlist): if vi == vert_index: if md5mesh.verts[i].u == uv_u and md5mesh.verts[i].v == uv_v: match = 1 match_index = i #ERROR: this isnt right, it assumes the same number of weights and verts, which is a lie! if match == 0: #found new unique vertex vertlist.append(vert_index) md5tri.indices[v] = md5mesh.numVerts md5vert = Md5Vertex_t() md5vert.u = uv_u md5vert.v = uv_v #TODO: md5vert.boneWeight #TODO: md5vert.boneCount md5weight = Md5Weight_t() #TODO: md5weight.jointIdx #TODO: md5weight.bias md5weight.pos = nobj.verts[vert_index].co * obj.matrix_world md5weight.pos[0] = round(((md5weight.pos[0] + obj.matrix_world[3][0]) * settings.scale) + settings.offsetx,5) md5weight.pos[1] = round(((md5weight.pos[0] + obj.matrix_world[3][1]) * settings.scale) + settings.offsety,5) md5weight.pos[2] = round(((md5weight.pos[0] + obj.matrix_world[3][2]) * settings.scale) + settings.offsetz,5) md5mesh.verts.append(md5vert) md5mesh.weights.append(md5weight) md5mesh.numVerts += 1 else: #found matched vertex md5tri.indices[v] = match_index md5mesh.tris.append(md5tri) md5mesh.numTris += 1 #end for f,face in enumerate(nobj.face) bpy.data.meshes.remove(nobj) #clean up temporary copy #TODO: now read in reference skeleton elif obj.type == 'EMPTY': message(log, "skip empty obj " + obj.name) if bpy.context.selected_objects: file = open(settings.savepath + ".md5mesh", "w") #removed "wb" -- ascii, so dont open in binary mode md5.Save(file) file.close() #TODO: save md5anim message(log, "MD5 saved to " + settings.savepath) elapsedtime = round(time.clock() - starttime,5) message(log, "Elapsed " + str(elapsedtime) + " seconds") else: message(log, "Select an object to export!") if log: print("Logged to", newlogpath) log.close() #now create the UI registration interfacefrom bpy.props import *class ExportMD5(bpy.types.Operator): '''Export to Quake Model 5 (.md5mesh)''' bl_idname = "export.md5" bl_label = 'Export MD5' logenum = [("console","Console","log to console"), ("append","Append","append to log file"), ("overwrite","Overwrite","overwrite log file")] filepath = StringProperty(subtype = 'FILE_PATH',name="File Path", description="Filepath for exporting", maxlen= 1024, default= "") md5name = StringProperty(name="MD5 Name", description="MD5 header name / skin path (64 bytes)",maxlen=64,default="") md5logtype = EnumProperty(name="Save log", items=logenum, description="File logging options",default = 'console') md5scale = FloatProperty(name="Scale", description="Scale all objects from world origin (0,0,0)",default=1.0,precision=5) md5offsetx = FloatProperty(name="Offset X", description="Transition scene along x axis",default=0.0,precision=5) md5offsety = FloatProperty(name="Offset Y", description="Transition scene along y axis",default=0.0,precision=5) md5offsetz = FloatProperty(name="Offset Z", description="Transition scene along z axis",default=0.0,precision=5) def execute(self, context): settings = md5Settings(savepath = self.properties.filepath, name = self.properties.md5name, logtype = self.properties.md5logtype, scale = self.properties.md5scale, offsetx = self.properties.md5offsetx, offsety = self.properties.md5offsety, offsetz = self.properties.md5offsetz) save_md5(settings) return {'FINISHED'} def invoke(self, context, event): wm = context.manager wm.add_fileselect(self) return {'RUNNING_MODAL'} def poll(self, context): return context.active_object != None def menu_func(self, context): newpath = os.path.splitext(bpy.context.main.filepath)[0] + ".md5" self.layout.operator(ExportMD5.bl_idname, text="Quake Model 5 (.md5)", icon='BLENDER').filepath = newpath def register(): bpy.types.register(ExportMD5) bpy.types.INFO_MT_file_export.append(menu_func) def unregister(): bpy.types.unregister(ExportMD5) bpy.types.INFO_MT_file_export.remove(menu_func) if __name__ == "__main__": register()
MD5Version 10commandline "created by Blender 2.53 with export_md5.py (v0.1) by Paul Zirkle" numJoints 0numMeshes 1joints { } mesh { // meshes: Cube shader "" numVerts 20 vert 0 ( 0.000000 0.000000 ) 0 0 vert 1 ( 1.000000 0.000000 ) 0 0 vert 2 ( 1.000000 1.000000 ) 0 0 vert 3 ( 0.000000 1.000000 ) 0 0 vert 4 ( 0.000000 0.000000 ) 0 0 vert 5 ( 1.000000 0.000000 ) 0 0 vert 6 ( 1.000000 1.000000 ) 0 0 vert 7 ( 0.000000 1.000000 ) 0 0 vert 8 ( 0.000000 0.000000 ) 0 0 vert 9 ( 1.000000 0.000000 ) 0 0 vert 10 ( 0.000000 1.000000 ) 0 0 vert 11 ( 1.000000 1.000000 ) 0 0 vert 12 ( 0.000000 0.000000 ) 0 0 vert 13 ( 1.000000 0.000000 ) 0 0 vert 14 ( 0.000000 1.000000 ) 0 0 vert 15 ( 1.000000 1.000000 ) 0 0 vert 16 ( 1.000000 0.000000 ) 0 0 vert 17 ( 0.000000 1.000000 ) 0 0 vert 18 ( 1.000000 0.000000 ) 0 0 vert 19 ( 1.000000 1.000000 ) 0 0 numtris 12 tri 0 0 1 2 tri 1 0 2 3 tri 2 4 5 6 tri 3 4 6 7 tri 4 8 9 10 tri 5 9 11 10 tri 6 12 13 14 tri 7 13 15 14 tri 8 0 16 17 tri 9 16 11 17 tri 10 12 18 19 tri 11 12 19 7 numweights 20 weight 0 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 1 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 2 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 3 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 4 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 5 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 6 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 7 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 8 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 9 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 10 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 11 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 12 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 13 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 14 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 15 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 16 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) weight 17 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 18 0 0.000000 ( 1.000000 1.000000 1.000000 ) weight 19 0 0.000000 ( -1.000000 -1.000000 -1.000000 ) }
weight 0 15 1.000000 0.872552 4.004826 1.665381
vert 0 0.162109 0.550781 0 1
I just looked at my old 'Bob' character model files I've got on site and the *.md5mesh data is not that far off what you've got there.NumWeights looks like this;Code: [Select]weight 0 15 1.000000 0.872552 4.004826 1.665381NumVerts looks like this;Code: [Select]vert 0 0.162109 0.550781 0 1So at first glance it looks like the format is actually structured that way in terms of it's appearance without necessarily meaning that it *is* XYZ coordinate data?... if that makes sense?
@keless, although i can't help i 'applaud' you for working on this *thumbs up*
data.getVertexInfluences(face.v[i].index)
mesh = someMeshObjfor vert in mesh.verts: boneWeights = [0] * len( vert.groups ) for vgIdx in range(len(vert.groups)): boneWeights[vgIdx].objVgIdx = vert.groups[vgIdx].group boneWeights[vgIdx].weight = vert.groups[vgIdx].weight for weight in boneWeights: weight.name = mesh.vertex_groups[ weight.objVgIdx ].name
nobj = obj.create_mesh(bpy.context.scene,True,'PREVIEW')faces = nopj.facesfor face in faces[:]: #some code here faces.remove(face.index) #ERROR HERE