Jelajahi Sumber

Updated Blender 2.58 exporter with recent changes from 2.57 exporter.

(normal maps, textures packed in blend file, copy textures, urlBaseType, texture params)

Also fixed broken reload handling and bumped up version number.
alteredq 14 tahun lalu
induk
melakukan
ed92022b4b

+ 23 - 7
utils/exporters/blender/2.58/scripts/addons/io_mesh_threejs/__init__.py

@@ -20,13 +20,11 @@
 # Init
 # ################################################################
 
-# To support reload properly, try to access a package var,
-# if it's there, reload everything
 
 bl_info = {
     "name": "three.js format",
-    "author": "mrdoob, kikko, alteredq, remoe",
-    "version": (1, 0),
+    "author": "mrdoob, kikko, alteredq, remoe, pxf",
+    "version": (1, 0, 2),
     "blender": (2, 5, 7),
     "api": 35622,
     "location": "File > Import-Export",
@@ -36,6 +34,11 @@ bl_info = {
     "tracker_url": "https://github.com/mrdoob/three.js/issues",
     "category": "Import-Export"}
 
+# To support reload properly, try to access a package var,
+# if it's there, reload everything
+
+import bpy
+
 if "bpy" in locals():
     import imp
     if "export_threejs" in locals():
@@ -43,7 +46,6 @@ if "bpy" in locals():
     if "import_threejs" in locals():
         imp.reload(import_threejs)
 
-import bpy
 from bpy.props import *
 from bpy_extras.io_utils import ExportHelper, ImportHelper
 
@@ -175,7 +177,9 @@ def save_settings_export(properties):
     settings = {
     "option_export_scene" : properties.option_export_scene,
     "option_embed_meshes" : properties.option_embed_meshes,
-    
+    "option_url_base_html" : properties.option_url_base_html,
+    "option_copy_textures" : properties.option_copy_textures,
+
     "option_lights" : properties.option_lights,
     "option_cameras" : properties.option_cameras,
 
@@ -225,6 +229,8 @@ def restore_settings_export(properties):
 
     properties.option_export_scene = settings.get("option_export_scene", False)
     properties.option_embed_meshes = settings.get("option_embed_meshes", True)
+    properties.option_url_base_html = settings.get("option_url_base_html", False)
+    properties.option_copy_textures = settings.get("option_copy_textures", False)
 
     properties.option_lights = settings.get("option_lights", False)
     properties.option_cameras = settings.get("option_cameras", False)
@@ -263,7 +269,9 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
 
     option_export_scene = BoolProperty(name = "Scene", description = "Export scene", default = False)
     option_embed_meshes = BoolProperty(name = "Embed", description = "Embed meshes", default = True)
-    
+    option_copy_textures = BoolProperty(name = "Copy textures", description = "Copy textures", default = False)
+    option_url_base_html = BoolProperty(name = "HTML as url base", description = "Use HTML as url base ", default = False)
+
     option_lights = BoolProperty(name = "Lights", description = "Export default scene lights", default = False)
     option_cameras = BoolProperty(name = "Cameras", description = "Export default scene cameras", default = False)
 
@@ -284,6 +292,7 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
         save_settings_export(self.properties)
 
         filepath = self.filepath
+
         import io_mesh_threejs.export_threejs
         return io_mesh_threejs.export_threejs.save(self, context, **self.properties)
 
@@ -341,11 +350,18 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
 
         row = layout.row()
         row.prop(self.properties, "option_export_scene")
+
+        row = layout.row()
         row.prop(self.properties, "option_lights")
         row.prop(self.properties, "option_cameras")
 
         row = layout.row()
         row.prop(self.properties, "option_embed_meshes")
+        row.prop(self.properties, "option_copy_textures")
+
+        row = layout.row()
+        row.prop(self.properties, "option_url_base_html")
+
         layout.separator()
 
 

+ 235 - 86
utils/exporters/blender/2.58/scripts/addons/io_mesh_threejs/export_threejs.py

@@ -20,13 +20,13 @@
 Blender exporter for Three.js (ASCII JSON format).
 
 TODO
-    - copy used images to folder where exported file goes
     - binary format
 """
 
 import bpy
 import mathutils
 
+import shutil
 import os
 import os.path
 import math
@@ -79,7 +79,7 @@ COLORS = [0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee]
 TEMPLATE_SCENE_ASCII = """\
 /* Converted from: %(fname)s
  *
- * File generated with Blender 2.57 Exporter
+ * File generated with Blender 2.58 Exporter
  * https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/
  *
  * objects:    %(nobjects)s
@@ -91,7 +91,7 @@ TEMPLATE_SCENE_ASCII = """\
 var scene = {
 
 "type" : "scene",
-"urlBaseType" : "relativeToScene",
+"urlBaseType" : %(basetype)s,
 
 %(sections)s
 
@@ -222,7 +222,7 @@ TEMPLATE_HEX = "0x%06x"
 
 TEMPLATE_FILE_ASCII = """\
 /*
- * File generated with Blender 2.57 Exporter
+ * File generated with Blender 2.58 Exporter
  * https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/
  *
  * vertices: %(nvertex)d
@@ -693,6 +693,8 @@ def value2string(v):
         return '"%s"' % v
     elif type(v) == bool:
         return str(v).lower()
+    elif type(v) == list:
+        return "[%s]" % (", ".join(value2string(x) for x in v))
     return str(v)
 
 def generate_materials(mtl, materials, draw_type):
@@ -721,7 +723,7 @@ def generate_materials(mtl, materials, draw_type):
 
     return ",\n\n".join([m for i,m in sorted(mtl_array)]), len(mtl_array)
 
-def extract_materials(mesh, scene, option_colors):
+def extract_materials(mesh, scene, option_colors, option_copy_textures, filepath):
     world = scene.world
 
     materials = {}
@@ -749,22 +751,16 @@ def extract_materials(mesh, scene, option_colors):
             material['transparency'] = m.alpha
 
             # not sure about mapping values to Blinn-Phong shader
-            # Blender uses INT from [1,511] with default 0
+            # Blender uses INT from [1, 511] with default 0
             # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
 
             material["specularCoef"] = m.specular_hardness
 
-            texture = m.active_texture
+            textures = guess_material_textures(m)
 
-            if texture and texture.type == 'IMAGE' and texture.image:
-                fn = bpy.path.abspath(texture.image.filepath)
-                fn = os.path.normpath(fn)
-                fn_strip = os.path.basename(fn)
-
-                material['mapDiffuse'] = fn_strip
-                
-                if texture.repeat_x != 1 or texture.repeat_y != 1:
-                    material['mapDiffuseRepeat'] = [texture.repeat_x, texture.repeat_y]
+            handle_texture('diffuse', textures, material, filepath, option_copy_textures)
+            handle_texture('light', textures, material, filepath, option_copy_textures)
+            handle_texture('normal', textures, material, filepath, option_copy_textures)
 
             material["vertexColors"] = m.THREE_useVertexColors and option_colors
 
@@ -779,7 +775,7 @@ def extract_materials(mesh, scene, option_colors):
 
     return materials
 
-def generate_materials_string(mesh, scene, option_colors, draw_type):
+def generate_materials_string(mesh, scene, option_colors, draw_type, option_copy_textures, filepath):
 
     random.seed(42) # to get well defined color order for debug materials
 
@@ -801,10 +797,45 @@ def generate_materials_string(mesh, scene, option_colors, draw_type):
 
     # extract real materials from the mesh
 
-    mtl.update(extract_materials(mesh, scene, option_colors))
+    mtl.update(extract_materials(mesh, scene, option_colors, option_copy_textures, filepath))
 
     return generate_materials(mtl, materials, draw_type)
 
+def handle_texture(id, textures, material, filepath, option_copy_textures):
+
+    if textures[id]:
+        texName     = 'map%s'       % id.capitalize()
+        repeatName  = 'map%sRepeat' % id.capitalize()
+        wrapName    = 'map%sWrap'   % id.capitalize()
+
+        slot = textures[id]['slot']
+        texture = textures[id]['texture']
+        image = texture.image
+        fname = extract_texture_filename(image)
+        material[texName] = fname
+
+        if option_copy_textures:
+            save_image(image, fname, filepath)
+
+        if texture.repeat_x != 1 or texture.repeat_y != 1:
+            material[repeatName] = [texture.repeat_x, texture.repeat_y]
+
+        if texture.extension == "REPEAT":
+            wrap_x = "repeat"
+            wrap_y = "repeat"
+
+            if texture.use_mirror_x:
+                wrap_x = "mirror"
+            if texture.use_mirror_y:
+                wrap_y = "mirror"
+
+            material[wrapName] = [wrap_x, wrap_y]
+
+        if slot.use_map_normal:
+            if slot.normal_factor != 1.0:
+                material['mapNormalFactor'] = slot.normal_factor
+
+
 # #####################################################
 # ASCII model generator
 # #####################################################
@@ -821,7 +852,9 @@ def generate_ascii_model(mesh, scene,
                          align_model,
                          flipyz,
                          option_scale,
-                         draw_type):
+                         draw_type,
+                         option_copy_textures,
+                         filepath):
 
     vertices = mesh.vertices[:]
 
@@ -843,7 +876,7 @@ def generate_ascii_model(mesh, scene,
     nedges = 0
 
     if option_materials:
-        materials_string, nmaterial = generate_materials_string(mesh, scene, option_colors, draw_type)
+        materials_string, nmaterial = generate_materials_string(mesh, scene, option_colors, draw_type, option_copy_textures, filepath)
 
     if option_edges:
         nedges = len(mesh.edges)
@@ -873,7 +906,7 @@ def generate_ascii_model(mesh, scene,
     "ncolor"    : ncolor,
     "nmaterial" : nmaterial,
     "nedges"    : nedges,
-    
+
     "model"     : model_string
     }
 
@@ -897,7 +930,9 @@ def generate_mesh_string(obj, scene,
                 align_model,
                 flipyz,
                 option_scale,
-                export_single_model):
+                export_single_model,
+                option_copy_textures,
+                filepath):
 
     # collapse modifiers into mesh
 
@@ -937,6 +972,10 @@ def generate_mesh_string(obj, scene,
         if not active_col_layer:
             option_colors = False
 
+    option_copy_textures_model = False
+    if export_single_model and option_copy_textures:
+        option_copy_textures_model = True
+
     text, model_string = generate_ascii_model(mesh, scene,
                                 option_vertices,
                                 option_vertices_truncate,
@@ -949,11 +988,13 @@ def generate_mesh_string(obj, scene,
                                 align_model,
                                 flipyz,
                                 option_scale,
-                                obj.draw_type)
+                                obj.draw_type,
+                                option_copy_textures_model,
+                                filepath)
     # remove temp mesh
 
     bpy.data.meshes.remove(mesh)
-    
+
     return text, model_string
 
 def export_mesh(obj, scene, filepath,
@@ -968,7 +1009,8 @@ def export_mesh(obj, scene, filepath,
                 align_model,
                 flipyz,
                 option_scale,
-                export_single_model):
+                export_single_model,
+                option_copy_textures):
 
     """Export single mesh"""
 
@@ -984,7 +1026,9 @@ def export_mesh(obj, scene, filepath,
                 align_model,
                 flipyz,
                 option_scale,
-                export_single_model)
+                export_single_model,
+                option_copy_textures,
+                filepath)
 
     write_file(filepath, text)
 
@@ -1085,7 +1129,7 @@ def generate_objects(data):
                 visible = False
 
             geometry_string = generate_string(geometry_id)
-                
+
             object_string = TEMPLATE_OBJECT % {
             "object_id"   : generate_string(object_id),
             "geometry_id" : geometry_string,
@@ -1103,7 +1147,7 @@ def generate_objects(data):
             "visible"      : generate_bool_property(visible)
             }
             chunks.append(object_string)
-            
+
         elif obj.type == "EMPTY" or (obj.type == "MESH" and not obj.THREE_exportGeometry):
 
             object_id = obj.name
@@ -1117,7 +1161,7 @@ def generate_objects(data):
                 group_string = generate_string_list(group_ids)
 
             triggerType = obj.THREE_triggerType
-                
+
             object_string = TEMPLATE_EMPTY % {
             "object_id"   : generate_string(object_id),
             "group_id"    : group_string,
@@ -1153,7 +1197,7 @@ def generate_geometries(data):
             if name not in geo_set:
 
                 geometry_id = "geo_%s" % name
-                
+
                 if data["embed_meshes"]:
 
                     embed_id = "emb_%s" % name
@@ -1195,10 +1239,25 @@ def generate_textures_scene(data):
 
             texture_id = img.name
             texture_file = extract_texture_filename(img)
-            
+
+            if data["copy_textures"]:
+                save_image(img, texture_file, data["filepath"])
+
             extras = ""
+
             if texture.repeat_x != 1 or texture.repeat_y != 1:
-                extras = ',\n        "repeat": [%f, %f]' % (texture.repeat_x, texture.repeat_y)
+                extras += ',\n        "repeat": [%f, %f]' % (texture.repeat_x, texture.repeat_y)
+
+            if texture.extension == "REPEAT":
+                wrap_x = "repeat"
+                wrap_y = "repeat"
+
+                if texture.use_mirror_x:
+                    wrap_x = "mirror"
+                if texture.use_mirror_y:
+                    wrap_y = "mirror"
+
+                extras += ',\n        "wrap": ["%s", "%s"]' % (wrap_x, wrap_y)
 
             texture_string = TEMPLATE_TEXTURE % {
             "texture_id"   : generate_string(texture_id),
@@ -1215,6 +1274,19 @@ def extract_texture_filename(image):
     fn_strip = os.path.basename(fn)
     return fn_strip
 
+def save_image(img, name, fpath):
+    dst_dir = os.path.dirname(fpath)
+    dst_path = os.path.join(dst_dir, name)
+
+    ensure_folder_exist(dst_dir)
+
+    if img.packed_file:
+        img.save_render(dst_path)
+
+    else:
+        src_path = bpy.path.abspath(img.filepath)
+        shutil.copy(src_path, dst_dir)
+
 # #####################################################
 # Scene exporter - materials
 # #####################################################
@@ -1248,38 +1320,60 @@ def extract_material_data(m, option_colors):
 
     material["specularCoef"] = m.specular_hardness
 
+    material["vertexColors"] = m.THREE_useVertexColors and option_colors
+
     material['mapDiffuse'] = ""
     material['mapLight'] = ""
     material['mapNormal'] = ""
+    material['mapNormalFactor'] = 1.0
+
+    textures = guess_material_textures(m)
+
+    if textures['diffuse']:
+        material['mapDiffuse'] = textures['diffuse']['texture'].image.name
+
+    if textures['light']:
+        material['mapLight'] = textures['light']['texture'].image.name
+
+    if textures['normal']:
+        material['mapNormal'] = textures['normal']['texture'].image.name
+        if textures['normal']['slot'].use_map_normal:
+            material['mapNormalFactor'] = textures['normal']['slot'].normal_factor
+
+    material['shading'] = m.THREE_materialType
+
+    return material
+
+def guess_material_textures(material):
+    textures = {
+        'diffuse' : None,
+        'light'   : None,
+        'normal'  : None
+    }
 
-    material["vertexColors"] = m.THREE_useVertexColors and option_colors
-    
     # just take first textures of each, for the moment three.js materials can't handle more
+    # assume diffuse comes before lightmap, normalmap has checked flag
 
-    for i in range(len(m.texture_slots)):
-        ts = m.texture_slots[i]
-        if ts:
-            t = ts.texture
-            if ts.use and t.type == 'IMAGE':
-                name = t.image.name
+    for i in range(len(material.texture_slots)):
+        slot = material.texture_slots[i]
+        if slot:
+            texture = slot.texture
+            if slot.use and texture.type == 'IMAGE':
 
-                if t.use_normal_map:
-                    material['mapNormal'] = name
+                if texture.use_normal_map:
+                    textures['normal'] = { "texture": texture, "slot": slot }
 
                 else:
-
-                    if not material['mapDiffuse']:
-                        material['mapDiffuse'] = name
+                    if not textures['diffuse']:
+                        textures['diffuse'] = { "texture": texture, "slot": slot }
 
                     else:
-                        material['mapLight'] = name
+                        textures['light'] = { "texture": texture, "slot": slot }
 
-                if material['mapDiffuse'] and material['mapNormal'] and material['mapLight']:
+                if textures['diffuse'] and textures['normal'] and textures['light']:
                     break
 
-    material['shading'] = m.THREE_materialType
-
-    return material
+    return textures
 
 def generate_material_string(material):
     type_map = {
@@ -1302,6 +1396,7 @@ def generate_material_string(material):
     colorMap = material['mapDiffuse']
     lightMap = material['mapLight']
     normalMap = material['mapNormal']
+    normalMapFactor = material['mapNormalFactor']
 
     if colorMap:
         parameters += ', "map": %s' % generate_string(colorMap)
@@ -1309,10 +1404,12 @@ def generate_material_string(material):
         parameters += ', "lightMap": %s' % generate_string(lightMap)
     if normalMap:
         parameters += ', "normalMap": %s' % generate_string(normalMap)
+    if normalMapFactor != 1.0:
+        parameters += ', "normalMapFactor": %f' % normalMapFactor
 
     if material['vertexColors']:
         parameters += ', "vertexColors": "vertex"'
-        
+
     material_string = TEMPLATE_MATERIAL_SCENE % {
     "material_id" : generate_string(material_id),
     "type"        : generate_string(material_type),
@@ -1340,14 +1437,13 @@ def generate_materials_scene(data):
 def generate_cameras(data):
     if data["use_cameras"]:
 
-        cameras = data.get("cameras", [])
-        
-        if not cameras:
-            cameras.append(DEFAULTS["camera"])
+        cams = bpy.data.objects
+        cams = [ob for ob in cams if (ob.type == 'CAMERA' and ob.select)]
 
         chunks = []
 
-        for camera in cameras:
+        if not cams:
+            camera = DEFAULTS["camera"]
 
             if camera["type"] == "perspective":
 
@@ -1377,6 +1473,29 @@ def generate_cameras(data):
 
             chunks.append(camera_string)
 
+        else:
+
+            for cameraobj in cams:
+                camera = bpy.data.cameras[cameraobj.name]
+
+                # TODO:
+                #   Support more than perspective camera
+                #   Calculate a target/lookat
+                #   Get correct aspect ratio
+                if camera.id_data.type == "PERSP":
+
+                    camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
+                    "camera_id" : generate_string(camera.name),
+                    "fov"       : (camera.angle / 3.14) * 180.0,
+                    "aspect"    : 1.333,
+                    "near"      : camera.clip_start,
+                    "far"       : camera.clip_end,
+                    "position"  : generate_vec3([cameraobj.location[0], -cameraobj.location[1], cameraobj.location[2]]),
+                    "target"    : generate_vec3([0, 0, 0])
+                    }
+
+                chunks.append(camera_string)
+
         return ",\n\n".join(chunks)
 
     return ""
@@ -1417,7 +1536,7 @@ def generate_lights(data):
             chunks.append(light_string)
 
         return ",\n\n".join(chunks)
-        
+
     return ""
 
 # #####################################################
@@ -1425,20 +1544,20 @@ def generate_lights(data):
 # #####################################################
 
 def generate_embeds(data):
-    
+
     if data["embed_meshes"]:
 
         chunks = []
-        
+
         for e in data["embeds"]:
-            
+
             embed = '"emb_%s": {%s}' % (e, data["embeds"][e])
             chunks.append(embed)
-            
+
         return ",\n\n".join(chunks)
 
     return ""
-    
+
 # #####################################################
 # Scene exporter - generate ASCII scene
 # #####################################################
@@ -1455,6 +1574,13 @@ def generate_ascii_scene(data):
 
     embeds = generate_embeds(data)
 
+    basetype = "relativeTo"
+
+    if data["base_html"]:
+        basetype += "HTML"
+    else:
+        basetype += "Scene"
+
     sections = [
     ["objects",    objects],
     ["geometries", geometries],
@@ -1474,7 +1600,11 @@ def generate_ascii_scene(data):
 
     default_camera = ""
     if data["use_cameras"]:
-        default_camera = "default_camera"
+        cams = [ob for ob in bpy.data.objects if (ob.type == 'CAMERA' and ob.select)]
+        if not cams:
+            default_camera = "default_camera"
+        else:
+            default_camera = cams[0].name
 
     parameters = {
     "fname"     : data["source_file"],
@@ -1488,6 +1618,7 @@ def generate_ascii_scene(data):
     "nobjects"      : nobjects,
     "ngeometries"   : ngeometries,
     "ntextures"     : ntextures,
+    "basetype"      : generate_string(basetype),
     "nmaterials"    : nmaterials,
 
     "position"      : generate_vec3(DEFAULTS["position"]),
@@ -1499,22 +1630,24 @@ def generate_ascii_scene(data):
 
     return text
 
-def export_scene(scene, filepath, flipyz, option_colors, option_lights, option_cameras, option_embed_meshes, embeds):
+def export_scene(scene, filepath, flipyz, option_colors, option_lights, option_cameras, option_embed_meshes, embeds, option_url_base_html, option_copy_textures):
 
     source_file = os.path.basename(bpy.data.filepath)
 
     scene_text = ""
     data = {
-    "scene"       : scene,
-    "objects"     : scene.objects,
-    "embeds"      : embeds,
-    "source_file" : source_file,
-    "filepath"    : filepath,
-    "flipyz"      : flipyz,
-    "use_colors"  : option_colors,
-    "use_lights"  : option_lights, 
-    "use_cameras" : option_cameras,
-    "embed_meshes": option_embed_meshes
+    "scene"        : scene,
+    "objects"      : scene.objects,
+    "embeds"       : embeds,
+    "source_file"  : source_file,
+    "filepath"     : filepath,
+    "flipyz"       : flipyz,
+    "use_colors"   : option_colors,
+    "use_lights"   : option_lights,
+    "use_cameras"  : option_cameras,
+    "embed_meshes" : option_embed_meshes,
+    "base_html"    : option_url_base_html,
+    "copy_textures": option_copy_textures
     }
     scene_text += generate_ascii_scene(data)
 
@@ -1539,7 +1672,11 @@ def save(operator, context, filepath = "",
          option_lights = False,
          option_cameras = False,
          option_scale = 1.0,
-         option_embed_meshes = True):
+         option_embed_meshes = True,
+         option_url_base_html = False,
+         option_copy_textures = False):
+
+    #print("URL TYPE", option_url_base_html)
 
     filepath = ensure_extension(filepath, '.js')
 
@@ -1568,9 +1705,9 @@ def save(operator, context, filepath = "",
                     name = obj.data.name
 
                 if name not in geo_set:
-                    
+
                     if option_embed_meshes:
-                        
+
                         text, model_string = generate_mesh_string(obj, scene,
                                                         option_vertices,
                                                         option_vertices_truncate,
@@ -1580,17 +1717,20 @@ def save(operator, context, filepath = "",
                                                         option_uv_coords,
                                                         option_materials,
                                                         option_colors,
-                                                        False,
+                                                        False,          # align_model
                                                         option_flip_yz,
                                                         option_scale,
-                                                        False)
-                        
+                                                        False,          # export_single_model
+                                                        False,          # option_copy_textures
+                                                        filepath)
+
                         embeds[name] = model_string
 
                     else:
 
                         fname = generate_mesh_filename(name, filepath)
-                        export_mesh(obj, scene, fname,
+                        export_mesh(obj, scene,
+                                    fname,
                                     option_vertices,
                                     option_vertices_truncate,
                                     option_faces,
@@ -1599,14 +1739,23 @@ def save(operator, context, filepath = "",
                                     option_uv_coords,
                                     option_materials,
                                     option_colors,
-                                    False,
+                                    False,          # align_model
                                     option_flip_yz,
                                     option_scale,
-                                    False)
+                                    False,          # export_single_model
+                                    option_copy_textures)
 
                     geo_set.add(name)
 
-        export_scene(scene, filepath, option_flip_yz, option_colors, option_lights, option_cameras, option_embed_meshes, embeds)
+        export_scene(scene, filepath,
+                     option_flip_yz,
+                     option_colors,
+                     option_lights,
+                     option_cameras,
+                     option_embed_meshes,
+                     embeds,
+                     option_url_base_html,
+                     option_copy_textures)
 
     else:
 
@@ -1626,7 +1775,7 @@ def save(operator, context, filepath = "",
                     align_model,
                     option_flip_yz,
                     option_scale,
-                    True)
-
+                    True,            # export_single_model
+                    option_copy_textures)
 
     return {'FINISHED'}