diff options
author | Howard Trickey <howard.trickey@gmail.com> | 2022-02-03 15:55:33 +0300 |
---|---|---|
committer | Howard Trickey <howard.trickey@gmail.com> | 2022-02-03 15:55:33 +0300 |
commit | d364a7b4253e974ad3cc5c76e08478fa69ca0a46 (patch) | |
tree | f17b84f74e5a27ec0ef0fd4c8b90213fed8700e1 /io_scene_obj/export_obj.py | |
parent | 81fc6b060b6cc7d1aefa4afdd60dc057dc334cc5 (diff) |
Split io_scene_obj into separate io_import_obj and io_export_obj.
Also put an " - Old" by the name of the exporter.
The intention is that we won't load the Python exporter, but if a user wants
it, they can enable that addon.
Diffstat (limited to 'io_scene_obj/export_obj.py')
-rw-r--r-- | io_scene_obj/export_obj.py | 793 |
1 files changed, 0 insertions, 793 deletions
diff --git a/io_scene_obj/export_obj.py b/io_scene_obj/export_obj.py deleted file mode 100644 index e5466c76..00000000 --- a/io_scene_obj/export_obj.py +++ /dev/null @@ -1,793 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# <pep8 compliant> - -import os - -import bpy -from mathutils import Matrix, Vector, Color -from bpy_extras import io_utils, node_shader_utils - -from bpy_extras.wm_utils.progress_report import ( - ProgressReport, - ProgressReportSubstep, -) - - -def name_compat(name): - if name is None: - return 'None' - else: - return name.replace(' ', '_') - - -def mesh_triangulate(me): - import bmesh - bm = bmesh.new() - bm.from_mesh(me) - bmesh.ops.triangulate(bm, faces=bm.faces) - bm.to_mesh(me) - bm.free() - - -def write_mtl(scene, filepath, path_mode, copy_set, mtl_dict): - source_dir = os.path.dirname(bpy.data.filepath) - dest_dir = os.path.dirname(filepath) - - with open(filepath, "w", encoding="utf8", newline="\n") as f: - fw = f.write - - fw('# Blender MTL File: %r\n' % (os.path.basename(bpy.data.filepath) or "None")) - fw('# Material Count: %i\n' % len(mtl_dict)) - - mtl_dict_values = list(mtl_dict.values()) - mtl_dict_values.sort(key=lambda m: m[0]) - - # Write material/image combinations we have used. - # Using mtl_dict.values() directly gives un-predictable order. - for mtl_mat_name, mat in mtl_dict_values: - # Get the Blender data for the material and the image. - # Having an image named None will make a bug, dont do it :) - - fw('\nnewmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname - - mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat) if mat else None - - if mat_wrap: - use_mirror = mat_wrap.metallic != 0.0 - use_transparency = mat_wrap.alpha != 1.0 - - # XXX Totally empirical conversion, trying to adapt it - # (from 1.0 - 0.0 Principled BSDF range to 0.0 - 1000.0 OBJ specular exponent range): - # (1.0 - bsdf_roughness)^2 * 1000 - spec = (1.0 - mat_wrap.roughness) - spec *= spec * 1000 - fw('Ns %.6f\n' % spec) - - # Ambient - if use_mirror: - fw('Ka %.6f %.6f %.6f\n' % (mat_wrap.metallic, mat_wrap.metallic, mat_wrap.metallic)) - else: - fw('Ka %.6f %.6f %.6f\n' % (1.0, 1.0, 1.0)) - fw('Kd %.6f %.6f %.6f\n' % mat_wrap.base_color[:3]) # Diffuse - # XXX TODO Find a way to handle tint and diffuse color, in a consistent way with import... - fw('Ks %.6f %.6f %.6f\n' % (mat_wrap.specular, mat_wrap.specular, mat_wrap.specular)) # Specular - # Emission, not in original MTL standard but seems pretty common, see T45766. - emission_strength = mat_wrap.emission_strength - emission = [emission_strength * c for c in mat_wrap.emission_color[:3]] - fw('Ke %.6f %.6f %.6f\n' % tuple(emission)) - fw('Ni %.6f\n' % mat_wrap.ior) # Refraction index - fw('d %.6f\n' % mat_wrap.alpha) # Alpha (obj uses 'd' for dissolve) - - # See http://en.wikipedia.org/wiki/Wavefront_.obj_file for whole list of values... - # Note that mapping is rather fuzzy sometimes, trying to do our best here. - if mat_wrap.specular == 0: - fw('illum 1\n') # no specular. - elif use_mirror: - if use_transparency: - fw('illum 6\n') # Reflection, Transparency, Ray trace - else: - fw('illum 3\n') # Reflection and Ray trace - elif use_transparency: - fw('illum 9\n') # 'Glass' transparency and no Ray trace reflection... fuzzy matching, but... - else: - fw('illum 2\n') # light normally - - #### And now, the image textures... - image_map = { - "map_Kd": "base_color_texture", - "map_Ka": None, # ambient... - "map_Ks": "specular_texture", - "map_Ns": "roughness_texture", - "map_d": "alpha_texture", - "map_Tr": None, # transmission roughness? - "map_Bump": "normalmap_texture", - "disp": None, # displacement... - "refl": "metallic_texture", - "map_Ke": "emission_color_texture" if emission_strength != 0.0 else None, - } - - for key, mat_wrap_key in sorted(image_map.items()): - if mat_wrap_key is None: - continue - tex_wrap = getattr(mat_wrap, mat_wrap_key, None) - if tex_wrap is None: - continue - image = tex_wrap.image - if image is None: - continue - - filepath = io_utils.path_reference(image.filepath, source_dir, dest_dir, - path_mode, "", copy_set, image.library) - options = [] - if key == "map_Bump": - if mat_wrap.normalmap_strength != 1.0: - options.append('-bm %.6f' % mat_wrap.normalmap_strength) - if tex_wrap.translation != Vector((0.0, 0.0, 0.0)): - options.append('-o %.6f %.6f %.6f' % tex_wrap.translation[:]) - if tex_wrap.scale != Vector((1.0, 1.0, 1.0)): - options.append('-s %.6f %.6f %.6f' % tex_wrap.scale[:]) - if options: - fw('%s %s %s\n' % (key, " ".join(options), repr(filepath)[1:-1])) - else: - fw('%s %s\n' % (key, repr(filepath)[1:-1])) - - else: - # Write a dummy material here? - fw('Ns 500\n') - fw('Ka 0.8 0.8 0.8\n') - fw('Kd 0.8 0.8 0.8\n') - fw('Ks 0.8 0.8 0.8\n') - fw('d 1\n') # No alpha - fw('illum 2\n') # light normally - - -def test_nurbs_compat(ob): - if ob.type != 'CURVE': - return False - - for nu in ob.data.splines: - if nu.point_count_v == 1 and nu.type != 'BEZIER': # not a surface and not bezier - return True - - return False - - -def write_nurb(fw, ob, ob_mat): - tot_verts = 0 - cu = ob.data - - # use negative indices - for nu in cu.splines: - if nu.type == 'POLY': - DEG_ORDER_U = 1 - else: - DEG_ORDER_U = nu.order_u - 1 # odd but tested to be correct - - if nu.type == 'BEZIER': - print("\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported") - continue - - if nu.point_count_v > 1: - print("\tWarning, surface:", ob.name, "only poly and nurbs curves supported") - continue - - if len(nu.points) <= DEG_ORDER_U: - print("\tWarning, order_u is lower then vert count, skipping:", ob.name) - continue - - pt_num = 0 - do_closed = nu.use_cyclic_u - do_endpoints = (do_closed == 0) and nu.use_endpoint_u - - for pt in nu.points: - fw('v %.6f %.6f %.6f\n' % (ob_mat @ pt.co.to_3d())[:]) - pt_num += 1 - tot_verts += pt_num - - fw('g %s\n' % (name_compat(ob.name))) # name_compat(ob.getData(1)) could use the data name too - fw('cstype bspline\n') # not ideal, hard coded - fw('deg %d\n' % DEG_ORDER_U) # not used for curves but most files have it still - - curve_ls = [-(i + 1) for i in range(pt_num)] - - # 'curv' keyword - if do_closed: - if DEG_ORDER_U == 1: - pt_num += 1 - curve_ls.append(-1) - else: - pt_num += DEG_ORDER_U - curve_ls = curve_ls + curve_ls[0:DEG_ORDER_U] - - fw('curv 0.0 1.0 %s\n' % (" ".join([str(i) for i in curve_ls]))) # Blender has no U and V values for the curve - - # 'parm' keyword - tot_parm = (DEG_ORDER_U + 1) + pt_num - tot_parm_div = float(tot_parm - 1) - parm_ls = [(i / tot_parm_div) for i in range(tot_parm)] - - if do_endpoints: # end points, force param - for i in range(DEG_ORDER_U + 1): - parm_ls[i] = 0.0 - parm_ls[-(1 + i)] = 1.0 - - fw("parm u %s\n" % " ".join(["%.6f" % i for i in parm_ls])) - - fw('end\n') - - return tot_verts - - -def write_file(filepath, objects, depsgraph, scene, - EXPORT_TRI=False, - EXPORT_EDGES=False, - EXPORT_SMOOTH_GROUPS=False, - EXPORT_SMOOTH_GROUPS_BITFLAGS=False, - EXPORT_NORMALS=False, - EXPORT_UV=True, - EXPORT_MTL=True, - EXPORT_APPLY_MODIFIERS=True, - EXPORT_APPLY_MODIFIERS_RENDER=False, - 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, - EXPORT_GLOBAL_MATRIX=None, - EXPORT_PATH_MODE='AUTO', - progress=ProgressReport(), - ): - """ - Basic write function. The context and options must be already set - This can be accessed externally - eg. - write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options. - """ - if EXPORT_GLOBAL_MATRIX is None: - EXPORT_GLOBAL_MATRIX = Matrix() - - def veckey3d(v): - return round(v.x, 4), round(v.y, 4), round(v.z, 4) - - def veckey2d(v): - return round(v[0], 4), round(v[1], 4) - - 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 vertex 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_index in face.vertices: - vWeights = vWeightMap[vert_index] - for vGroupName, weight in vWeights: - weightDict[vGroupName] = weightDict.get(vGroupName, 0.0) + weight - - if weightDict: - return max((weight, vGroupName) for vGroupName, weight in weightDict.items())[1] - else: - return '(null)' - - with ProgressReportSubstep(progress, 2, "OBJ Export path: %r" % filepath, "OBJ Export Finished") as subprogress1: - with open(filepath, "w", encoding="utf8", newline="\n") as f: - fw = f.write - - # Write Header - fw('# Blender v%s OBJ File: %r\n' % (bpy.app.version_string, os.path.basename(bpy.data.filepath))) - fw('# www.blender.org\n') - - # Tell the obj file what material file to use. - if EXPORT_MTL: - mtlfilepath = os.path.splitext(filepath)[0] + ".mtl" - # filepath can contain non utf8 chars, use repr - fw('mtllib %s\n' % repr(os.path.basename(mtlfilepath))[1:-1]) - - # Initialize totals, these are updated each object - totverts = totuvco = totno = 1 - - face_vert_index = 1 - - # A Dict of Materials - # (material.name, image.name):matname_imagename # matname_imagename has gaps removed. - mtl_dict = {} - # Used to reduce the usage of matname_texname materials, which can become annoying in case of - # repeated exports/imports, yet keeping unique mat names per keys! - # mtl_name: (material.name, image.name) - mtl_rev_dict = {} - - copy_set = set() - - # Get all meshes - subprogress1.enter_substeps(len(objects)) - for i, ob_main in enumerate(objects): - # ignore dupli children - if ob_main.parent and ob_main.parent.instance_type in {'VERTS', 'FACES'}: - subprogress1.step("Ignoring %s, dupli child..." % ob_main.name) - continue - - obs = [(ob_main, ob_main.matrix_world)] - if ob_main.is_instancer: - obs += [(dup.instance_object.original, dup.matrix_world.copy()) - for dup in depsgraph.object_instances - if dup.parent and dup.parent.original == ob_main] - # ~ print(ob_main.name, 'has', len(obs) - 1, 'dupli children') - - subprogress1.enter_substeps(len(obs)) - for ob, ob_mat in obs: - with ProgressReportSubstep(subprogress1, 6) as subprogress2: - uv_unique_count = no_unique_count = 0 - - # Nurbs curve support - if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob): - ob_mat = EXPORT_GLOBAL_MATRIX @ ob_mat - totverts += write_nurb(fw, ob, ob_mat) - continue - # END NURBS - - ob_for_convert = ob.evaluated_get(depsgraph) if EXPORT_APPLY_MODIFIERS else ob.original - - try: - me = ob_for_convert.to_mesh() - except RuntimeError: - me = None - - if me is None: - continue - - # _must_ do this before applying transformation, else tessellation may differ - if EXPORT_TRI: - # _must_ do this first since it re-allocs arrays - mesh_triangulate(me) - - me.transform(EXPORT_GLOBAL_MATRIX @ ob_mat) - # If negative scaling, we have to invert the normals... - if ob_mat.determinant() < 0.0: - me.flip_normals() - - if EXPORT_UV: - faceuv = len(me.uv_layers) > 0 - if faceuv: - uv_layer = me.uv_layers.active.data[:] - else: - faceuv = False - - me_verts = me.vertices[:] - - # Make our own list so it can be sorted to reduce context switching - face_index_pairs = [(face, index) for index, face in enumerate(me.polygons)] - - if EXPORT_EDGES: - edges = me.edges - else: - edges = [] - - if not (len(face_index_pairs) + len(edges) + len(me.vertices)): # Make sure there is something to write - # clean up - ob_for_convert.to_mesh_clear() - continue # dont bother with this mesh. - - if EXPORT_NORMALS and face_index_pairs: - me.calc_normals_split() - # No need to call me.free_normals_split later, as this mesh is deleted anyway! - - loops = me.loops - - if (EXPORT_SMOOTH_GROUPS or EXPORT_SMOOTH_GROUPS_BITFLAGS) and face_index_pairs: - smooth_groups, smooth_groups_tot = me.calc_smooth_groups(use_bitflags=EXPORT_SMOOTH_GROUPS_BITFLAGS) - if smooth_groups_tot <= 1: - smooth_groups, smooth_groups_tot = (), 0 - else: - smooth_groups, smooth_groups_tot = (), 0 - - materials = me.materials[:] - material_names = [m.name if m else None for m in materials] - - # avoid bad index errors - if not materials: - materials = [None] - material_names = [name_compat(None)] - - # Sort by Material, then images - # so we dont over context switch in the obj file. - if EXPORT_KEEP_VERT_ORDER: - pass - else: - if len(materials) > 1: - if smooth_groups: - sort_func = lambda a: (a[0].material_index, - smooth_groups[a[1]] if a[0].use_smooth else False) - else: - sort_func = lambda a: (a[0].material_index, - a[0].use_smooth) - else: - # no materials - if smooth_groups: - sort_func = lambda a: smooth_groups[a[1] if a[0].use_smooth else False] - else: - sort_func = lambda a: a[0].use_smooth - - face_index_pairs.sort(key=sort_func) - - del sort_func - - # 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. - - if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB: - name1 = ob.name - name2 = ob.data.name - if name1 == name2: - obnamestring = name_compat(name1) - else: - obnamestring = '%s_%s' % (name_compat(name1), name_compat(name2)) - - if EXPORT_BLEN_OBS: - fw('o %s\n' % obnamestring) # Write Object name - else: # if EXPORT_GROUP_BY_OB: - fw('g %s\n' % obnamestring) - - subprogress2.step() - - # Vert - for v in me_verts: - fw('v %.6f %.6f %.6f\n' % v.co[:]) - - subprogress2.step() - - # UV - if faceuv: - # in case removing some of these dont get defined. - uv = f_index = uv_index = uv_key = uv_val = uv_ls = None - - uv_face_mapping = [None] * len(face_index_pairs) - - uv_dict = {} - uv_get = uv_dict.get - for f, f_index in face_index_pairs: - uv_ls = uv_face_mapping[f_index] = [] - for uv_index, l_index in enumerate(f.loop_indices): - uv = uv_layer[l_index].uv - # include the vertex index in the key so we don't share UV's between vertices, - # allowed by the OBJ spec but can cause issues for other importers, see: T47010. - - # this works too, shared UV's for all verts - #~ uv_key = veckey2d(uv) - uv_key = loops[l_index].vertex_index, veckey2d(uv) - - uv_val = uv_get(uv_key) - if uv_val is None: - uv_val = uv_dict[uv_key] = uv_unique_count - fw('vt %.6f %.6f\n' % uv[:]) - uv_unique_count += 1 - uv_ls.append(uv_val) - - del uv_dict, uv, f_index, uv_index, uv_ls, uv_get, uv_key, uv_val - # Only need uv_unique_count and uv_face_mapping - - subprogress2.step() - - # NORMAL, Smooth/Non smoothed. - if EXPORT_NORMALS: - no_key = no_val = None - normals_to_idx = {} - no_get = normals_to_idx.get - loops_to_normals = [0] * len(loops) - for f, f_index in face_index_pairs: - for l_idx in f.loop_indices: - no_key = veckey3d(loops[l_idx].normal) - no_val = no_get(no_key) - if no_val is None: - no_val = normals_to_idx[no_key] = no_unique_count - fw('vn %.4f %.4f %.4f\n' % no_key) - no_unique_count += 1 - loops_to_normals[l_idx] = no_val - del normals_to_idx, no_get, no_key, no_val - else: - loops_to_normals = [] - - subprogress2.step() - - # XXX - if EXPORT_POLYGROUPS: - # Retrieve the list of vertex groups - vertGroupNames = ob.vertex_groups.keys() - if vertGroupNames: - currentVGroup = '' - # Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to - vgroupsMap = [[] for _i in range(len(me_verts))] - for v_idx, v_ls in enumerate(vgroupsMap): - v_ls[:] = [(vertGroupNames[g.group], g.weight) for g in me_verts[v_idx].groups] - - for f, f_index in face_index_pairs: - f_smooth = f.use_smooth - if f_smooth and smooth_groups: - f_smooth = smooth_groups[f_index] - f_mat = min(f.material_index, len(materials) - 1) - - # MAKE KEY - key = material_names[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 - vgroup_of_face = findVertexGroupName(f, vgroupsMap) - if vgroup_of_face != currentVGroup: - currentVGroup = vgroup_of_face - fw('g %s\n' % vgroup_of_face) - - # CHECK FOR CONTEXT SWITCH - if key == contextMat: - pass # Context already switched, dont do anything - else: - if key[0] is None and key[1] is None: - # Write a null material, since we know the context has changed. - if EXPORT_GROUP_BY_MAT: - # can be mat_image or (null) - fw("g %s_%s\n" % (name_compat(ob.name), name_compat(ob.data.name))) - if EXPORT_MTL: - fw("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 name_compat. - - # If none image dont bother adding it to the name - # Try to avoid as much as possible adding texname (or other things) - # to the mtl name (see [#32102])... - mtl_name = "%s" % name_compat(key[0]) - if mtl_rev_dict.get(mtl_name, None) not in {key, None}: - if key[1] is None: - tmp_ext = "_NONE" - else: - tmp_ext = "_%s" % name_compat(key[1]) - i = 0 - while mtl_rev_dict.get(mtl_name + tmp_ext, None) not in {key, None}: - i += 1 - tmp_ext = "_%3d" % i - mtl_name += tmp_ext - mat_data = mtl_dict[key] = mtl_name, materials[f_mat] - mtl_rev_dict[mtl_name] = key - - if EXPORT_GROUP_BY_MAT: - # can be mat_image or (null) - fw("g %s_%s_%s\n" % (name_compat(ob.name), name_compat(ob.data.name), mat_data[0])) - if EXPORT_MTL: - fw("usemtl %s\n" % mat_data[0]) # can be mat_image or (null) - - contextMat = key - if f_smooth != contextSmooth: - if f_smooth: # on now off - if smooth_groups: - f_smooth = smooth_groups[f_index] - fw('s %d\n' % f_smooth) - else: - fw('s 1\n') - else: # was off now on - fw('s off\n') - contextSmooth = f_smooth - - f_v = [(vi, me_verts[v_idx], l_idx) - for vi, (v_idx, l_idx) in enumerate(zip(f.vertices, f.loop_indices))] - - fw('f') - if faceuv: - if EXPORT_NORMALS: - for vi, v, li in f_v: - fw(" %d/%d/%d" % (totverts + v.index, - totuvco + uv_face_mapping[f_index][vi], - totno + loops_to_normals[li], - )) # vert, uv, normal - else: # No Normals - for vi, v, li in f_v: - fw(" %d/%d" % (totverts + v.index, - totuvco + uv_face_mapping[f_index][vi], - )) # vert, uv - - face_vert_index += len(f_v) - - else: # No UV's - if EXPORT_NORMALS: - for vi, v, li in f_v: - fw(" %d//%d" % (totverts + v.index, totno + loops_to_normals[li])) - else: # No Normals - for vi, v, li in f_v: - fw(" %d" % (totverts + v.index)) - - fw('\n') - - subprogress2.step() - - # Write edges. - if EXPORT_EDGES: - for ed in edges: - if ed.is_loose: - fw('l %d %d\n' % (totverts + ed.vertices[0], totverts + ed.vertices[1])) - - # Make the indices global rather then per mesh - totverts += len(me_verts) - totuvco += uv_unique_count - totno += no_unique_count - - # clean up - ob_for_convert.to_mesh_clear() - - subprogress1.leave_substeps("Finished writing geometry of '%s'." % ob_main.name) - subprogress1.leave_substeps() - - subprogress1.step("Finished exporting geometry, now exporting materials") - - # Now we have all our materials, save them - if EXPORT_MTL: - write_mtl(scene, mtlfilepath, EXPORT_PATH_MODE, copy_set, mtl_dict) - - # copy all collected files. - io_utils.path_reference_copy(copy_set) - - -def _write(context, filepath, - EXPORT_TRI, # ok - EXPORT_EDGES, - EXPORT_SMOOTH_GROUPS, - EXPORT_SMOOTH_GROUPS_BITFLAGS, - EXPORT_NORMALS, # ok - EXPORT_UV, # ok - EXPORT_MTL, - EXPORT_APPLY_MODIFIERS, # ok - EXPORT_APPLY_MODIFIERS_RENDER, # ok - EXPORT_BLEN_OBS, - EXPORT_GROUP_BY_OB, - EXPORT_GROUP_BY_MAT, - EXPORT_KEEP_VERT_ORDER, - EXPORT_POLYGROUPS, - EXPORT_CURVE_AS_NURBS, - EXPORT_SEL_ONLY, # ok - EXPORT_ANIMATION, - EXPORT_GLOBAL_MATRIX, - EXPORT_PATH_MODE, # Not used - ): - - with ProgressReport(context.window_manager) as progress: - base_name, ext = os.path.splitext(filepath) - context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension - - depsgraph = context.evaluated_depsgraph_get() - scene = context.scene - - # Exit edit mode before exporting, so current object states are exported properly. - if bpy.ops.object.mode_set.poll(): - bpy.ops.object.mode_set(mode='OBJECT') - - orig_frame = scene.frame_current - - # Export an animation? - if EXPORT_ANIMATION: - scene_frames = range(scene.frame_start, scene.frame_end + 1) # Up to and including the end frame. - else: - scene_frames = [orig_frame] # Dont export an animation. - - # Loop through all frames in the scene and export. - progress.enter_substeps(len(scene_frames)) - for frame in scene_frames: - if EXPORT_ANIMATION: # Add frame to the filepath. - context_name[2] = '_%.6d' % frame - - scene.frame_set(frame, subframe=0.0) - if EXPORT_SEL_ONLY: - objects = context.selected_objects - else: - objects = scene.objects - - full_path = ''.join(context_name) - - # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad. - # EXPORT THE FILE. - progress.enter_substeps(1) - write_file(full_path, objects, depsgraph, scene, - EXPORT_TRI, - EXPORT_EDGES, - EXPORT_SMOOTH_GROUPS, - EXPORT_SMOOTH_GROUPS_BITFLAGS, - EXPORT_NORMALS, - EXPORT_UV, - EXPORT_MTL, - EXPORT_APPLY_MODIFIERS, - EXPORT_APPLY_MODIFIERS_RENDER, - EXPORT_BLEN_OBS, - EXPORT_GROUP_BY_OB, - EXPORT_GROUP_BY_MAT, - EXPORT_KEEP_VERT_ORDER, - EXPORT_POLYGROUPS, - EXPORT_CURVE_AS_NURBS, - EXPORT_GLOBAL_MATRIX, - EXPORT_PATH_MODE, - progress, - ) - progress.leave_substeps() - - scene.frame_set(orig_frame, subframe=0.0) - progress.leave_substeps() - - -""" -Currently the exporter lacks these features: -* multiple scene export (only active scene is written) -* particles -""" - - -def save(context, - filepath, - *, - use_triangles=False, - use_edges=True, - use_normals=False, - use_smooth_groups=False, - use_smooth_groups_bitflags=False, - use_uvs=True, - use_materials=True, - use_mesh_modifiers=True, - use_mesh_modifiers_render=False, - use_blen_objects=True, - group_by_object=False, - group_by_material=False, - keep_vertex_order=False, - use_vertex_groups=False, - use_nurbs=True, - use_selection=True, - use_animation=False, - global_matrix=None, - path_mode='AUTO' - ): - - _write(context, filepath, - EXPORT_TRI=use_triangles, - EXPORT_EDGES=use_edges, - EXPORT_SMOOTH_GROUPS=use_smooth_groups, - EXPORT_SMOOTH_GROUPS_BITFLAGS=use_smooth_groups_bitflags, - EXPORT_NORMALS=use_normals, - EXPORT_UV=use_uvs, - EXPORT_MTL=use_materials, - EXPORT_APPLY_MODIFIERS=use_mesh_modifiers, - EXPORT_APPLY_MODIFIERS_RENDER=use_mesh_modifiers_render, - EXPORT_BLEN_OBS=use_blen_objects, - EXPORT_GROUP_BY_OB=group_by_object, - EXPORT_GROUP_BY_MAT=group_by_material, - EXPORT_KEEP_VERT_ORDER=keep_vertex_order, - EXPORT_POLYGROUPS=use_vertex_groups, - EXPORT_CURVE_AS_NURBS=use_nurbs, - EXPORT_SEL_ONLY=use_selection, - EXPORT_ANIMATION=use_animation, - EXPORT_GLOBAL_MATRIX=global_matrix, - EXPORT_PATH_MODE=path_mode, - ) - - return {'FINISHED'} |