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: 253
Group: 'Export'
Tooltip: 'Export a Md5 mesh/anim'
"""
import bpy,struct,math,os,time
MAX_QPATH = 64
MD5_VER_TAG = "MD5Version"
MD5_VERSION = 10
class 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: 253
Group: 'Export'
Tooltip: 'Export a Md5 mesh/anim'
"""
import bpy,struct,math,os,time
MAX_QPATH = 64
MD5_COMMANDLINE = "created by Blender 2.53 with export_md5.py (v0.1) by Paul Zirkle"
MD5_VERSION = 10
class 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 data
class 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 weights
class 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
#serialize
def 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 interface
from 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 10
commandline "created by Blender 2.53 with export_md5.py (v0.1) by Paul Zirkle"
numJoints 0
numMeshes 1
joints {
}
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
NumVerts looks like this;vert 0 0.162109 0.550781 0 1
So 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?
I just looked at my old 'Bob' character model files (http://www.katsbits.com/download/models/#md5) 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.665381
NumVerts looks like this;Code: [Select]vert 0 0.162109 0.550781 0 1
So 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)
would be?mesh = someMeshObj
for 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.faces
for face in faces[:]:
#some code here
faces.remove(face.index) #ERROR HERE
Couldn't get this to run for some reason. Tried loading it into a text view and Alt+P'd it but that doesn't run scripts at present. Also dropped it into scripts/io and had to change the name to "export_md5.py" for it to appear in the export list, but it shows up as a list heading rather than an active script for me.
This is with 2.53beta running on Vista.
MD5Version 10
commandline "Exported from Blender by export_md5.py by Paul Zirkle"
numJoints 0
numMeshes 1
joints {
}
mesh {
shader "body"
numverts 0
numtris 0
numweights 0
}
Produces the same output regardless as to whether the mesh has a parent or not. A second test on a simple textured cube has Blender go through the motions of exporting without actually producing a file; it's been a long time since I used MD5 meshes so I can't remember if there were some necessary requirements for export - vertex_groups and or Armatures etc?.Exporting selected objects...
Processing mesh: Cube
Traceback (most recent call last):
File "C:\Users\[user]\AppData\Roaming\Blender Foundation\Blender\2.54\scripts\io\
io_export_md5.py", line 637, in execute
save_md5(settings)
File "C:\Users\[user]\AppData\Roaming\Blender Foundation\Blender\2.54\scripts\io\
io_export_md5.py", line 491, in save_md5
), matrix))
NameError: global name 'matrix' is not defined
matrix = obj.getMatrix('worldspace')
def treat_bone(b, parent = None):
...
mat = Blender.Mathutils.Matrix(b.matrix['ARMATURESPACE'])*matrix
...
bone = Bone( ..., mat, ... )
...
w_matrix = obj.matrix_world
def treat_bone(b, parent = None):
...
mat = b.matrix_local * w_matrix
...
bone = Bone( ..., mat, ... )
...
"Torso" -1 ( 0.019181 0.011407 7.975472 ) ( -0.707107 -0.000000 -0.000000 ) //2.49
"L_Up_Arm" 0 ( 0.019181 0.011407 12.575473 ) ( 0.000000 0.017672 0.707106 ) //2.49
"Torso" -1 ( 0.019181 -7.975471 0.011409 ) ( -0.707107 -0.000000 -0.000000 ) //2.54
"L_Up_Arm" 0 ( -0.187871 0.180156 12.571256 ) ( 0.000000 0.017672 0.707106 ) //2.54
If I'm understanding what you're saying there would it make any difference to *require* meshes be properly prepped *before* export so the script isn't doing what is effectively unnecessary work?
[EDIT]Good job so far. Results of export in the MD5 viewer. Mesh seems to be solid and everything in place, only UVW's are a messed up as per your comments above about that.
for bonename in thearmature.data.bones.keys():
posebonemat = mathutils.Matrix(pose.bones[bonename].matrix ) # @ivar poseMatrix: The total transformation of this PoseBone including constraints. -- different from localMatrix
try:
bone = BONES[bonename] #look up md5bone
except:
print( "found a posebone animating a bone that is not part of the exported armature: " + bonename )
continue
if bone.parent: # need parentspace-matrix
parentposemat = mathutils.Matrix(pose.bones[bone.parent.name].matrix ) # @ivar poseMatrix: The total transformation of this PoseBone including constraints. -- different from localMatrix
posebonemat = posebonemat*parentposemat.invert()
else:
posebonemat = posebonemat*thearmature.matrix_world
loc = [posebonemat[3][0],
posebonemat[3][1],
posebonemat[3][2],
]
rot = posebonemat.to_quat().normalize()
rot = [rot.w,rot.x,rot.y,rot.z]
animation.addkeyforbone(bone.id, time, loc, rot)
Was testing the script today and came across a minor issue, it's currently exporting all frames present in the Actions editor time line. Sometimes you need to 'over-pose' an animation to make sure it cycles correctly, right now the script is exporting those extra unwanted frames (its exporting 1>120 instead of 1>100). You need to add a UI input field so "start >> end" frames can be marked? Or read the rendering datablock that has "start >> end" data associated with still image rendering to get the actual limit?.
found bundled python: D:\PROGRA~1\BLENDE~1\BLENDE~1.54B\2.54\python
read blend: F:\IMvu-WIPs\PET bunny\sneakyidle3 v254.blend
Traceback (most recent call last):
File "C:\Users\[user]\AppData\Roaming\Blender Foundation\Blender\2.54\scripts\io\
io_export_md5.py", line 832, in execute
name = self.properties.md5name,
AttributeError: 'EXPORT_OT_md5' object has no attribute 'md5name'
I usually select both the mesh and armature with the mesh as the active object when exported (not sure if that makes a difference but it's a force of habit), adding the *.md5mesh extension to the file - tried with and without, nadda from either.Traceback (most recent call last):
File "C:\Users\[user]\AppData\Roaming\Blender Foundation\Blender\2.56\scripts\io\io_export_md5.py", line 848, in invoke
WindowManager.add_fileselect(self)
AttributeError: 'WindowManager' object has no attribute 'add_fileselect'
location:<unknown location>:-1
WindowManager.add_fileselect(self)
WindowManager.fileselect_add(self)
WindowManager.add_fileselect(self)
WindowManager.fileselect_add(self)
the invert() function was modified, I'm a little dim on the precise reasons, but I think the early .invert() returned an inverted matrix, while the new .invert() modifies the parentposemat in place. now if you want to simply return an inverted matrix you do a .inverted()
posebonemat = parentposemat.inverted() * posebonemat
The result is, as far as I can tell, identical.
I can kind of understand the changes but why not just make a mesh with a single root bone from the get-go and export that using the 'standard' script? I'm assuming the 'fake' bone is written into the file, so you're still actually exporting a rigged mesh (albeit very simple rig)?. Is there a particular reason for the changes (other than using a single format for both static and animated models)? Will take a look nontheless ;)
D:\[path]\Blender Foundation\Blender 2.59\2.59\scripts\addons
NOTE: the script was loaded via User Preferences which created a scripts/addon folder in the main Windows "User" profile, it seems custom scripts are placed there (need to be?) rather than in with the defaults located in the installation directory.
Traceback (most recent call last):
File "/home/gavlig/.blender/2.60/scripts/addons/io_export_md5.py", line 849, in execute
save_md5(settings)
File "/home/gavlig/.blender/2.60/scripts/addons/io_export_md5.py", line 713, in save_md5
arm_action = thearmature.animation_data.action
AttributeError: 'int' object has no attribute 'animation_data'
location:<unknown location>:-1
You are using wrong exporter. MD5 is for animated with bones models. If you simply trying to export level or a piece of a level, you need to export into ASE. There is another exporter for that.Or failing that, if you need to export to MD5 and because the error is due to you missing animation data, you'll need to add a simple Armature and Action to the mesh before export. I'd go with what motorsep said though and export to another format that's more appropriate for large static objects like that (ASE, OBJ).
...I get a exploded model full of skinning errors...Yes, I just checked, bone position data is not being exported correctly, it looks like it's resetting to locations to "0" - I couldn't even get the files to open in the MD5Viewer as it crashes when it gets this sort of corrupted input. So far as I can tell, all the mesh data is OK, it's just the bones/rig that are broken.
I don't think you can use MD5 like, you need both the md5mesh and md5anim for it to workBarring bugs, an MD5 mesh should look fine on its own. However, an MD5 animation can sometimes look right despite a screwed-up underlying mesh. I saw this happen when writing an exporter.
For example I download Blender 2.63 and new export module.Do you mean this exporter?
When I want something to export and save the file, nothing happens. File can not be save or not showing any error.
Traceback (most recent call last):
File "C:\Blender Foundation\Blender\2.63\scripts\addons\io_export_md5-263.py", line 905, in execute
return {'FINISHED'}
File "C:\Blender Foundation\Blender\2.63\scripts\addons\io_export_md5-263.py", line 855, in save_md5
buffer = anim.to_md5anim()
File "C:\Blender Foundation\Blender\2.63\scripts\addons\io_export_md5-263.py", line 560, in generateboundingbox
md5animation.bounds.append((min[0]*scale, min[1]*scale, min[2]*scale, max[0]*scale, max[1]*scale, max[2]*scale))
File "C:\Blender Foundation\Blender\2.63\scripts\addons\io_export_md5-263.py", line 514, in getminmax
if len(listofpoints[0]) == 0: return ([0,0,0],[0,0,0])
IndexError: list index out of range
location:<unknown location>:-1
Traceback (most recent call last):
File "C:\Users\dmeat\AppData\Roaming\Blender Foundation\Blender\2.69\scripts\addons\io_export_md5-263.py", line 904, in execute
save_md5(settings)
File "C:\Users\dmeat\AppData\Roaming\Blender Foundation\Blender\2.69\scripts\addons\io_export_md5-263.py", line 726, in save_md5
uv = [uv_textures.active.data[face.index].uv[i][0], uv_textures.active.data[face.index].uv[i][1]]
IndexError: bpy_prop_array[index]: index 3 out of range
location: <unknown location>:-1
If it were easy, everyone would be doing it and we'd no longer be special ;)
The text is too small in the image to read.. Can you type what it's telling you?
Looks like it could be the mesh objects (Shapes) you're using as part of the rigging - MD5 rigs generally can't contain non-bone objects, which includes meshes and empties. Disable/remove those then try again. Basically you should only be exporting the character mesh and the Armature composed of bones. So long as you have the Armature modifier and other bits set up you should then be able to export without issue.
To answer you other point about assimp using MD5, it's because its a purely text based format, making it super useful for teaching game development - everything is easily readable/accessible.
Based on what you've said there it pretty much looks like you're not properly prepping for export. Read through this, How to export MD5 (http://www.katsbits.com/smforum/index.php?topic=178.0) (it's linked in the first post of this topic incidentally), it's a more detailed, but generic overview, of what you should be doing - single mesh, single armature with bones only, an animation action selected, etc.
As far as I'm aware there isn't a way to restrict vertex assignments like that. You can however, see which vertices are members of which vertex groups and then manage them (http://www.katsbits.com/smforum/index.php?topic=610.msg3620#msg3620) by checking "Vertex Weight" in the Properties panel ("N") - obviously with 50k+ verts on the model you're using that will be quite a task!
As far as I'm aware there isn't a way to restrict vertex assignments like that. You can however, see which vertices are members of which vertex groups and then manage them (http://www.katsbits.com/smforum/index.php?topic=610.msg3620#msg3620) by checking "Vertex Weight" in the Properties panel ("N") - obviously with 50k+ verts on the model you're using that will be quite a task!
location: <unknown location>:-1
Exporting selected objects...
root bone: Bone
Processing mesh: mesh1
created verts at A 80, B 0, C 88
<io_export_md5-263.MD5Animation object at 0x0000000009A026D8>
Traceback (most recent call last):
File "C:\Users\oladitan\AppData\Roaming\Blender Foundation\Blender\2.71\script
s\addons\io_export_md5-263.py", line 904, in execute
save_md5(settings)
File "C:\Users\oladitan\AppData\Roaming\Blender Foundation\Blender\2.71\script
s\addons\io_export_md5-263.py", line 854, in save_md5
generateboundingbox(objects, anim, [rangestart, rangeend])
File "C:\Users\oladitan\AppData\Roaming\Blender Foundation\Blender\2.71\script
s\addons\io_export_md5-263.py", line 559, in generateboundingbox
(min, max) = getminmax(corners)
File "C:\Users\oladitan\AppData\Roaming\Blender Foundation\Blender\2.71\script
s\addons\io_export_md5-263.py", line 514, in getminmax
if len(listofpoints[0]) == 0: return ([0,0,0],[0,0,0])
IndexError: list index out of range
Which script did you use? The one authored by keless here (http://www.katsbits.com/smforum/index.php?topic=167.0), or the one by nemyax here (http://www.katsbits.com/smforum/index.php?topic=404.0)? If you used keless' script that looks like a bounding-box issue so make sure you have the mesh selected even though you're only exporting the animation (also make sure its assigned to the Armature before export - it should be the active sequence).
The deforming armature has no bones in layer 5.
Add all of the bones you want to export to the armature's layer 5,
or change the reserved bone layer in the scene properties,
and retry export.
“Just to check this further the below is the first line from the 'bounds' block exporting the same (original) Bob file from each script corresponding version of Blender - before export MESH objects were reset so their size and origin were relative to Blenders grid-centre (used "Apply" to set Origin points at 0,0,0) - the bounding box values are calculated relative to that position (outwards).
…
It looks like either there's an error in the script or Blender itself (in terms of what it's doing relative to the script) after the significant change that happened Blender 2.60 onwards - looking at the numbers from 2.62 the bounds do indeed appear to be a flat box compared to prior that.”
>>> corners.append(point_by_matrix (v, matrix)) <<<
(min, max) = getminmax(corners)
md5animation.bounds.append((min[0]*scale, min[1]*scale, min[2]*scale, max[0]*scale, max[1]*scale, max[2]*scale))
def generateboundingbox(objects, md5animation, framerange):
…
matrix = [[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
>>> [0.0, 1.0, 1.0, 0.0], <<< there is two (not one) correction values!
[0.0, 0.0, 0.0, 1.0],
]
def point_by_matrix(p, m):
…
return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0] + m[3][0],
p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1] + m[3][1],
p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]]
root
> hips
> > legs
> > spine
> > > arms
> > > head