def write(filename, objects): def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) print 'OBJ Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") # Write Header file.write('# Blender3D v%s EOL Armature File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1])) file.write('# www.blender3d.org\n') # Get all armatures for ob_main in objects: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): write_armature(file, ob) write_poses(file, ob) file.close() print "Armature Export time: %.2f" % (sys.time() - time1)
def write(filename, objects): def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) print 'OBJ Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") # Write Header file.write('# Blender3D v%s EOL Armature File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) file.write('# www.blender3d.org\n') # Get all armatures for ob_main in objects: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): write_armature(file,ob) write_poses(file,ob) file.close() print "Armature Export time: %.2f" % (sys.time() - time1)
def collect_edges(edges): """Gets the max-min coordinates of the mesh""" """Getting the extremes of the mesh to be exported""" maxX = maxY = maxZ = -1000000000 minX = minY = minZ = 1000000000 FGON = Blender.Mesh.EdgeFlags.FGON me = bpy.data.meshes.new() for ob_base in bpy.data.scenes.active.objects.context: for ob in BPyObject.getDerivedObjects(ob_base): me.verts = None try: me.getFromObject(ob[0]) except: pass if me.edges: me.transform(ob[1]) for ed in me.edges: if not ed.flag & FGON: x, y, z = v1 = tuple(ed.v1.co) maxX = max(maxX, x) maxY = max(maxY, y) maxZ = max(maxZ, z) minX = min(minX, x) minY = min(minY, y) minZ = min(minZ, z) x, y, z = v2 = tuple(ed.v2.co) maxX = max(maxX, x) maxY = max(maxY, y) maxZ = max(maxZ, z) minX = min(minX, x) minY = min(minY, y) minZ = min(minZ, z) edges.append((v1, v2)) me.verts = None # free memory return maxX, maxY, maxZ, minX, minY, minZ
def collect_edges(edges): """Gets the max-min coordinates of the mesh""" """Getting the extremes of the mesh to be exported""" maxX=maxY=maxZ = -1000000000 minX=minY=minZ = 1000000000 FGON= Blender.Mesh.EdgeFlags.FGON me = bpy.data.meshes.new() for ob_base in bpy.data.scenes.active.objects.context: for ob in BPyObject.getDerivedObjects(ob_base): me.verts = None try: me.getFromObject(ob[0]) except: pass if me.edges: me.transform(ob[1]) for ed in me.edges: if not ed.flag & FGON: x,y,z = v1 = tuple(ed.v1.co) maxX = max(maxX, x) maxY = max(maxY, y) maxZ = max(maxZ, z) minX = min(minX, x) minY = min(minY, y) minZ = min(minZ, z) x,y,z = v2 = tuple(ed.v2.co) maxX = max(maxX, x) maxY = max(maxY, y) maxZ = max(maxZ, z) minX = min(minX, x) minY = min(minY, y) minZ = min(minZ, z) edges.append( (v1, v2) ) me.verts = None # free memory return maxX,maxY,maxZ,minX,minY,minZ
def write(filename, objects,\ EXPORT_NORMALS_HQ=False,\ EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\ EXPORT_APPLY_MODIFIERS=True, EXPORT_BLEN_OBS=True,\ EXPORT_GROUP_BY_OB=False): ''' Basic write function. The context and options must be alredy set This can be accessed externaly eg. write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. ''' def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) print 'WTF Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") file.write('<?xml version="1.0"?>\n') file.write('<OPEN_TRACK>\n') # Write Header # file.write('\n<!--\n' # + ' Blender3D v%s WTF File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ) # + ' www.blender3d.org\n' # + '-->\n\n') # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) del meshName del tempMesh # Initialize totals, these are updated each object totverts = totuvco = totno = 0 face_vert_index = 0 globalNormals = {} file.write('\n<library_objects>\n') # Get all meshs for ob_main in objects: obnamestring = fixName(ob_main.name) file.write('\t<object id="%s">\n' % obnamestring) # Write Object name for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): # Will work for non meshes now! :) # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) me = BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) if not me: file.write('\t\t<loc>%.6f %.6f %.6f</loc>\n' % tuple(ob_main.loc)) # Write Object name file.write('\t\t<rot>%.6f %.6f %.6f</rot>\n' % tuple(ob_main.rot)) # Write Object name continue faceuv = me.faceUV # We have a valid mesh if me.faces: # Add a dummy object to it. has_quads = False for f in me.faces: if len(f) == 4: has_quads = True break if has_quads: oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) me.sel = True tempob = scn.objects.new(me) me.quadToTriangle(0) # more=0 shortest length oldmode = Mesh.Mode(oldmode) scn.objects.unlink(tempob) Mesh.Mode(oldmode) # Make our own list so it can be sorted to reduce context switching faces = [f for f in me.faces] edges = me.edges if not (len(faces) + len(edges) + len(me.verts)): # Make sure there is somthing to write continue # dont bother with this mesh. me.transform(ob_mat) # High Quality Normals if faces: if EXPORT_NORMALS_HQ: BPyMesh.meshCalcNormals(me) else: # transforming normals is incorrect # when the matrix is scaled, # better to recalculate them me.calcNormals() # # Crash Blender #materials = me.getMaterials(1) # 1 == will return None in the list. materials = me.materials materialNames = [] materialItems = materials[:] if materials: for mat in materials: if mat: # !=None materialNames.append(mat.name) else: materialNames.append(None) # Cant use LC because some materials are None. # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. # Possible there null materials, will mess up indicies # but at least it will export, wait until Blender gets fixed. materialNames.extend((16 - len(materialNames)) * [None]) materialItems.extend((16 - len(materialItems)) * [None]) # Sort by Material, then images # so we dont over context switch in the obj file. if faceuv: try: faces.sort(key=lambda a: (a.mat, a.image, a.smooth)) except: faces.sort(lambda a, b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) elif len(materials) > 1: try: faces.sort(key=lambda a: (a.mat, a.smooth)) except: faces.sort(lambda a, b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) else: # no materials try: faces.sort(key=lambda a: a.smooth) except: faces.sort(lambda a, b: cmp(a.smooth, b.smooth)) # Set the default mat to no material and no image. contextMat = ( 0, 0 ) # Can never be this, so we will label a new material teh first chance we get. contextSmooth = None # Will either be true or false, set bad to force initialization switch. if len(faces) > 0: file.write('\t\t<mesh>\n') else: file.write('\t\t<curve>\n') vertname = "%s-Vertices" % obnamestring vertarrayname = "%s-Array" % vertname normname = "%s-Normals" % obnamestring normarrayname = "%s-Array" % normname texname = "%s-TexCoord" % obnamestring texarrayname = "%s-Array" % texname # Vert file.write('\t\t\t<float_array count="%d" id="%s">' % (len(me.verts), vertarrayname)) for v in me.verts: file.write(' %.6f %.6f %.6f' % tuple(v.co)) file.write('</float_array>\n') file.write('\t\t\t<vertices id="%s" source="#%s" />\n' % (vertname, vertarrayname)) # UV if faceuv: file.write('\t\t\t<float_array id="%s">' % texarrayname) uv_face_mapping = [[0, 0, 0, 0] for f in faces ] # a bit of a waste for tri's :/ uv_dict = {} # could use a set() here for f_index, f in enumerate(faces): for uv_index, uv in enumerate(f.uv): uvkey = veckey2d(uv) try: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] except: uv_face_mapping[f_index][uv_index] = uv_dict[ uvkey] = len(uv_dict) file.write(' %.6f %.6f' % tuple(uv)) uv_unique_count = len(uv_dict) del uv, uvkey, uv_dict, f_index, uv_index # Only need uv_unique_count and uv_face_mapping file.write('</float_array>\n') file.write('\t\t\t<texcoords id="%s" source="#%s" />\n' % (texname, texarrayname)) # NORMAL, Smooth/Non smoothed. if len(faces) > 0: file.write('\t\t\t<float_array id="%s">' % normarrayname) for f in faces: if f.smooth: for v in f: noKey = veckey3d(v.no) if not globalNormals.has_key(noKey): globalNormals[noKey] = totno totno += 1 file.write(' %.6f %.6f %.6f' % noKey) else: # Hard, 1 normal from the face. noKey = veckey3d(f.no) if not globalNormals.has_key(noKey): globalNormals[noKey] = totno totno += 1 file.write(' %.6f %.6f %.6f' % noKey) file.write('</float_array>\n') file.write('\t\t\t<normals id="%s" source="#%s" />\n' % (normname, normarrayname)) if not faceuv: f_image = None in_triangles = False for f_index, f in enumerate(faces): f_v = f.v f_smooth = f.smooth f_mat = min(f.mat, len(materialNames) - 1) if faceuv: f_image = f.image f_uv = f.uv # MAKE KEY if faceuv and f_image: # Object is always true. key = materialNames[f_mat], f_image.name else: key = materialNames[ f_mat], None # No image, use None instead. # CHECK FOR CONTEXT SWITCH if key == contextMat: pass # Context alredy switched, dont do anythoing else: if key[0] == None and key[1] == None: # Write a null material, since we know the context has changed. if in_triangles: file.write('</p>\n') file.write('\t\t\t</triangles>\n') file.write('\t\t\t<triangles id="%s_%s">\n' % (fixName(ob.name), fixName(ob.getData(1)))) in_triangles = True else: mat_data = MTL_DICT.get(key) if not mat_data: # First add to global dict so we can export to mtl # Then write mtl # Make a new names from the mat and image name, # converting any spaces to underscores with fixName. # If none image dont bother adding it to the name if key[1] == None: mat_data = MTL_DICT[key] = ('%s' % fixName( key[0])), materialItems[f_mat], f_image else: mat_data = MTL_DICT[key] = ( '%s_%s' % (fixName(key[0]), fixName(key[1])) ), materialItems[f_mat], f_image if in_triangles: file.write('</p>\n') file.write('\t\t\t</triangles>\n') file.write( '\t\t\t<triangles id="%s_%s_%s" material="#%s">\n' % (fixName(ob.name), fixName( ob.getData(1)), mat_data[0], mat_data[0])) in_triangles = True file.write( '\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n' % vertname) file.write( '\t\t\t\t<input offset="1" semantic="NORMAL" source="#%s" />\n' % normname) if faceuv: file.write( '\t\t\t\t<input offset="2" semantic="TEXCOORD" source="#%s" />\n' % texname) file.write('\t\t\t\t<p>') contextMat = key if f_smooth != contextSmooth: if f_smooth: # on now off # file.write('s 1\n') contextSmooth = f_smooth else: # was off now on # file.write('s off\n') contextSmooth = f_smooth if faceuv: if f_smooth: # Smoothed, use vertex normals for vi, v in enumerate(f_v): file.write( ' %d %d %d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals no = globalNormals[veckey3d(f.no)] for vi, v in enumerate(f_v): file.write( ' %d %d %d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ no)) # vert, uv, normal face_vert_index += len(f_v) else: # No UV's if f_smooth: # Smoothed, use vertex normals for v in f_v: file.write( ' %d %d' % (\ v.index+totverts,\ globalNormals[ veckey3d(v.no) ])) else: # No smoothing, face normals no = globalNormals[veckey3d(f.no)] for v in f_v: file.write( ' %d %d' % (\ v.index+totverts,\ no)) if in_triangles: file.write('</p>\n') file.write('\t\t\t</triangles>\n') # Write edges. LOOSE = Mesh.EdgeFlags.LOOSE has_edge = False for ed in edges: if ed.flag & LOOSE: has_edge = True if has_edge: file.write('\t\t\t<edges>\n') file.write( '\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n' % vertname) file.write('\t\t\t\t<p>') for ed in edges: if ed.flag & LOOSE: file.write( ' %d %d' % (ed.v1.index + totverts, ed.v2.index + totverts)) file.write('</p>\n') file.write('\t\t\t</edges>\n') # Make the indicies global rather then per mesh # totverts += len(me.verts) # if faceuv: # totuvco += uv_unique_count me.verts = None if len(faces) > 0: file.write('\t\t</mesh>\n') else: file.write('\t\t</curve>\n') file.write('\t</object>\n') file.write('</library_objects>\n\n') # Now we have all our materials, save them if EXPORT_MTL: write_library_materials(file) # Save the groups write_library_groups(file) file.write('</OPEN_TRACK>\n') file.close() if EXPORT_COPY_IMAGES: dest_dir = filename # Remove chars until we are just the path. while dest_dir and dest_dir[-1] not in '\\/': dest_dir = dest_dir[:-1] if dest_dir: copy_images(dest_dir) else: print '\tError: "%s" could not be used as a base for an image path.' % filename print "WTF Export time: %.2f" % (sys.time() - time1)
def write(filename, objects,\ EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_NORMALS_HQ=False,\ EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\ EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=False,\ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True): ''' Basic write function. The context and options must be alredy set This can be accessed externaly eg. write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. ''' def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) def findVertexGroupName(face, vWeightMap): """ Searches the vertexDict to see what groups is assigned to a given face. We use a frequency system in order to sort out the name because a given vetex can belong to two or more groups at the same time. To find the right name for the face we list all the possible vertex group names with their frequency and then sort by frequency in descend order. The top element is the one shared by the highest number of vertices is the face's group """ weightDict = {} for vert in face: vWeights = vWeightMap[vert.index] for vGroupName, weight in vWeights: weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight if weightDict: alist = [(weight,vGroupName) for vGroupName, weight in weightDict.iteritems()] # sort least to greatest amount of weight alist.sort() return(alist[-1][1]) # highest value last else: return '(null)' print 'OBJ Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") # Write Header file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) file.write('# www.blender3d.org\n') # Tell the obj file what material file to use. if EXPORT_MTL: mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1]) file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] )) # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) if EXPORT_ROTX90: mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') del meshName del tempMesh # Initialize totals, these are updated each object totverts = totuvco = totno = 1 face_vert_index = 1 globalNormals = {} # Get all meshes for ob_main in objects: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): # Nurbs curve support if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob): if EXPORT_ROTX90: ob_mat = ob_mat * mat_xrot90 totverts += write_nurb(file, ob, ob_mat) continue # end nurbs # Will work for non meshes now! :) # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn) if not me: continue if EXPORT_UV: faceuv= me.faceUV else: faceuv = False # We have a valid mesh if EXPORT_TRI and me.faces: # Add a dummy object to it. has_quads = False for f in me.faces: if len(f) == 4: has_quads = True break if has_quads: oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) me.sel = True tempob = scn.objects.new(me) me.quadToTriangle(0) # more=0 shortest length oldmode = Mesh.Mode(oldmode) scn.objects.unlink(tempob) Mesh.Mode(oldmode) # Make our own list so it can be sorted to reduce context switching faces = [ f for f in me.faces ] if EXPORT_EDGES: edges = me.edges else: edges = [] if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write continue # dont bother with this mesh. if EXPORT_ROTX90: me.transform(ob_mat*mat_xrot90) else: me.transform(ob_mat) # High Quality Normals if EXPORT_NORMALS and faces: if EXPORT_NORMALS_HQ: BPyMesh.meshCalcNormals(me) else: # transforming normals is incorrect # when the matrix is scaled, # better to recalculate them me.calcNormals() # # Crash Blender #materials = me.getMaterials(1) # 1 == will return None in the list. materials = me.materials materialNames = [] materialItems = materials[:] if materials: for mat in materials: if mat: # !=None materialNames.append(mat.name) else: materialNames.append(None) # Cant use LC because some materials are None. # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. # Possible there null materials, will mess up indicies # but at least it will export, wait until Blender gets fixed. materialNames.extend((16-len(materialNames)) * [None]) materialItems.extend((16-len(materialItems)) * [None]) # Sort by Material, then images # so we dont over context switch in the obj file. if EXPORT_KEEP_VERT_ORDER: pass elif faceuv: try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth)) except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) elif len(materials) > 1: try: faces.sort(key = lambda a: (a.mat, a.smooth)) except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) else: # no materials try: faces.sort(key = lambda a: a.smooth) except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth)) # Set the default mat to no material and no image. contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get. contextSmooth = None # Will either be true or false, set bad to force initialization switch. if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB: name1 = ob.name name2 = ob.getData(1) if name1 == name2: obnamestring = fixName(name1) else: obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) if EXPORT_BLEN_OBS: file.write('o %s\n' % obnamestring) # Write Object name else: # if EXPORT_GROUP_BY_OB: file.write('g %s\n' % obnamestring) # Vert for v in me.verts: file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) # UV if faceuv: uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ uv_dict = {} # could use a set() here for f_index, f in enumerate(faces): for uv_index, uv in enumerate(f.uv): uvkey = veckey2d(uv) try: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] except: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) file.write('vt %.6f %.6f\n' % tuple(uv)) uv_unique_count = len(uv_dict) del uv, uvkey, uv_dict, f_index, uv_index # Only need uv_unique_count and uv_face_mapping # NORMAL, Smooth/Non smoothed. if EXPORT_NORMALS: for f in faces: if f.smooth: for v in f: noKey = veckey3d(v.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) else: # Hard, 1 normal from the face. noKey = veckey3d(f.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) if not faceuv: f_image = None if EXPORT_POLYGROUPS: # Retrieve the list of vertex groups vertGroupNames = me.getVertGroupNames() currentVGroup = '' # Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to vgroupsMap = [[] for _i in xrange(len(me.verts))] for vertexGroupName in vertGroupNames: for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1): vgroupsMap[vIdx].append((vertexGroupName, vWeight)) for f_index, f in enumerate(faces): f_v= f.v f_smooth= f.smooth f_mat = min(f.mat, len(materialNames)-1) if faceuv: f_image = f.image f_uv= f.uv # MAKE KEY if faceuv and f_image: # Object is always true. key = materialNames[f_mat], f_image.name else: key = materialNames[f_mat], None # No image, use None instead. # Write the vertex group if EXPORT_POLYGROUPS: if vertGroupNames: # find what vertext group the face belongs to theVGroup = findVertexGroupName(f,vgroupsMap) if theVGroup != currentVGroup: currentVGroup = theVGroup file.write('g %s\n' % theVGroup) # CHECK FOR CONTEXT SWITCH if key == contextMat: pass # Context alredy switched, dont do anything else: if key[0] == None and key[1] == None: # Write a null material, since we know the context has changed. if EXPORT_GROUP_BY_MAT: file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) file.write('usemtl (null)\n') # mat, image else: mat_data= MTL_DICT.get(key) if not mat_data: # First add to global dict so we can export to mtl # Then write mtl # Make a new names from the mat and image name, # converting any spaces to underscores with fixName. # If none image dont bother adding it to the name if key[1] == None: mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image else: mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image if EXPORT_GROUP_BY_MAT: file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) contextMat = key if f_smooth != contextSmooth: if f_smooth: # on now off file.write('s 1\n') contextSmooth = f_smooth else: # was off now on file.write('s off\n') contextSmooth = f_smooth file.write('f') if faceuv: if EXPORT_NORMALS: if f_smooth: # Smoothed, use vertex normals for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ no)) # vert, uv, normal else: # No Normals for vi, v in enumerate(f_v): file.write( ' %d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi])) # vert, uv face_vert_index += len(f_v) else: # No UV's if EXPORT_NORMALS: if f_smooth: # Smoothed, use vertex normals for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ globalNormals[ veckey3d(v.no) ])) else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ no)) else: # No Normals for v in f_v: file.write( ' %d' % (\ v.index+totverts)) file.write('\n') # Write edges. if EXPORT_EDGES: LOOSE= Mesh.EdgeFlags.LOOSE for ed in edges: if ed.flag & LOOSE: file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) # Make the indicies global rather then per mesh totverts += len(me.verts) if faceuv: totuvco += uv_unique_count me.verts= None file.close() # Now we have all our materials, save them if EXPORT_MTL: write_mtl(mtlfilename) if EXPORT_COPY_IMAGES: dest_dir = filename # Remove chars until we are just the path. while dest_dir and dest_dir[-1] not in '\\/': dest_dir = dest_dir[:-1] if dest_dir: copy_images(dest_dir) else: print '\tError: "%s" could not be used as a base for an image path.' % filename print "OBJ Export time: %.2f" % (sys.time() - time1)
def saveBR2(filename): if not filename.lower().endswith('.br2'): filename += '.br2' if not BPyMessages.Warning_SaveOver(filename): return print "Start BR2 Export..." Blender.Window.WaitCursor(1) file = open( filename, 'wb') scene = Blender.Scene.GetCurrent() allObjects = scene.objects filedata = "// Nexus Buddy BR2 - Exported from Blender for import to Nexus Buddy 2\n" modelObs = {} modelMeshes = {} # will need list of these for multi-skeleton boneIds = {} for object in allObjects: if object.type == 'Armature': modelObs[object.name] = object if object.type == 'Mesh': print "Getting parent for mesh: %s" % object.name parentArmOb = BPyObject.getObjectArmature(object) if not parentArmOb.name in modelMeshes: modelMeshes[parentArmOb.name] = [] modelMeshes[parentArmOb.name].append(object) for modelObName in modelObs.keys(): # Write Skeleton filedata += "skeleton\n" armOb = modelObs[modelObName] armature = armOb.data # Calc bone depths and sort boneDepths = [] for bone in armature.bones.values(): boneDepth = getBoneTreeDepth(bone, 0) boneDepths.append((bone, boneDepth)) boneDepths = sorted(boneDepths, key=lambda k: k[0].name) boneDepths = sorted(boneDepths, key=lambda k: k[1]) sortedBones = boneDepths for boneid, boneTuple in enumerate(sortedBones): boneIds[boneTuple[0].name] = boneid boneIds[armOb.name] = -1 # Add entry for World Bone # Write World Bone filedata += '%d "%s" %d ' % (0, armOb.name, -1) filedata += '%.8f %.8f %.8f ' % (0.0, 0.0, 0.0) filedata += '%.8f %.8f %.8f %.8f ' % (0.0, 0.0, 0.0, 1.0) filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f\n' % (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) for boneid, boneTuple in enumerate(sortedBones): bone = boneTuple[0] boneDepth = boneTuple[1] #boneid = boneid + 1 # World bone is zero position, orientationQuat = getTranslationOrientation(bone) # Get Inverse World Matrix for bone t = bone.matrix['ARMATURESPACE'].copy().invert() invWorldMatrix = Matrix([t[0][1], -t[0][0], t[0][2], t[0][3]], [t[1][1], -t[1][0], t[1][2], t[1][3]], [t[2][1], -t[2][0], t[2][2], t[2][3]], [t[3][1], -t[3][0], t[3][2], t[3][3]]) outputBoneName = bone.name if len(outputBoneName) == 29: for item in armOb.getAllProperties(): if (("B_" + outputBoneName) == item.getName()): outputBoneName = item.getData() print 'Decode Bone Name: "%s" >' % item.getName() print ' "%s"' % item.getData() break filedata += '%d "%s" ' % (boneid + 1, outputBoneName) # Adjust bone ids + 1 as zero is the World Bone parentBoneId = 0 if bone.hasParent(): parentBoneId = boneIds[bone.parent.name] + 1 # Adjust bone ids + 1 as zero is the World Bone filedata += '%d ' % parentBoneId filedata +='%.8f %.8f %.8f ' % (position[0], position[1] , position[2]) filedata +='%.8f %.8f %.8f %.8f ' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0]) # GR2 uses x,y,z,w for Quaternions rather than w,x,y,z filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f' % ( invWorldMatrix[0][0], invWorldMatrix[0][1], invWorldMatrix[0][2], invWorldMatrix[0][3], invWorldMatrix[1][0], invWorldMatrix[1][1], invWorldMatrix[1][2], invWorldMatrix[1][3], invWorldMatrix[2][0], invWorldMatrix[2][1], invWorldMatrix[2][2], invWorldMatrix[2][3], invWorldMatrix[3][0], invWorldMatrix[3][1], invWorldMatrix[3][2], invWorldMatrix[3][3]) #End of bone line filedata += "\n" filedata += 'meshes:%d\n' % len(modelMeshes[modelObName]) for meshObject in modelMeshes[modelObName]: mesh = meshObject.data meshName = meshObject.name filedata += 'mesh:"%s"\n' % meshName parentArmOb = BPyObject.getObjectArmature(meshObject) # Fetch long mesh names from Armature properties if len(meshName) == 19: for item in parentArmOb.getAllProperties(): if ("M_" + meshName == item.getName()): meshName = item.getData() print 'Decode Mesh Name: %s > %s' % (item.getName(), item.getData()) break #file.write('meshname:%s\n' % meshName) #file.write('parent Arm:%s\n' % parentArmOb) weights = meshNormalizedWeights(mesh) vertexBoneWeights = {} for boneName in boneIds.keys(): vgroupDataForBone = getBoneWeights(boneName, weights) #file.write('bone:%s vg:%s\n' % (boneName, vgroupDataForBone)) for vgData in vgroupDataForBone: vertexId = vgData[0] weight = vgData[1] if not vertexId in vertexBoneWeights: vertexBoneWeights[vertexId] = [] vertexBoneWeights[vertexId].append((boneName, weight)) #file.write('vert:%d bone:%s \n' % (vertexId, (boneName, weight))) grannyVertexBoneWeights = {} for vertId in vertexBoneWeights.keys(): #file.write('vert:%d ' % vertId) rawBoneIdWeightTuples = [] firstBoneId = 0 for i in range(max(4,len(vertexBoneWeights[vertId]))): if i < len(vertexBoneWeights[vertId]): vertexBoneWeightTuple = vertexBoneWeights[vertId][i] boneName = vertexBoneWeightTuple[0] rawBoneIdWeightTuples.append((boneIds[boneName] + 1, vertexBoneWeightTuple[1])) if i == 0: firstBoneId = boneIds[boneName] + 1 else: rawBoneIdWeightTuples.append((firstBoneId, 0)) # Sort bone mappings by weight highest to lowest sortedBoneIdWeightTuples = sorted(rawBoneIdWeightTuples, key=lambda rawBoneIdWeightTuple: rawBoneIdWeightTuple[1], reverse=True) #if len(vertexBoneWeights[vertId]) > 4: # print "len(vertexBoneWeights[vertId]): %s" % len(vertexBoneWeights[vertId]) # print "sortedBoneIdWeightTuples: %s" % sortedBoneIdWeightTuples # Pick first four highest weighted bones boneIdsList = [] rawBoneWeightsList = [] for i in range(4): boneIdsList.append(sortedBoneIdWeightTuples[i][0]) rawBoneWeightsList.append(sortedBoneIdWeightTuples[i][1]) rawWeightTotal = 0 for weight in rawBoneWeightsList: rawWeightTotal = rawWeightTotal + weight boneWeightsList = [] for weight in rawBoneWeightsList: calcWeight = round(255 * weight / rawWeightTotal) boneWeightsList.append(calcWeight) # Ensure that total of vertex bone weights is 255 runningTotal = 0 for i, weight in enumerate(boneWeightsList): runningTotal = runningTotal + weight if runningTotal > 255: boneWeightsList[i] = weight - 1 break if runningTotal < 255: boneWeightsList[0] = boneWeightsList[0] + 1 runningTotal = 0 for i, weight in enumerate(boneWeightsList): runningTotal = runningTotal + weight if runningTotal != 255: raise "Error: Vertex bone weights do not total 255!" if not vertId in grannyVertexBoneWeights: grannyVertexBoneWeights[vertId] = [] grannyVertexBoneWeights[vertId] = (boneIdsList, boneWeightsList) #file.write('%s %s ' % (boneIdsList, boneWeightsList)) #file.write("\n") position, orientationQuat = getTranslationOrientation(meshObject) #file.write('position:%.8f %.8f %.8f\n' % (position[0], position[1], position[2])) #file.write('orientationQuat:%.8f %.8f %.8f %.8f\n' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0])) #file.write(meshName+"\n") filedata += "vertices\n" # Determine unique vertex/UVs for output uniqueVertSet = set() uniqueVertUVIndexes = {} uniqueVertUVs = [] currentVertUVIndex = 0 currentTriangleId = 0 triangleVertUVIndexes = [] for triangle in mesh.faces: vertIds = [v.index for v in triangle] vertIds = tuple(vertIds) triangleVertUVIndexes.append([]) for i, uv in enumerate(triangle.uv): vertexId = vertIds[i] uvt = tuple(uv) vertSig = '%i|%.8f|%.8f' % (vertexId, uvt[0], uvt[1]) if vertSig in uniqueVertSet: triangleVertUVIndex = uniqueVertUVIndexes[vertSig] else: uniqueVertSet.add(vertSig) uniqueVertUVIndexes[vertSig] = currentVertUVIndex uniqueVertUVs.append((vertexId, uvt[0], uvt[1])) triangleVertUVIndex = currentVertUVIndex currentVertUVIndex = currentVertUVIndex + 1 triangleVertUVIndexes[currentTriangleId].append(triangleVertUVIndex) currentTriangleId = currentTriangleId + 1 meshVerts = {} for i,vert in enumerate(mesh.verts): meshVerts[i] = vert # Write Vertices for uniqueVertUV in uniqueVertUVs: index = uniqueVertUV[0] vert = meshVerts[index] vertCoord = tuple(vert.co) vertNormal = tuple(vert.no) filedata +='%.8f %.8f %.8f ' % (vertCoord[0] + position[0], vertCoord[1] + position[1], vertCoord[2] + position[2]) filedata +='%.8f %.8f %.8f ' % vertNormal filedata +='%.8f %.8f ' % (uniqueVertUV[1], 1 - uniqueVertUV[2]) if index in grannyVertexBoneWeights: vBoneWeightTuple = grannyVertexBoneWeights[index] else: raise "Error: Mesh has unweighted vertices!" #vBoneWeightTuple = ([-1,-1,-1,-1],[-1,-1,-1,-1]) # Unweighted vertex - raise error filedata +='%d %d %d %d ' % (vBoneWeightTuple[0][0], vBoneWeightTuple[0][1],vBoneWeightTuple[0][2],vBoneWeightTuple[0][3]) # Bone Ids filedata +='%d %d %d %d\n' % (vBoneWeightTuple[1][0], vBoneWeightTuple[1][1],vBoneWeightTuple[1][2],vBoneWeightTuple[1][3]) # Bone Weights # Write Triangles filedata += "triangles\n" for triangle in triangleVertUVIndexes: #filedata += '%i %i %i\n' % tuple(triangle) filedata += '%i %i %i\n' % (triangle[0],triangle[1],triangle[2]) filedata += "end" file.write(filedata) file.close() Blender.Window.WaitCursor(0) print "End BR2 Export."
def write(directory, filename, objects): def v_n_uv_key(v, n, uv): return round(v.x, 6), round(v.y, 6), round(v.z, 6), round(n.x, 6), round( n.y, 6), round(n.z, 6), round(uv[0], 6), round(uv[1], 6) def v_n_key(v, n): return round(v.x, 6), round(v.y, 6), round(v.z, 6), round(n.x, 6), round(n.y, 6), round(n.z, 6) def adjust_key(key, obCenter): keyList = list(key) keyList[0] -= obCenter[0] keyList[1] -= obCenter[1] keyList[2] -= obCenter[2] return tuple(keyList) temp_mesh_name = '~tmp-mesh' scn = Scene.GetCurrent() # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) del meshName del tempMesh try: armature = Blender.Object.Get("Armature") write_armature(directory + filename, armature) except: armature = None # Get all meshs for ob_main in objects: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): me = BPyMesh.getMeshFromObject(ob, containerMesh, True, False, scn) if not me: continue # Initialize globalVertices and globalMaterials dictionaries vertIndex = 0 matIndex = 0 globalVertices = {} globalMaterials = {} # Dictionary of materials: (material.name, image.name):matname_imagename # matname_imagename has fixed names. materialDict = {} # We have a valid mesh if me.faces: # Add a dummy object to it. has_quads = False for f in me.faces: if len(f) == 4: has_quads = True break if has_quads: oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) me.sel = True tempob = scn.objects.new(me) me.quadToTriangle(0) # more=0 shortest length oldmode = Mesh.Mode(oldmode) scn.objects.unlink(tempob) Mesh.Mode(oldmode) else: continue # High Quality Normals BPyMesh.meshCalcNormals(me) # Make our own list so it can be sorted to reduce context switching faces = [f for f in me.faces] faceuv = me.faceUV edges = me.edges materials = me.materials materialNames = [] materialItems = materials[:] if materials: for mat in materials: if mat: materialNames.append(mat.name) else: materialNames.append(None) # Possible there null materials, will mess up indicies # but at least it will export, wait until Blender gets fixed. materialNames.extend((16 - len(materialNames)) * [None]) materialItems.extend((16 - len(materialItems)) * [None]) # Sort by Material, then images # so we dont over context switch in the obj file. if faceuv: try: faces.sort(key=lambda a: (a.mat, a.image, a.smooth)) except: faces.sort(lambda a, b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) elif len(materials) > 1: try: faces.sort(key=lambda a: (a.mat, a.smooth)) except: faces.sort(lambda a, b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) else: # no materials try: faces.sort(key=lambda a: a.smooth) except: faces.sort(lambda a, b: cmp(a.smooth, b.smooth)) # Set the default mat to no material and no image. contextMat = ( 0, 0 ) # Can never be this, so we will label a new material the first chance we get. contextSmooth = None # Will either be true or false, set bad to force initialization switch. name1 = ob.name name2 = ob.getData(1) obnamestring = fixName(name1) file = open(directory + obnamestring + ".drkMesh", "w") # Fill globalVertices dictionary by creating (vert, normal, uv) tuple for all vertices of all faces vertString = "" obCenter = ob.getLocation() if faceuv: vOutputFormat = 'v %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f\n' else: vOutputFormat = 'v %.6f %.6f %.6f %.6f %.6f %.6f\n' f_image = None #Loop through all faces submeshCount = 0 faceCount = 0 faceCounts = [] for face in faces: if faceuv: faceUVs = list(face.uv) faceUVindex = 0 faceIndices = [] for v in face: if face.smooth: vno = v.no else: vno = face.no if faceuv: key = v_n_uv_key(v.co, v.no, faceUVs[faceUVindex]) faceUVindex += 1 else: key = v_n_key(v.co, v.no) if not globalVertices.has_key(key): globalVertices[key] = vertIndex vertString += vOutputFormat % key faceIndices.append(vertIndex) vertIndex += 1 else: faceIndices.append(globalVertices[key]) # Make material,texture key f_mat = min(face.mat, len(materialNames) - 1) if faceuv: f_image = face.image if faceuv and f_image: matKey = materialNames[f_mat], f_image.name else: matKey = materialNames[f_mat], None # Check for context switch if matKey != contextMat: submeshCount += 1 if matKey[0] == None and matKey[1] == None: # Write a null material, since we know the context has changed. faceString += 'use (null)\n' # mat, image else: mat_data = materialDict.get(matKey) if not mat_data: mat_data = materialDict[matKey] = fixName( matKey[0]), materialItems[f_mat], f_image vertString += 'use %d\n' % matIndex globalMaterials[mat_data[0]] = matIndex matIndex += 1 if faceCount != 0: faceCounts.append(faceCount) faceCount = 0 contextMat = matKey vertString += 'face %d %d %d\n' % tuple(faceIndices) faceCount += 1 faceCounts.append(faceCount) file.write('count %d\n' % vertIndex) if faceuv: file.write('uvs\n') file.write('submeshes %d\n' % submeshCount) for faceCount in faceCounts: file.write('faces %d\n' % faceCount) file.write(vertString) me.verts = None write_mtl(file, materialDict, globalMaterials) file.close()
def write(filename, objects,\ EXPORT_TRI=False, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_NORMALS_HQ=False,\ EXPORT_UV=True, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\ EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False, EXPORT_ARMATURE=False): ''' Basic write function. The context and options must be alredy set This can be accessed externaly eg. write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. ''' def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) print 'OBJ Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") # Write Header file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) file.write('# www.blender3d.org\n') # Tell the obj file what material file to use. if EXPORT_MTL: mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1]) file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] )) # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) if EXPORT_ROTX90: mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') del meshName del tempMesh # Initialize totals, these are updated each object totverts = totuvco = totno = 1 face_vert_index = 1 globalNormals = {} # Get all meshs for ob_main in objects: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): # Will work for non meshes now! :) # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) if EXPORT_ARMATURE: write_armature(file,ob) write_poses(file,ob) me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) if not me: continue if EXPORT_UV: faceuv= me.faceUV else: faceuv = False # We have a valid mesh if EXPORT_TRI and me.faces: # Add a dummy object to it. has_quads = False for f in me.faces: if len(f) == 4: has_quads = True break if has_quads: oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) me.sel = True tempob = scn.objects.new(me) me.quadToTriangle(0) # more=0 shortest length oldmode = Mesh.Mode(oldmode) scn.objects.unlink(tempob) Mesh.Mode(oldmode) faces = [ f for f in me.faces ] if EXPORT_EDGES: edges = me.edges else: edges = [] if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write continue # dont bother with this mesh. if EXPORT_ROTX90: me.transform(ob_mat*mat_xrot90) else: me.transform(ob_mat) # High Quality Normals if EXPORT_NORMALS and faces: if EXPORT_NORMALS_HQ: BPyMesh.meshCalcNormals(me) else: # transforming normals is incorrect # when the matrix is scaled, # better to recalculate them me.calcNormals() # # Crash Blender #materials = me.getMaterials(1) # 1 == will return None in the list. materials = me.materials materialNames = [] materialItems = materials[:] if materials: for mat in materials: if mat: # !=None materialNames.append(mat.name) else: materialNames.append(None) # Cant use LC because some materials are None. # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. # Possible there null materials, will mess up indicies # but at least it will export, wait until Blender gets fixed. materialNames.extend((16-len(materialNames)) * [None]) materialItems.extend((16-len(materialItems)) * [None]) # Sort by Material, then images # so we dont over context switch in the obj file. if EXPORT_MORPH_TARGET: pass elif faceuv: try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth)) except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) elif len(materials) > 1: try: faces.sort(key = lambda a: (a.mat, a.smooth)) except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) else: # no materials try: faces.sort(key = lambda a: a.smooth) except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth)) # Set the default mat to no material and no image. contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get. contextSmooth = None # Will either be true or false, set bad to force initialization switch. if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB: name1 = ob.name name2 = ob.getData(1) if name1 == name2: obnamestring = fixName(name1) else: obnamestring = '%s_%s' % (fixName(name1), fixName(name2)) if EXPORT_BLEN_OBS: file.write('o %s\n' % obnamestring) # Write Object name else: # if EXPORT_GROUP_BY_OB: file.write('g %s\n' % obnamestring) # Vert mesh = ob.getData() objmat = ob.getMatrix() for i in objmat: file.write('obm: %.6f %.6f %.6f %.6f\n' % tuple(i)) vgrouplist = mesh.getVertGroupNames() file.write('vgroupcount: %i\n' % len(vgrouplist)) for vgname in vgrouplist: file.write('vgroup: %s\n' % vgname) for v in mesh.verts: file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) influences = mesh.getVertexInfluences(v.index) file.write('influence: %i\n' % len(influences)) for name,weight in influences: file.write('GroupName: %s\n' % name) file.write('Weight: %f\n' % weight) # UV if faceuv: uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ uv_dict = {} # could use a set() here for f_index, f in enumerate(faces): for uv_index, uv in enumerate(f.uv): uvkey = veckey2d(uv) try: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] except: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) file.write('vt %.6f %.6f\n' % tuple(uv)) uv_unique_count = len(uv_dict) del uv, uvkey, uv_dict, f_index, uv_index # Only need uv_unique_count and uv_face_mapping # NORMAL, Smooth/Non smoothed. if EXPORT_NORMALS: for f in faces: if f.smooth: for v in f: noKey = veckey3d(v.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) else: # Hard, 1 normal from the face. noKey = veckey3d(f.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) if not faceuv: f_image = None for f_index, f in enumerate(faces): f_v= f.v f_smooth= f.smooth f_mat = min(f.mat, len(materialNames)-1) if faceuv: f_image = f.image f_uv= f.uv # MAKE KEY if faceuv and f_image: # Object is always true. key = materialNames[f_mat], f_image.name else: key = materialNames[f_mat], None # No image, use None instead. # CHECK FOR CONTEXT SWITCH if key == contextMat: pass # Context alredy switched, dont do anythoing else: if key[0] == None and key[1] == None: # Write a null material, since we know the context has changed. if EXPORT_GROUP_BY_MAT: file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null) file.write('usemtl (null)\n') # mat, image else: mat_data= MTL_DICT.get(key) if not mat_data: # First add to global dict so we can export to mtl # Then write mtl # Make a new names from the mat and image name, # converting any spaces to underscores with fixName. # If none image dont bother adding it to the name if key[1] == None: mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image else: mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image if EXPORT_GROUP_BY_MAT: file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null) file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null) contextMat = key if f_smooth != contextSmooth: if f_smooth: # on now off file.write('s 1\n') contextSmooth = f_smooth else: # was off now on file.write('s off\n') contextSmooth = f_smooth file.write('f') if faceuv: if EXPORT_NORMALS: if f_smooth: # Smoothed, use vertex normals for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ no)) # vert, uv, normal else: # No Normals for vi, v in enumerate(f_v): file.write( ' %d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi])) # vert, uv face_vert_index += len(f_v) else: # No UV's if EXPORT_NORMALS: if f_smooth: # Smoothed, use vertex normals for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ globalNormals[ veckey3d(v.no) ])) else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ no)) else: # No Normals for v in f_v: file.write( ' %d' % (\ v.index+totverts)) file.write('\n') # Write edges. if EXPORT_EDGES: LOOSE= Mesh.EdgeFlags.LOOSE for ed in edges: if ed.flag & LOOSE: file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) # Make the indicies global rather then per mesh totverts += len(me.verts) if faceuv: totuvco += uv_unique_count me.verts= None file.close() # Now we have all our materials, save them if EXPORT_MTL: write_mtl(mtlfilename) if EXPORT_COPY_IMAGES: dest_dir = filename # Remove chars until we are just the path. while dest_dir and dest_dir[-1] not in '\\/': dest_dir = dest_dir[:-1] if dest_dir: copy_images(dest_dir) else: print '\tError: "%s" could not be used as a base for an image path.' % filename print "OBJ Export time: %.2f" % (sys.time() - time1)
def export(self, scene, world, alltextures,\ EXPORT_APPLY_MODIFIERS = False,\ EXPORT_TRI= False,\ ): print "Info: starting X3D export to " + self.filename + "..." self.writeHeader() # self.writeScript() self.writeNavigationInfo(scene) self.writeBackground(world, alltextures) self.writeFog(world) self.proto = 0 # COPIED FROM OBJ EXPORTER if EXPORT_APPLY_MODIFIERS: temp_mesh_name = '~tmp-mesh' # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) # -------------------------- for ob_main in scene.objects.context: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): objType=ob.type objName=ob.name self.matonly = 0 if objType == "Camera": self.writeViewpoint(ob, ob_mat, scene) elif objType in ("Mesh", "Curve", "Surf", "Text") : if EXPORT_APPLY_MODIFIERS or objType != 'Mesh': me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene) else: me = ob.getData(mesh=1) self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI) elif objType == "Lamp": data= ob.data datatype=data.type if datatype == Lamp.Types.Lamp: self.writePointLight(ob, ob_mat, data, world) elif datatype == Lamp.Types.Spot: self.writeSpotLight(ob, ob_mat, data, world) elif datatype == Lamp.Types.Sun: self.writeDirectionalLight(ob, ob_mat, data, world) else: self.writeDirectionalLight(ob, ob_mat, data, world) # do you think x3d could document what to do with dummy objects? #elif objType == "Empty" and objName != "Empty": # self.writeNode(ob, ob_mat) else: #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType) pass self.file.write("\n</Scene>\n</X3D>") if EXPORT_APPLY_MODIFIERS: if containerMesh: containerMesh.verts = None self.cleanup()
def write(filename, objects,\ EXPORT_NORMALS_HQ=False,\ EXPORT_MTL=True, EXPORT_COPY_IMAGES=False,\ EXPORT_APPLY_MODIFIERS=True, EXPORT_BLEN_OBS=True,\ EXPORT_GROUP_BY_OB=False): ''' Basic write function. The context and options must be alredy set This can be accessed externaly eg. write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. ''' def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) print 'WTF Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") file.write('<?xml version="1.0"?>\n') file.write('<OPEN_TRACK>\n') # Write Header # file.write('\n<!--\n' # + ' Blender3D v%s WTF File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ) # + ' www.blender3d.org\n' # + '-->\n\n') # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) del meshName del tempMesh # Initialize totals, these are updated each object totverts = totuvco = totno = 0 face_vert_index = 0 globalNormals = {} file.write('\n<library_objects>\n') # Get all meshs for ob_main in objects: obnamestring = fixName(ob_main.name) file.write('\t<object id="%s">\n' % obnamestring) # Write Object name for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): # Will work for non meshes now! :) # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) me = BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) if not me: file.write('\t\t<loc>%.6f %.6f %.6f</loc>\n' % tuple(ob_main.loc)) # Write Object name file.write('\t\t<rot>%.6f %.6f %.6f</rot>\n' % tuple(ob_main.rot)) # Write Object name continue faceuv = me.faceUV # We have a valid mesh if me.faces: # Add a dummy object to it. has_quads = False for f in me.faces: if len(f) == 4: has_quads = True break if has_quads: oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) me.sel = True tempob = scn.objects.new(me) me.quadToTriangle(0) # more=0 shortest length oldmode = Mesh.Mode(oldmode) scn.objects.unlink(tempob) Mesh.Mode(oldmode) # Make our own list so it can be sorted to reduce context switching faces = [ f for f in me.faces ] edges = me.edges if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write continue # dont bother with this mesh. me.transform(ob_mat) # High Quality Normals if faces: if EXPORT_NORMALS_HQ: BPyMesh.meshCalcNormals(me) else: # transforming normals is incorrect # when the matrix is scaled, # better to recalculate them me.calcNormals() # # Crash Blender #materials = me.getMaterials(1) # 1 == will return None in the list. materials = me.materials materialNames = [] materialItems = materials[:] if materials: for mat in materials: if mat: # !=None materialNames.append(mat.name) else: materialNames.append(None) # Cant use LC because some materials are None. # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken. # Possible there null materials, will mess up indicies # but at least it will export, wait until Blender gets fixed. materialNames.extend((16-len(materialNames)) * [None]) materialItems.extend((16-len(materialItems)) * [None]) # Sort by Material, then images # so we dont over context switch in the obj file. if faceuv: try: faces.sort(key = lambda a: (a.mat, a.image, a.smooth)) except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth))) elif len(materials) > 1: try: faces.sort(key = lambda a: (a.mat, a.smooth)) except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth))) else: # no materials try: faces.sort(key = lambda a: a.smooth) except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth)) # Set the default mat to no material and no image. contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get. contextSmooth = None # Will either be true or false, set bad to force initialization switch. if len(faces) > 0: file.write('\t\t<mesh>\n') else: file.write('\t\t<curve>\n') vertname = "%s-Vertices" % obnamestring vertarrayname = "%s-Array" % vertname normname = "%s-Normals" % obnamestring normarrayname = "%s-Array" % normname texname = "%s-TexCoord" % obnamestring texarrayname = "%s-Array" % texname # Vert file.write('\t\t\t<float_array count="%d" id="%s">' % (len(me.verts), vertarrayname)) for v in me.verts: file.write(' %.6f %.6f %.6f' % tuple(v.co)) file.write('</float_array>\n') file.write('\t\t\t<vertices id="%s" source="#%s" />\n' % (vertname, vertarrayname)) # UV if faceuv: file.write('\t\t\t<float_array id="%s">' % texarrayname) uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ uv_dict = {} # could use a set() here for f_index, f in enumerate(faces): for uv_index, uv in enumerate(f.uv): uvkey = veckey2d(uv) try: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] except: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) file.write(' %.6f %.6f' % tuple(uv)) uv_unique_count = len(uv_dict) del uv, uvkey, uv_dict, f_index, uv_index # Only need uv_unique_count and uv_face_mapping file.write('</float_array>\n') file.write('\t\t\t<texcoords id="%s" source="#%s" />\n' % (texname, texarrayname)) # NORMAL, Smooth/Non smoothed. if len(faces) > 0: file.write('\t\t\t<float_array id="%s">' % normarrayname) for f in faces: if f.smooth: for v in f: noKey = veckey3d(v.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write(' %.6f %.6f %.6f' % noKey) else: # Hard, 1 normal from the face. noKey = veckey3d(f.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write(' %.6f %.6f %.6f' % noKey) file.write('</float_array>\n') file.write('\t\t\t<normals id="%s" source="#%s" />\n' % (normname, normarrayname)) if not faceuv: f_image = None in_triangles = False for f_index, f in enumerate(faces): f_v= f.v f_smooth= f.smooth f_mat = min(f.mat, len(materialNames)-1) if faceuv: f_image = f.image f_uv= f.uv # MAKE KEY if faceuv and f_image: # Object is always true. key = materialNames[f_mat], f_image.name else: key = materialNames[f_mat], None # No image, use None instead. # CHECK FOR CONTEXT SWITCH if key == contextMat: pass # Context alredy switched, dont do anythoing else: if key[0] == None and key[1] == None: # Write a null material, since we know the context has changed. if in_triangles: file.write('</p>\n') file.write('\t\t\t</triangles>\n') file.write('\t\t\t<triangles id="%s_%s">\n' % (fixName(ob.name), fixName(ob.getData(1)))) in_triangles = True else: mat_data= MTL_DICT.get(key) if not mat_data: # First add to global dict so we can export to mtl # Then write mtl # Make a new names from the mat and image name, # converting any spaces to underscores with fixName. # If none image dont bother adding it to the name if key[1] == None: mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image else: mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image if in_triangles: file.write('</p>\n') file.write('\t\t\t</triangles>\n') file.write('\t\t\t<triangles id="%s_%s_%s" material="#%s">\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0], mat_data[0]) ) in_triangles = True file.write('\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n' % vertname) file.write('\t\t\t\t<input offset="1" semantic="NORMAL" source="#%s" />\n' % normname) if faceuv: file.write('\t\t\t\t<input offset="2" semantic="TEXCOORD" source="#%s" />\n' % texname) file.write('\t\t\t\t<p>') contextMat = key if f_smooth != contextSmooth: if f_smooth: # on now off # file.write('s 1\n') contextSmooth = f_smooth else: # was off now on # file.write('s off\n') contextSmooth = f_smooth if faceuv: if f_smooth: # Smoothed, use vertex normals for vi, v in enumerate(f_v): file.write( ' %d %d %d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for vi, v in enumerate(f_v): file.write( ' %d %d %d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ no)) # vert, uv, normal face_vert_index += len(f_v) else: # No UV's if f_smooth: # Smoothed, use vertex normals for v in f_v: file.write( ' %d %d' % (\ v.index+totverts,\ globalNormals[ veckey3d(v.no) ])) else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for v in f_v: file.write( ' %d %d' % (\ v.index+totverts,\ no)) if in_triangles: file.write('</p>\n') file.write('\t\t\t</triangles>\n') # Write edges. LOOSE = Mesh.EdgeFlags.LOOSE has_edge = False for ed in edges: if ed.flag & LOOSE: has_edge = True if has_edge: file.write('\t\t\t<edges>\n') file.write('\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n' % vertname) file.write('\t\t\t\t<p>') for ed in edges: if ed.flag & LOOSE: file.write(' %d %d' % (ed.v1.index+totverts, ed.v2.index+totverts)) file.write('</p>\n') file.write('\t\t\t</edges>\n') # Make the indicies global rather then per mesh # totverts += len(me.verts) # if faceuv: # totuvco += uv_unique_count me.verts= None if len(faces) > 0: file.write('\t\t</mesh>\n') else: file.write('\t\t</curve>\n') file.write('\t</object>\n') file.write('</library_objects>\n\n') # Now we have all our materials, save them if EXPORT_MTL: write_library_materials(file) # Save the groups write_library_groups(file) file.write('</OPEN_TRACK>\n') file.close() if EXPORT_COPY_IMAGES: dest_dir = filename # Remove chars until we are just the path. while dest_dir and dest_dir[-1] not in '\\/': dest_dir = dest_dir[:-1] if dest_dir: copy_images(dest_dir) else: print '\tError: "%s" could not be used as a base for an image path.' % filename print "WTF Export time: %.2f" % (sys.time() - time1)
def export(self, scene, world, alltextures,\ EXPORT_APPLY_MODIFIERS = False,\ EXPORT_TRI= False,\ ): print "Info: starting X3D export to " + self.filename + "..." self.writeHeader() # self.writeScript() self.writeNavigationInfo(scene) self.writeBackground(world, alltextures) self.writeFog(world) self.proto = 0 # COPIED FROM OBJ EXPORTER if EXPORT_APPLY_MODIFIERS: temp_mesh_name = '~tmp-mesh' # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) # -------------------------- for ob_main in scene.objects.context: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): objType = ob.type objName = ob.name self.matonly = 0 if objType == "Camera": self.writeViewpoint(ob, ob_mat, scene) elif objType in ("Mesh", "Curve", "Surf", "Text"): if EXPORT_APPLY_MODIFIERS or objType != 'Mesh': me = BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene) else: me = ob.getData(mesh=1) self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI=EXPORT_TRI) elif objType == "Lamp": data = ob.data datatype = data.type if datatype == Lamp.Types.Lamp: self.writePointLight(ob, ob_mat, data, world) elif datatype == Lamp.Types.Spot: self.writeSpotLight(ob, ob_mat, data, world) elif datatype == Lamp.Types.Sun: self.writeDirectionalLight(ob, ob_mat, data, world) else: self.writeDirectionalLight(ob, ob_mat, data, world) # do you think x3d could document what to do with dummy objects? #elif objType == "Empty" and objName != "Empty": # self.writeNode(ob, ob_mat) else: #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType) pass self.file.write("\n</Scene>\n</X3D>") if EXPORT_APPLY_MODIFIERS: if containerMesh: containerMesh.verts = None self.cleanup()
def saveBR2(filename): if not filename.lower().endswith('.br2'): filename += '.br2' if not BPyMessages.Warning_SaveOver(filename): return print "Start BR2 Export..." Blender.Window.WaitCursor(1) file = open( filename, 'wb') scene = Blender.Scene.GetCurrent() allObjects = scene.objects filedata = "// Nexus Buddy BR2 - Exported from Blender for import to Nexus Buddy 2\n" modelObs = {} modelMeshes = {} # will need list of these for multi-skeleton boneIds = {} for object in allObjects: if object.type == 'Armature': modelObs[object.name] = object if object.type == 'Mesh': parentArmOb = BPyObject.getObjectArmature(object) if not parentArmOb.name in modelMeshes: modelMeshes[parentArmOb.name] = [] modelMeshes[parentArmOb.name].append(object) for modelObName in modelObs.keys(): # Write Skeleton filedata += "skeleton\n" armOb = modelObs[modelObName] armature = armOb.data # Calc bone depths and sort boneDepths = [] for bone in armature.bones.values(): boneDepth = getBoneTreeDepth(bone, 0) boneDepths.append((bone, boneDepth)) boneDepths = sorted(boneDepths, key=lambda k: k[0].name) boneDepths = sorted(boneDepths, key=lambda k: k[1]) sortedBones = boneDepths for boneid, boneTuple in enumerate(sortedBones): boneIds[boneTuple[0].name] = boneid #print 'boneId: %d: %s (depth:%s)' % (boneid, boneTuple[0].name, sortedBones[boneid][1]) # Write World Bone filedata += '%d "%s" %d ' % (0, armOb.name, -1) filedata += '%.8f %.8f %.8f ' % (0.0, 0.0, 0.0) filedata += '%.8f %.8f %.8f %.8f ' % (0.0, 0.0, 0.0, 1.0) filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f\n' % (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0) for boneid, boneTuple in enumerate(sortedBones): bone = boneTuple[0] boneDepth = boneTuple[1] #boneid = boneid + 1 # World bone is zero position, orientationQuat = getTranslationOrientation(bone, file) # Get Inverse World Matrix for bone t = bone.matrix['ARMATURESPACE'].copy().invert() invWorldMatrix = Matrix([t[0][1], -t[0][0], t[0][2], t[0][3]], [t[1][1], -t[1][0], t[1][2], t[1][3]], [t[2][1], -t[2][0], t[2][2], t[2][3]], [t[3][1], -t[3][0], t[3][2], t[3][3]]) outputBoneName = bone.name if len(outputBoneName) == 29: for item in armOb.getAllProperties(): if (("B_" + outputBoneName) == item.getName()): outputBoneName = item.getData() print 'Decode Bone Name: "%s" >' % item.getName() print ' "%s"' % item.getData() break filedata += '%d "%s" ' % (boneid + 1, outputBoneName) # Adjust bone ids + 1 as zero is the World Bone parentBoneId = 0 if bone.hasParent(): parentBoneId = boneIds[bone.parent.name] + 1 # Adjust bone ids + 1 as zero is the World Bone filedata += '%d ' % parentBoneId filedata +='%.8f %.8f %.8f ' % (position[0], position[1], position[2]) filedata +='%.8f %.8f %.8f %.8f ' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0]) # GR2 uses x,y,z,w for Quaternions rather than w,x,y,z filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f' % (invWorldMatrix[0][0], invWorldMatrix[0][1], invWorldMatrix[0][2], invWorldMatrix[0][3], invWorldMatrix[1][0], invWorldMatrix[1][1], invWorldMatrix[1][2], invWorldMatrix[1][3], invWorldMatrix[2][0], invWorldMatrix[2][1], invWorldMatrix[2][2], invWorldMatrix[2][3], invWorldMatrix[3][0], invWorldMatrix[3][1], invWorldMatrix[3][2], invWorldMatrix[3][3]) #End of bone line filedata += "\n" filedata += 'meshes:%d\n' % len(modelMeshes[modelObName]) for meshObject in modelMeshes[modelObName]: mesh = meshObject.data meshName = meshObject.name filedata += 'mesh:"%s"\n' % meshName parentArmOb = BPyObject.getObjectArmature(meshObject) # Fetch long mesh names from Armature properties if len(meshName) == 19: for item in parentArmOb.getAllProperties(): if ("M_" + meshName == item.getName()): meshName = item.getData() print 'Decode Mesh Name: %s > %s' % (item.getName(), item.getData()) break #file.write('meshname:%s\n' % meshName) #file.write('parent Arm:%s\n' % parentArmOb) weights = meshNormalizedWeights(mesh) vertexBoneWeights = {} for boneName in parentArmOb.data.bones.keys(): vgroupDataForBone = getBoneWeights(boneName, weights) #file.write('bone:%s vg:%s\n' % (boneName, vgroupDataForBone)) for vgData in vgroupDataForBone: vertexId = vgData[0] weight = vgData[1] if not vertexId in vertexBoneWeights: vertexBoneWeights[vertexId] = [] vertexBoneWeights[vertexId].append((boneName, weight)) #file.write('vert:%d bone:%s \n' % (vertexId, (boneName, weight))) grannyVertexBoneWeights = {} for vertId in vertexBoneWeights.keys(): #file.write('vert:%d ' % vertId) boneIdsList = [] boneWeightsList = [] firstBoneId = 0 for i in range(4): if i < len(vertexBoneWeights[vertId]): vertexBoneWeightTuple = vertexBoneWeights[vertId][i] boneName = vertexBoneWeightTuple[0] boneIdsList.append(boneIds[boneName] + 1) boneWeightsList.append(round(vertexBoneWeightTuple[1] * 255)) if i == 0: firstBoneId = boneIds[boneName] + 1 else: boneIdsList.append(firstBoneId) boneWeightsList.append(0) runningTotal = 0 for i, weight in enumerate(boneWeightsList): runningTotal = runningTotal + weight if runningTotal > 255: boneWeightsList[i] = weight - 1 break if not vertId in grannyVertexBoneWeights: grannyVertexBoneWeights[vertId] = [] grannyVertexBoneWeights[vertId] = (boneIdsList, boneWeightsList) #file.write('%s %s ' % (boneIdsList, boneWeightsList)) #file.write("\n") position, orientationQuat = getTranslationOrientation(meshObject, file) #file.write('position:%.8f %.8f %.8f\n' % (position[0], position[1], position[2])) #file.write('orientationQuat:%.8f %.8f %.8f %.8f\n' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0])) #file.write(meshName+"\n") filedata += "vertices\n" # Determine unique vertex/UVs for output uniqueVertSet = set() uniqueVertUVIndexes = {} uniqueVertUVs = [] currentVertUVIndex = 0 currentTriangleId = 0 triangleVertUVIndexes = [] for triangle in mesh.faces: vertIds = [v.index for v in triangle] vertIds = tuple(vertIds) triangleVertUVIndexes.append([]) for i, uv in enumerate(triangle.uv): vertexId = vertIds[i] uvt = tuple(uv) vertSig = '%i|%.8f|%.8f' % (vertexId, uvt[0], uvt[1]) if vertSig in uniqueVertSet: triangleVertUVIndex = uniqueVertUVIndexes[vertSig] else: uniqueVertSet.add(vertSig) uniqueVertUVIndexes[vertSig] = currentVertUVIndex uniqueVertUVs.append((vertexId, uvt[0], uvt[1])) triangleVertUVIndex = currentVertUVIndex currentVertUVIndex = currentVertUVIndex + 1 triangleVertUVIndexes[currentTriangleId].append(triangleVertUVIndex) currentTriangleId = currentTriangleId + 1 meshVerts = {} for i,vert in enumerate(mesh.verts): meshVerts[i] = vert # Write Vertices for uniqueVertUV in uniqueVertUVs: index = uniqueVertUV[0] vert = meshVerts[index] vertCoord = tuple(vert.co) vertNormal = tuple(vert.no) filedata +='%.8f %.8f %.8f ' % (vertCoord[0] + position[0], vertCoord[1] + position[1], vertCoord[2] + position[2]) filedata +='%.8f %.8f %.8f ' % vertNormal filedata +='%.8f %.8f ' % (uniqueVertUV[1], 1 - uniqueVertUV[2]) if index in grannyVertexBoneWeights: vBoneWeightTuple = grannyVertexBoneWeights[index] else: raise "Error: Mesh has unweighted vertices!" #vBoneWeightTuple = ([-1,-1,-1,-1],[-1,-1,-1,-1]) # Unweighted vertex - raise error filedata +='%d %d %d %d ' % (vBoneWeightTuple[0][0], vBoneWeightTuple[0][1],vBoneWeightTuple[0][2],vBoneWeightTuple[0][3]) # Bone Ids filedata +='%d %d %d %d\n' % (vBoneWeightTuple[1][0], vBoneWeightTuple[1][1],vBoneWeightTuple[1][2],vBoneWeightTuple[1][3]) # Bone Weights # Write Triangles filedata += "triangles\n" for triangle in triangleVertUVIndexes: #filedata += '%i %i %i\n' % tuple(triangle) filedata += '%i %i %i\n' % (triangle[0],triangle[1],triangle[2]) filedata += "end" file.write(filedata) file.close() Blender.Window.WaitCursor(0) print "End BR2 Export."
def write(filename, objects,\ EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True): ''' Basic write function. The context and options must be alredy set This can be accessed externaly eg. write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. ''' def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) print 'EOL MESH Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") # Write Header file.write('# Blender3D v%s EOL MESH File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1])) file.write('# www.blender3d.org\n') # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) if EXPORT_ROTX90: mat_xrot90 = Blender.Mathutils.RotationMatrix(-90, 4, 'x') del meshName del tempMesh # Initialize totals, these are updated each object totverts = totuvco = totno = 1 face_vert_index = 1 globalNormals = {} # Get all meshs for ob_main in objects: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): # Will work for non meshes now! :) # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) me = BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) if not me: continue faceuv = me.faceUV has_quads = False for f in me.faces: if len(f) == 4: has_quads = True break if has_quads: oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) me.sel = True tempob = scn.objects.new(me) me.quadToTriangle(0) # more=0 shortest length oldmode = Mesh.Mode(oldmode) scn.objects.unlink(tempob) Mesh.Mode(oldmode) edges = me.edges faces = [f for f in me.faces] if EXPORT_ROTX90: me.transform(ob_mat * mat_xrot90) else: me.transform(ob_mat) # Vert mesh = ob.getData() objmat = ob.getMatrix() for i in objmat: file.write('obm: %.6f %.6f %.6f %.6f\n' % tuple(i)) vgrouplist = mesh.getVertGroupNames() file.write('vgroupcount: %i\n' % len(vgrouplist)) for vgname in vgrouplist: file.write('vgroup: %s\n' % vgname) file.write('vertexcount: %i\n' % len(mesh.verts)) for v in mesh.verts: file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) influences = mesh.getVertexInfluences(v.index) file.write('influence: %i\n' % len(influences)) for name, weight in influences: file.write('groupname: %s\n' % name) file.write('weight: %f\n' % weight) # UV if faceuv: uv_face_mapping = [[0, 0, 0, 0] for f in faces ] # a bit of a waste for tri's :/ uv_dict = {} # could use a set() here for f_index, f in enumerate(faces): for uv_index, uv in enumerate(f.uv): uvkey = veckey2d(uv) try: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] except: uv_face_mapping[f_index][uv_index] = uv_dict[ uvkey] = len(uv_dict) file.write('vt %.6f %.6f\n' % tuple(uv)) uv_unique_count = len(uv_dict) del uv, uvkey, uv_dict, f_index, uv_index # Only need uv_unique_count and uv_face_mapping file.write('uvcount: %i\n' % uv_unique_count) # NORMAL, Smooth/Non smoothed. for f in faces: if f.smooth: for v in f: noKey = veckey3d(v.no) if not globalNormals.has_key(noKey): globalNormals[noKey] = totno totno += 1 file.write('vn %.6f %.6f %.6f\n' % noKey) else: # Hard, 1 normal from the face. noKey = veckey3d(f.no) if not globalNormals.has_key(noKey): globalNormals[noKey] = totno totno += 1 file.write('vn %.6f %.6f %.6f\n' % noKey) file.write('normalcount: %i\n' % len(globalNormals)) if not faceuv: f_image = None file.write('facecount: %i\n' % len(faces)) for f_index, f in enumerate(faces): f_v = f.v f_smooth = f.smooth if faceuv: f_uv = f.uv file.write('f') if faceuv: if f_smooth: # Smoothed, use vertex normals for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals no = globalNormals[veckey3d(f.no)] for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ no)) # vert, uv, normal face_vert_index += len(f_v) else: # No UV's if f_smooth: # Smoothed, use vertex normals for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ globalNormals[ veckey3d(v.no) ])) else: # No smoothing, face normals no = globalNormals[veckey3d(f.no)] for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ no)) file.write('\n') # Write edges. LOOSE = Mesh.EdgeFlags.LOOSE for ed in edges: if ed.flag & LOOSE: file.write( 'f %d %d\n' % (ed.v1.index + totverts, ed.v2.index + totverts)) # Make the indicies global rather then per mesh totverts += len(me.verts) if faceuv: totuvco += uv_unique_count me.verts = None file.close() # Now we have all our materials, save them print "MESH Export time: %.2f" % (sys.time() - time1)
def write(filename, objects,\ EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True): ''' Basic write function. The context and options must be alredy set This can be accessed externaly eg. write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. ''' def veckey3d(v): return round(v.x, 6), round(v.y, 6), round(v.z, 6) def veckey2d(v): return round(v.x, 6), round(v.y, 6) print 'EOL MESH Export path: "%s"' % filename temp_mesh_name = '~tmp-mesh' time1 = sys.time() scn = Scene.GetCurrent() file = open(filename, "w") # Write Header file.write('# Blender3D v%s EOL MESH File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) file.write('# www.blender3d.org\n') # Get the container mesh. - used for applying modifiers and non mesh objects. containerMesh = meshName = tempMesh = None for meshName in Blender.NMesh.GetNames(): if meshName.startswith(temp_mesh_name): tempMesh = Mesh.Get(meshName) if not tempMesh.users: containerMesh = tempMesh if not containerMesh: containerMesh = Mesh.New(temp_mesh_name) if EXPORT_ROTX90: mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x') del meshName del tempMesh # Initialize totals, these are updated each object totverts = totuvco = totno = 1 face_vert_index = 1 globalNormals = {} # Get all meshs for ob_main in objects: for ob, ob_mat in BPyObject.getDerivedObjects(ob_main): # Will work for non meshes now! :) # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None) me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) if not me: continue faceuv= me.faceUV has_quads = False for f in me.faces: if len(f) == 4: has_quads = True break if has_quads: oldmode = Mesh.Mode() Mesh.Mode(Mesh.SelectModes['FACE']) me.sel = True tempob = scn.objects.new(me) me.quadToTriangle(0) # more=0 shortest length oldmode = Mesh.Mode(oldmode) scn.objects.unlink(tempob) Mesh.Mode(oldmode) edges = me.edges faces = [ f for f in me.faces ] if EXPORT_ROTX90: me.transform(ob_mat*mat_xrot90) else: me.transform(ob_mat) # Vert mesh = ob.getData() objmat = ob.getMatrix() for i in objmat: file.write('obm: %.6f %.6f %.6f %.6f\n' % tuple(i)) vgrouplist = mesh.getVertGroupNames() file.write('vgroupcount: %i\n' % len(vgrouplist)) for vgname in vgrouplist: file.write('vgroup: %s\n' % vgname) file.write('vertexcount: %i\n' % len(mesh.verts)) for v in mesh.verts: file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) influences = mesh.getVertexInfluences(v.index) file.write('influence: %i\n' % len(influences)) for name,weight in influences: file.write('groupname: %s\n' % name) file.write('weight: %f\n' % weight) # UV if faceuv: uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/ uv_dict = {} # could use a set() here for f_index, f in enumerate(faces): for uv_index, uv in enumerate(f.uv): uvkey = veckey2d(uv) try: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] except: uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict) file.write('vt %.6f %.6f\n' % tuple(uv)) uv_unique_count = len(uv_dict) del uv, uvkey, uv_dict, f_index, uv_index # Only need uv_unique_count and uv_face_mapping file.write('uvcount: %i\n' % uv_unique_count) # NORMAL, Smooth/Non smoothed. for f in faces: if f.smooth: for v in f: noKey = veckey3d(v.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) else: # Hard, 1 normal from the face. noKey = veckey3d(f.no) if not globalNormals.has_key( noKey ): globalNormals[noKey] = totno totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) file.write('normalcount: %i\n' % len(globalNormals)) if not faceuv: f_image = None file.write('facecount: %i\n' % len(faces)) for f_index, f in enumerate(faces): f_v= f.v f_smooth= f.smooth if faceuv: f_uv= f.uv file.write('f') if faceuv: if f_smooth: # Smoothed, use vertex normals for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ totuvco + uv_face_mapping[f_index][vi],\ no)) # vert, uv, normal face_vert_index += len(f_v) else: # No UV's if f_smooth: # Smoothed, use vertex normals for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ globalNormals[ veckey3d(v.no) ])) else: # No smoothing, face normals no = globalNormals[ veckey3d(f.no) ] for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ no)) file.write('\n') # Write edges. LOOSE= Mesh.EdgeFlags.LOOSE for ed in edges: if ed.flag & LOOSE: file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts)) # Make the indicies global rather then per mesh totverts += len(me.verts) if faceuv: totuvco += uv_unique_count me.verts= None file.close() # Now we have all our materials, save them print "MESH Export time: %.2f" % (sys.time() - time1)