diff options
Diffstat (limited to 'release/scripts/export_obj.py')
-rw-r--r-- | release/scripts/export_obj.py | 198 |
1 files changed, 108 insertions, 90 deletions
diff --git a/release/scripts/export_obj.py b/release/scripts/export_obj.py index 4c7ced2d200..8e7374f02b5 100644 --- a/release/scripts/export_obj.py +++ b/release/scripts/export_obj.py @@ -68,15 +68,11 @@ def fixName(name): else: return name.replace(' ', '_') -# Used to add the scene name into the filename without using odd chars -global MTL_DICT - # A Dict of Materials # (material.name, image.name):matname_imagename # matname_imagename has gaps removed. MTL_DICT = {} def write_mtl(filename): - global MTL_DICT world = Blender.World.GetCurrent() if world: @@ -88,23 +84,14 @@ def write_mtl(filename): file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1]) file.write('# Material Count: %i\n' % len(MTL_DICT)) # Write material/image combinations we have used. - for key, mtl_mat_name in MTL_DICT.iteritems(): + for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems(): # Get the Blender data for the material and the image. # Having an image named None will make a bug, dont do it :) file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname - if key[0] == None: - #write a dummy material here? - file.write('Ns 0\n') - file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour, - file.write('Kd 0.8 0.8 0.8\n') - file.write('Ks 0.8 0.8 0.8\n') - file.write('d 1\n') # No alpha - file.write('illum 2\n') # light normaly - else: - mat = Blender.Material.Get(key[0]) + if mat: file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.amb for c in worldAmb]) ) # Ambient, uses mirror colour, file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse @@ -120,13 +107,20 @@ def write_mtl(filename): else: file.write('illum 2\n') # light normaly + else: + #write a dummy material here? + file.write('Ns 0\n') + file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour, + file.write('Kd 0.8 0.8 0.8\n') + file.write('Ks 0.8 0.8 0.8\n') + file.write('d 1\n') # No alpha + file.write('illum 2\n') # light normaly # Write images! - if key[1] != None: # We have an image on the face! - img = Image.Get(key[1]) + if img: # We have an image on the face! file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image - elif key[0] != None: # No face image. if we havea material search for MTex image. + elif not mat: # No face image. if we havea material search for MTex image. for mtex in mat.getTextures(): if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: try: @@ -157,26 +151,26 @@ def copy_images(dest_dir): # Get unique image names uniqueImages = {} - for matname, imagename in MTL_DICT.iterkeys(): # Only use image name + for matname, mat, image in MTL_DICT.itervalues(): # Only use image name # Get Texface images - if imagename != None: - uniqueImages[imagename] = None # Should use sets here. wait until Python 2.4 is default. + if image: + uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default. # Get MTex images - if matname != None: - mat= Blender.Material.Get(matname) + if mat: for mtex in mat.getTextures(): if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: - try: - uniqueImages[mtex.tex.image.name] = None - except: - pass + image_tex = mtex.tex.image + if image_tex: + try: + uniqueImages[image_tex] = image_tex + except: + pass # Now copy images copyCount = 0 - for imageName in uniqueImages.iterkeys(): - bImage = Image.Get(imageName) + for bImage in uniqueImages.itervalues(): image_path = sys.expandpath(bImage.filename) if sys.exists(image_path): # Make a name for the target path. @@ -187,12 +181,6 @@ def copy_images(dest_dir): copyCount+=1 print '\tCopied %d images' % copyCount -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 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,\ @@ -204,8 +192,14 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) 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 - global MTL_DICT temp_mesh_name = '~tmp-mesh' time1 = sys.time() @@ -241,7 +235,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) # Initialize totals, these are updated each object totverts = totuvco = totno = 1 - face_vert_index = 1 # used for uvs now + face_vert_index = 1 globalNormals = {} @@ -253,7 +247,11 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn) if not me: continue - faceuv= me.faceUV + + if EXPORT_UV: + faceuv= me.faceUV + else: + faceuv = False # We have a valid mesh if EXPORT_TRI and me.faces: @@ -293,14 +291,21 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) me.transform(ob_mat) # High Quality Normals - if EXPORT_NORMALS and EXPORT_NORMALS_HQ and faces: - BPyMesh.meshCalcNormals(me) + 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 @@ -313,13 +318,13 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) # 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 and EXPORT_UV: + 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: @@ -353,10 +358,23 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) file.write('v %.6f %.6f %.6f\n' % tuple(v.co)) # UV - if faceuv and EXPORT_UV: - for f in faces: - for uv in f.uv: - file.write('vt %.6f %.6f 0.0\n' % tuple(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: @@ -376,18 +394,22 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) totno +=1 file.write('vn %.6f %.6f %.6f\n' % noKey) - for f in faces: + 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 EXPORT_UV and faceuv and f.image: # Object is always true. - key = materialNames[min(f.mat,len(materialNames)-1)], f.image.name - #key = materialNames[f.mat], f.image.name + if faceuv and f_image: # Object is always true. + key = materialNames[f_mat], f_image.name else: - key = materialNames[min(f.mat,len(materialNames)-1)], None # No image, use None instead. - #key = materialNames[f.mat], None # No image, use None instead. + key = materialNames[f_mat], None # No image, use None instead. # CHECK FOR CONTEXT SWITCH if key == contextMat: @@ -395,16 +417,13 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) else: if key[0] == None and key[1] == None: # Write a null material, since we know the context has changed. - matstring = '(null)' + 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: - try: # Faster to try then 2x dict lookups. - # We have the material, just need to write the context switch, - matstring = MTL_DICT[key] - - - except KeyError: + mat_data= MTL_DICT.get(key) + if not mat_data: # First add to global dict so we can export to mtl # Then write mtl @@ -413,32 +432,31 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) # If none image dont bother adding it to the name if key[1] == None: - matstring = MTL_DICT[key] ='%s' % fixName(key[0]) + mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image else: - matstring = MTL_DICT[key] = '%s_%s' % (fixName(key[0]), fixName(key[1])) - - if EXPORT_GROUP_BY_MAT: - file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), matstring) ) # can be mat_image or (null) - file.write('usemtl %s\n' % matstring) # can be mat_image or (null) + 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 contextSmooth: # on now off - file.write('s off\n') - contextSmooth = True - else: # was off now on + if f_smooth != contextSmooth: + if f_smooth: # on now off file.write('s 1\n') - contextSmooth = False + contextSmooth = f_smooth + else: # was off now on + file.write('s off\n') + contextSmooth = f_smooth file.write('f') - if faceuv and EXPORT_UV: + if faceuv: if EXPORT_NORMALS: - if f.smooth: # Smoothed, use vertex normals + if f_smooth: # Smoothed, use vertex normals for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ - face_vert_index + vi,\ + totuvco + uv_face_mapping[f_index][vi],\ globalNormals[ veckey3d(v.no) ])) # vert, uv, normal else: # No smoothing, face normals @@ -446,20 +464,20 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) for vi, v in enumerate(f_v): file.write( ' %d/%d/%d' % (\ v.index+totverts,\ - face_vert_index + vi,\ + 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,\ - face_vert_index + vi)) # vert, uv + 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 + if f_smooth: # Smoothed, use vertex normals for v in f_v: file.write( ' %d//%d' % (\ v.index+totverts,\ @@ -486,6 +504,8 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False) # Make the indicies global rather then per mesh totverts += len(me.verts) + if faceuv: + totuvco += uv_unique_count me.verts= None file.close() @@ -512,9 +532,8 @@ def write_ui(filename): if not filename.lower().endswith('.obj'): filename += '.obj' - #if not BPyMessages.Warning_SaveOver(filename): - # return - + if not BPyMessages.Warning_SaveOver(filename): + return EXPORT_APPLY_MODIFIERS = Draw.Create(1) EXPORT_ROTX90 = Draw.Create(1) @@ -535,7 +554,6 @@ def write_ui(filename): # removed too many options are bad! - # Get USER Options pup_block = [\ ('Context...'),\ @@ -631,14 +649,14 @@ def write_ui(filename): full_path= ''.join(context_name) - if BPyMessages.Warning_SaveOver(full_path): - # EXPORT THE FILE. - write(full_path, export_objects,\ - EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ - EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ - EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ - EXPORT_ROTX90, EXPORT_BLEN_OBS,\ - EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_MORPH_TARGET) + # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. + # EXPORT THE FILE. + write(full_path, export_objects,\ + EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ + EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ + EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ + EXPORT_ROTX90, EXPORT_BLEN_OBS,\ + EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_MORPH_TARGET) Blender.Set('curframe', orig_frame) |