diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py index 8adb5ebfbe5a5483df16f759597809959a44738c..b3e5257a6d7a02aa73fbb77af4d5392fc42c0757 100644 --- a/io_scene_fbx/__init__.py +++ b/io_scene_fbx/__init__.py @@ -56,6 +56,7 @@ from bpy_extras.io_utils import (ImportHelper, axis_conversion, ) + class ImportFBX(bpy.types.Operator, ImportHelper): """Load a FBX geometry file""" bl_idname = "import_scene.fbx" @@ -68,54 +69,52 @@ class ImportFBX(bpy.types.Operator, ImportHelper): filter_glob = StringProperty(default="*.fbx", options={'HIDDEN'}) use_image_search = BoolProperty( - name="Image Search", - description="Search subdirs for any associated images " - "(Warning, may be slow)", - default=True, - ) + name="Image Search", + description="Search subdirs for any associated images (Warning, may be slow)", + default=True, + ) use_alpha_decals = BoolProperty( - name="Alpha Decals", - description="Treat materials with alpha as decals " - "(no shadow casting)", - default=False, - options={'HIDDEN'} - ) + name="Alpha Decals", + description="Treat materials with alpha as decals (no shadow casting)", + default=False, + options={'HIDDEN'} + ) decal_offset = FloatProperty( - name="Decal Offset", - description="Displace geometry of alpha meshes", - min=0.0, max=1.0, - default=0.0, - options={'HIDDEN'} - ) + name="Decal Offset", + description="Displace geometry of alpha meshes", + min=0.0, max=1.0, + default=0.0, + options={'HIDDEN'} + ) axis_forward = EnumProperty( - name="Forward", - items=(('X', "X Forward", ""), - ('Y', "Y Forward", ""), - ('Z', "Z Forward", ""), - ('-X', "-X Forward", ""), - ('-Y', "-Y Forward", ""), - ('-Z', "-Z Forward", ""), - ), - default='-Z', - ) + name="Forward", + items=(('X', "X Forward", ""), + ('Y', "Y Forward", ""), + ('Z', "Z Forward", ""), + ('-X', "-X Forward", ""), + ('-Y', "-Y Forward", ""), + ('-Z', "-Z Forward", ""), + ), + default='-Z', + ) axis_up = EnumProperty( - name="Up", - items=(('X', "X Up", ""), - ('Y', "Y Up", ""), - ('Z', "Z Up", ""), - ('-X', "-X Up", ""), - ('-Y', "-Y Up", ""), - ('-Z', "-Z Up", ""), - ), - default='Y', - ) + name="Up", + items=(('X', "X Up", ""), + ('Y', "Y Up", ""), + ('Z', "Z Up", ""), + ('-X', "-X Up", ""), + ('-Y', "-Y Up", ""), + ('-Z', "-Z Up", ""), + ), + default='Y', + ) global_scale = FloatProperty( - name="Scale", - min=0.001, max=1000.0, - default=1.0, - ) + name="Scale", + min=0.001, max=1000.0, + default=1.0, + ) def execute(self, context): from mathutils import Matrix @@ -151,150 +150,146 @@ class ExportFBX(bpy.types.Operator, ExportHelper): # to the class instance from the operator settings before calling. version = EnumProperty( - items=(('BIN7400', "FBX 7.4 binary", "Newer 7.4 binary version, still in development (no animation yet)"), - ('ASCII6100', "FBX 6.1 ASCII", "Legacy 6.1 ascii version"), - ), - name="Exporter Version", - description="Choose which version of the exporter to use", - default='BIN7400', - ) + items=(('BIN7400', "FBX 7.4 binary", "Newer 7.4 binary version, still in development (no animation yet)"), + ('ASCII6100', "FBX 6.1 ASCII", "Legacy 6.1 ascii version"), + ), + name="Exporter Version", + description="Choose which version of the exporter to use", + default='BIN7400', + ) use_selection = BoolProperty( - name="Selected Objects", - description="Export selected objects on visible layers", - default=False, - ) + name="Selected Objects", + description="Export selected objects on visible layers", + default=False, + ) global_scale = FloatProperty( - name="Scale", - description=("Scale all data " - "(Some importers do not support scaled armatures!)"), - min=0.001, max=1000.0, - soft_min=0.01, soft_max=1000.0, - default=1.0, - ) + name="Scale", + description=("Scale all data (Some importers do not support scaled armatures!)"), + min=0.001, max=1000.0, + soft_min=0.01, soft_max=1000.0, + default=1.0, + ) axis_forward = EnumProperty( - name="Forward", - items=(('X', "X Forward", ""), - ('Y', "Y Forward", ""), - ('Z', "Z Forward", ""), - ('-X', "-X Forward", ""), - ('-Y', "-Y Forward", ""), - ('-Z', "-Z Forward", ""), - ), - default='-Z', - ) + name="Forward", + items=(('X', "X Forward", ""), + ('Y', "Y Forward", ""), + ('Z', "Z Forward", ""), + ('-X', "-X Forward", ""), + ('-Y', "-Y Forward", ""), + ('-Z', "-Z Forward", ""), + ), + default='-Z', + ) axis_up = EnumProperty( - name="Up", - items=(('X', "X Up", ""), - ('Y', "Y Up", ""), - ('Z', "Z Up", ""), - ('-X', "-X Up", ""), - ('-Y', "-Y Up", ""), - ('-Z', "-Z Up", ""), - ), - default='Y', - ) + name="Up", + items=(('X', "X Up", ""), + ('Y', "Y Up", ""), + ('Z', "Z Up", ""), + ('-X', "-X Up", ""), + ('-Y', "-Y Up", ""), + ('-Z', "-Z Up", ""), + ), + default='Y', + ) object_types = EnumProperty( - name="Object Types", - options={'ENUM_FLAG'}, - items=(('EMPTY', "Empty", ""), - ('CAMERA', "Camera", ""), - ('LAMP', "Lamp", ""), - ('ARMATURE', "Armature", ""), - ('MESH', "Mesh", ""), - ), - default={'EMPTY', 'CAMERA', 'LAMP', 'ARMATURE', 'MESH'}, - ) + name="Object Types", + options={'ENUM_FLAG'}, + items=(('EMPTY', "Empty", ""), + ('CAMERA', "Camera", ""), + ('LAMP', "Lamp", ""), + ('ARMATURE', "Armature", ""), + ('MESH', "Mesh", ""), + ), + default={'EMPTY', 'CAMERA', 'LAMP', 'ARMATURE', 'MESH'}, + ) use_mesh_modifiers = BoolProperty( - name="Apply Modifiers", - description="Apply modifiers to mesh objects", - default=True, - ) + name="Apply Modifiers", + description="Apply modifiers to mesh objects", + default=True, + ) mesh_smooth_type = EnumProperty( - name="Smoothing", - items=(('OFF', "Off", "Don't write smoothing"), - ('FACE', "Face", "Write face smoothing"), - ('EDGE', "Edge", "Write edge smoothing"), - ), - default='FACE', - ) + name="Smoothing", + items=(('OFF', "Off", "Don't write smoothing"), + ('FACE', "Face", "Write face smoothing"), + ('EDGE', "Edge", "Write edge smoothing"), + ), + default='FACE', + ) use_mesh_edges = BoolProperty( - name="Include Loose Edges", - default=False, - ) + name="Include Loose Edges", + default=False, + ) use_tspace = BoolProperty( - name="Include Tangent Space", - description=("Add binormal and tangent vectors, together with normal they form the tangent space " - "(will only work correctly with tris/quads only meshes!)"), - default=False, - ) + name="Include Tangent Space", + description=("Add binormal and tangent vectors, together with normal they form the tangent space " + "(will only work correctly with tris/quads only meshes!)"), + default=False, + ) use_custom_properties = BoolProperty( - name="Custom Properties", - description="Export custom properties", - default=False, - ) + name="Custom Properties", + description="Export custom properties", + default=False, + ) use_armature_deform_only = BoolProperty( - name="Only Deform Bones", - description="Only write deforming bones", - default=False, - ) + name="Only Deform Bones", + description="Only write deforming bones", + default=False, + ) use_anim = BoolProperty( - name="Include Animation", - description="Export keyframe animation", - default=True, - ) + name="Include Animation", + description="Export keyframe animation", + default=True, + ) use_anim_action_all = BoolProperty( - name="All Actions", - description=("Export all actions for armatures or just the " - "currently selected action"), - default=True, - ) + name="All Actions", + description=("Export all actions for armatures or just the currently selected action"), + default=True, + ) use_default_take = BoolProperty( - name="Include Default Take", - description=("Export currently assigned object and armature " - "animations into a default take from the scene " - "start/end frames"), - default=True - ) + name="Include Default Take", + description=("Export currently assigned object and armature animations into a default take from the scene " + "start/end frames"), + default=True + ) use_anim_optimize = BoolProperty( - name="Optimize Keyframes", - description="Remove double keyframes", - default=True, - ) + name="Optimize Keyframes", + description="Remove double keyframes", + default=True, + ) anim_optimize_precision = FloatProperty( - name="Precision", - description=("Tolerance for comparing double keyframes " - "(higher for greater accuracy)"), - min=0.0, max=20.0, # from 10^2 to 10^-18 frames precision. - soft_min=1.0, soft_max=16.0, - default=6.0, # default: 10^-4 frames. - ) + name="Precision", + description=("Tolerance for comparing double keyframes (higher for greater accuracy)"), + min=0.0, max=20.0, # from 10^2 to 10^-18 frames precision. + soft_min=1.0, soft_max=16.0, + default=6.0, # default: 10^-4 frames. + ) path_mode = path_reference_mode embed_textures = BoolProperty( - name="Embed Textures", - description="Embed textures in FBX binary file (only for \"Copy\" path mode!)", - default=False, - ) + name="Embed Textures", + description="Embed textures in FBX binary file (only for \"Copy\" path mode!)", + default=False, + ) batch_mode = EnumProperty( - name="Batch Mode", - items=(('OFF', "Off", "Active scene to file"), - ('SCENE', "Scene", "Each scene as a file"), - ('GROUP', "Group", "Each group as a file"), - ), - ) + name="Batch Mode", + items=(('OFF', "Off", "Active scene to file"), + ('SCENE', "Scene", "Each scene as a file"), + ('GROUP', "Group", "Each group as a file"), + ), + ) use_batch_own_dir = BoolProperty( - name="Batch Own Dir", - description="Create a dir for each exported file", - default=True, - ) + name="Batch Own Dir", + description="Create a dir for each exported file", + default=True, + ) use_metadata = BoolProperty( - name="Use Metadata", - default=True, - options={'HIDDEN'}, - ) + name="Use Metadata", + default=True, + options={'HIDDEN'}, + ) @property def check_extension(self): @@ -305,7 +300,6 @@ class ExportFBX(bpy.types.Operator, ExportHelper): if not self.filepath: raise Exception("filepath not set") - global_matrix = (Matrix.Scale(self.global_scale, 4) * axis_conversion(to_forward=self.axis_forward, to_up=self.axis_up, diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index ee3ea497f6ad4f69ecf1076e3afd25e66a20c97b..7dc334084160105d06581ed216797631d40bf44a 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -69,7 +69,8 @@ FBX_KTIME = 46186158000 # This is the number of "ktimes" in one second (yep, pr MAT_CONVERT_LAMP = Matrix.Rotation(math.pi / 2.0, 4, 'X') # Blender is -Z, FBX is -Y. MAT_CONVERT_CAMERA = Matrix.Rotation(math.pi / 2.0, 4, 'Y') # Blender is -Z, FBX is +X. -MAT_CONVERT_BONE = Matrix() #Matrix.Rotation(math.pi / -2.0, 4, 'X') # Blender is +Y, FBX is +Z. +#MAT_CONVERT_BONE = Matrix.Rotation(math.pi / -2.0, 4, 'X') # Blender is +Y, FBX is +Z. +MAT_CONVERT_BONE = Matrix() # Lamps. @@ -106,6 +107,7 @@ UNITS = { "ktime": FBX_KTIME, } + def units_convert(val, u_from, u_to): """Convert value.""" conv = UNITS[u_to] / UNITS[u_from] @@ -199,7 +201,7 @@ def get_fbxuid_from_key(key): return uid -# XXX Not sure we'll actually need this one? +# XXX Not sure we'll actually need this one? def get_key_from_fbxuid(uid): """ Return the key which generated this uid. @@ -389,7 +391,7 @@ def elem_props_template_set(template, elem, ptype_name, name, value): tmpl_val, tmpl_ptype = template.properties.get(name, (None, None)) if tmpl_ptype is not None: if ((len(ptype) == 4 and (tmpl_val, tmpl_ptype) == (value, ptype_name)) or - (len(ptype) > 4 and (tuple(tmpl_val), tmpl_ptype) == (tuple(value), ptype_name))): + (len(ptype) > 4 and (tuple(tmpl_val), tmpl_ptype) == (tuple(value), ptype_name))): return # Already in template and same value. _elem_props_set(elem, ptype, name, value) @@ -650,7 +652,7 @@ def fbx_template_def_video(scene, settings, override_defaults=None, nbr_users=0) props.update(override_defaults) return FBXTemplate(b"Video", b"FbxVideo", props, nbr_users) - + def fbx_template_def_pose(scene, settings, override_defaults=None, nbr_users=0): props = {} if override_defaults is not None: @@ -889,7 +891,7 @@ def fbx_data_mesh_elements(root, me, scene_data): # # We do loose edges as two-vertices faces, if enabled... # - # Note we have to process Edges in the same time, as they are based on poly's loops... + # Note we have to process Edges in the same time, as they are based on poly's loops... loop_nbr = len(me.loops) t_pvi = array.array(data_types.ARRAY_INT32, (0,) * loop_nbr) t_ls = [None] * len(me.polygons) @@ -975,7 +977,7 @@ def fbx_data_mesh_elements(root, me, scene_data): elem_data_single_string(lay_smooth, b"Name", b"") elem_data_single_string(lay_smooth, b"MappingInformationType", _map) elem_data_single_string(lay_smooth, b"ReferenceInformationType", b"Direct") - elem_data_single_int32_array(lay_smooth, b"Smoothing", t_ps); # Sight, int32 for bool... + elem_data_single_int32_array(lay_smooth, b"Smoothing", t_ps) # Sight, int32 for bool... del t_ps # TODO: Edge crease (LayerElementCrease). @@ -1068,7 +1070,8 @@ def fbx_data_mesh_elements(root, me, scene_data): if vcolnumber: def _coltuples_gen(raw_cols): def _infinite_gen(val): - while 1: yield val + while 1: + yield val return zip(*(iter(raw_cols),) * 3 + (_infinite_gen(1.0),)) # We need a fake alpha... t_lc = array.array(data_types.ARRAY_FLOAT64, [0.0] * len(me.loops) * 3) @@ -1084,7 +1087,7 @@ def fbx_data_mesh_elements(root, me, scene_data): elem_data_single_float64_array(lay_vcol, b"Colors", chain(*col2idx)) # Flatten again... col2idx = {col: idx for idx, col in enumerate(col2idx)} - elem_data_single_int32_array(lay_vcol, b"ColorIndex", (col2idx[c] for c in _coltuples_gen(t_lc))); + elem_data_single_int32_array(lay_vcol, b"ColorIndex", (col2idx[c] for c in _coltuples_gen(t_lc))) del col2idx del t_lc del _coltuples_gen @@ -1110,7 +1113,7 @@ def fbx_data_mesh_elements(root, me, scene_data): elem_data_single_float64_array(lay_uv, b"UV", chain(*uv2idx)) # Flatten again... uv2idx = {uv: idx for idx, uv in enumerate(uv2idx)} - elem_data_single_int32_array(lay_uv, b"UVIndex", (uv2idx[uv] for uv in _uvtuples_gen(t_luv))); + elem_data_single_int32_array(lay_uv, b"UVIndex", (uv2idx[uv] for uv in _uvtuples_gen(t_luv))) del uv2idx del t_luv del _uvtuples_gen @@ -1224,7 +1227,7 @@ def fbx_data_material_elements(root, mat, scene_data): elem_props_template_set(tmpl, props, "p_color_rgb", b"TransparentColor", mat.diffuse_color) elem_props_template_set(tmpl, props, "p_number", b"TransparencyFactor", mat.alpha if mat.use_transparency else 1.0) # Those are for later! - """ + """ b"NormalMap": ((0.0, 0.0, 0.0), "p_vector_3d"), b"Bump": ((0.0, 0.0, 0.0), "p_vector_3d"), b"BumpFactor": (1.0, "p_number"), @@ -1317,7 +1320,7 @@ def fbx_data_texture_file_elements(root, tex, scene_data): if scene_data.settings.use_custom_properties: fbx_data_element_custom_properties(tmpl, props, tex.texture) - + def fbx_data_video_elements(root, vid, scene_data): """ Write the actual image data block. @@ -1362,7 +1365,7 @@ def fbx_data_armature_elements(root, armature, scene_data): fbx_bo = elem_data_single_int64(root, b"NodeAttribute", get_fbxuid_from_key(bo_data_key)) fbx_bo.add_string(fbx_name_class(bo.name.encode(), b"NodeAttribute")) fbx_bo.add_string(b"LimbNode") - elem_data_single_string(fbx_bo, b"TypeFlags", b"Skeleton") + elem_data_single_string(fbx_bo, b"TypeFlags", b"Skeleton") props = elem_properties(fbx_bo) elem_props_template_set(tmpl, props, "p_number", b"Size", (bo.tail_local - bo.head_local).length) @@ -1371,7 +1374,6 @@ def fbx_data_armature_elements(root, armature, scene_data): if scene_data.settings.use_custom_properties: fbx_data_element_custom_properties(tmpl, props, bo) - # Deformers and BindPoses. # Note: we might also use Deformers for our "parent to vertex" stuff??? deformer = scene_data.data_deformers.get(armature, None) @@ -1413,8 +1415,8 @@ def fbx_data_armature_elements(root, armature, scene_data): for bo, clstr_key in clusters.items(): # Find which vertices are affected by this bone/vgroup pair, and matching weights. - indices = []; - weights = []; + indices = [] + weights = [] vg_idx = obj.vertex_groups[bo.name].index for idx, v in enumerate(me.vertices): vert_vg = [vg for vg in v.groups if vg.group == vg_idx] @@ -1438,8 +1440,9 @@ def fbx_data_armature_elements(root, armature, scene_data): # Transform and TransformLink matrices... # They seem to be mostly the same as BindPose ones??? # WARNING! Even though official FBX API presents Transform in global space, - # **it is stored in bone space in FBX data!** See - # http://area.autodesk.com/forum/autodesk-fbx/fbx-sdk/why-the-values-return-by-fbxcluster-gettransformmatrix-x-not-same-with-the-value-in-ascii-fbx-file/ + # **it is stored in bone space in FBX data!** See: + # http://area.autodesk.com/forum/autodesk-fbx/fbx-sdk/why-the-values-return- + # by-fbxcluster-gettransformmatrix-x-not-same-with-the-value-in-ascii-fbx-file/ elem_data_single_float64_array(fbx_clstr, b"Transform", matrix_to_array(mat_world_bones[bo].inverted() * mat_world_obj)) elem_data_single_float64_array(fbx_clstr, b"TransformLink", matrix_to_array(mat_world_bones[bo])) @@ -1726,7 +1729,8 @@ def fbx_data_from_scene(scene, settings): templates[b"BindPose"] = fbx_template_def_pose(scene, settings, nbr_users=len(arm_parents)) if data_deformers: - nbr = len(data_deformers) + sum(len(clusters) for def_me in data_deformers.values() for a, b, clusters in def_me.values()) + nbr = len(data_deformers) + nbr += sum(len(clusters) for def_me in data_deformers.values() for a, b, clusters in def_me.values()) templates[b"Deformers"] = fbx_template_def_deformer(scene, settings, nbr_users=nbr) # No world support in FBX... @@ -2053,6 +2057,7 @@ FBXSettings = namedtuple("FBXSettings", ( "use_metadata", "media_settings", "use_custom_properties", )) + # This func can be called with just the filepath def save_single(operator, scene, filepath="", global_matrix=Matrix(), diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py index 0cec24a7b93c71d6f05cbfefcbbd41475d88e6bf..c23247e66fe21d5dbbb6a0ab856e676f24a1f1ed 100644 --- a/io_scene_fbx/import_fbx.py +++ b/io_scene_fbx/import_fbx.py @@ -324,11 +324,11 @@ def blen_read_geom_layerinfo(fbx_layer): def blen_read_geom_array_mapped_vert( - mesh, blen_data, blend_attr, - fbx_layer_data, fbx_layer_index, - fbx_layer_mapping, fbx_layer_ref, - stride, item_size, descr, - ): + mesh, blen_data, blend_attr, + fbx_layer_data, fbx_layer_index, + fbx_layer_mapping, fbx_layer_ref, + stride, item_size, descr, + ): # TODO, generic mapping apply function if fbx_layer_mapping == b'ByVertice': if fbx_layer_ref == b'Direct': @@ -347,13 +347,12 @@ def blen_read_geom_array_mapped_vert( def blen_read_geom_array_mapped_edge( - mesh, blen_data, blend_attr, - fbx_layer_data, fbx_layer_index, - fbx_layer_mapping, fbx_layer_ref, - stride, item_size, descr, - xform=None, - ): - + mesh, blen_data, blend_attr, + fbx_layer_data, fbx_layer_index, + fbx_layer_mapping, fbx_layer_ref, + stride, item_size, descr, + xform=None, + ): if fbx_layer_mapping == b'ByEdge': if fbx_layer_ref == b'Direct': if stride == 1: @@ -384,13 +383,12 @@ def blen_read_geom_array_mapped_edge( def blen_read_geom_array_mapped_polygon( - mesh, blen_data, blend_attr, - fbx_layer_data, fbx_layer_index, - fbx_layer_mapping, fbx_layer_ref, - stride, item_size, descr, - xform=None, - ): - + mesh, blen_data, blend_attr, + fbx_layer_data, fbx_layer_index, + fbx_layer_mapping, fbx_layer_ref, + stride, item_size, descr, + xform=None, + ): if fbx_layer_mapping == b'ByPolygon': if fbx_layer_ref == b'IndexToDirect': if stride == 1: @@ -421,12 +419,11 @@ def blen_read_geom_array_mapped_polygon( def blen_read_geom_array_mapped_polyloop( - mesh, blen_data, blend_attr, - fbx_layer_data, fbx_layer_index, - fbx_layer_mapping, fbx_layer_ref, - stride, item_size, descr, - ): - + mesh, blen_data, blend_attr, + fbx_layer_data, fbx_layer_index, + fbx_layer_mapping, fbx_layer_ref, + stride, item_size, descr, + ): if fbx_layer_mapping == b'ByPolygonVertex': if fbx_layer_ref == b'IndexToDirect': assert(fbx_layer_index is not None) @@ -540,6 +537,7 @@ def blen_read_geom_layer_color(fbx_obj, mesh): 4, 3, layer_id, ) + def blen_read_geom_layer_smooth(fbx_obj, mesh): fbx_layer = elem_find_first(fbx_obj, b'LayerElementSmoothing') @@ -978,7 +976,8 @@ def load(operator, context, filepath="", # ---- # Load in the data - # http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html?url=WS73099cc142f487551fea285e1221e4f9ff8-7fda.htm,topicNumber=d0e6388 + # http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html?url= + # WS73099cc142f487551fea285e1221e4f9ff8-7fda.htm,topicNumber=d0e6388 fbx_connection_map = {} fbx_connection_map_reverse = {} @@ -1241,10 +1240,9 @@ def load(operator, context, filepath="", # tx/rot/scale tex_map = texture_mapping_get(fbx_lnk) if (tex_map[0] == (0.0, 0.0, 0.0) and - tex_map[1] == (0.0, 0.0, 0.0) and - tex_map[2] == (1.0, 1.0, 1.0) and - tex_map[3] == (False, False)): - + tex_map[1] == (0.0, 0.0, 0.0) and + tex_map[2] == (1.0, 1.0, 1.0) and + tex_map[3] == (False, False)): use_mapping = False else: use_mapping = True diff --git a/io_scene_fbx/json2fbx.py b/io_scene_fbx/json2fbx.py index 808564ade6ba3d6338f16df234fd35bd7e995259..f979c4290d480861f9809bac07038fdcb059fd94 100755 --- a/io_scene_fbx/json2fbx.py +++ b/io_scene_fbx/json2fbx.py @@ -140,7 +140,8 @@ def parse_json(json_root): def json2fbx(fn): - import os, json + import os + import json fn_fbx = "%s.fbx" % os.path.splitext(fn)[0] print("Writing: %r " % fn_fbx, end="")