ソースを参照

Merge pull request #4693 from phfatmonkey/Exporter-AddQuatRotation

Exporter add quat rotation
Mr.doob 11 年 前
コミット
e4ad4cb135

+ 10 - 5
utils/exporters/blender/2.65/scripts/addons/io_mesh_threejs/__init__.py

@@ -23,9 +23,9 @@
 
 bl_info = {
     "name": "three.js format",
-    "author": "mrdoob, kikko, alteredq, remoe, pxf, n3tfr34k",
-    "version": (1, 4, 0),
-    "blender": (2, 65, 0),
+    "author": "mrdoob, kikko, alteredq, remoe, pxf, n3tfr34k, crobi",
+    "version": (1, 5, 0),
+    "blender": (2, 7, 0),
     "location": "File > Import-Export",
     "description": "Import-Export three.js meshes",
     "warning": "",
@@ -201,6 +201,7 @@ def save_settings_export(properties):
 
     "option_animation_morph" : properties.option_animation_morph,
     "option_animation_skeletal" : properties.option_animation_skeletal,
+    "option_frame_index_as_time" : properties.option_frame_index_as_time,
 
     "option_frame_step" : properties.option_frame_step,
     "option_all_meshes" : properties.option_all_meshes,
@@ -263,6 +264,7 @@ def restore_settings_export(properties):
 
     properties.option_animation_morph = settings.get("option_animation_morph", False)
     properties.option_animation_skeletal = settings.get("option_animation_skeletal", False)
+    properties.option_frame_index_as_time = settings.get("option_frame_index_as_time", False)
 
     properties.option_frame_step = settings.get("option_frame_step", 1)
     properties.option_all_meshes = settings.get("option_all_meshes", True)
@@ -311,6 +313,7 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
 
     option_animation_morph = BoolProperty(name = "Morph animation", description = "Export animation (morphs)", default = False)
     option_animation_skeletal = BoolProperty(name = "Skeletal animation", description = "Export animation (skeletal)", default = False)
+    option_frame_index_as_time = BoolProperty(name = "Frame index as time", description = "Use (original) frame index as frame time", default = False)
 
     option_frame_step = IntProperty(name = "Frame step", description = "Animation frame step", min = 1, max = 1000, soft_min = 1, soft_max = 1000, default = 1)
     option_all_meshes = BoolProperty(name = "All meshes", description = "All meshes (merged)", default = True)
@@ -321,7 +324,7 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
 
     @classmethod
     def poll(cls, context):
-        return context.active_object is not None
+        return context.active_object != None
 
     def execute(self, context):
         print("Selected: " + context.active_object.name)
@@ -410,6 +413,8 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
         row = layout.row()
         row.prop(self.properties, "option_animation_skeletal")
         row = layout.row()
+        row.prop(self.properties, "option_frame_index_as_time")
+        row = layout.row()
         row.prop(self.properties, "option_frame_step")
         layout.separator()
 
@@ -450,4 +455,4 @@ def unregister():
     bpy.types.INFO_MT_file_import.remove(menu_func_import)
 
 if __name__ == "__main__":
-    register()
+    register()

+ 220 - 81
utils/exporters/blender/2.65/scripts/addons/io_mesh_threejs/export_threejs.py

@@ -90,7 +90,7 @@ TEMPLATE_SCENE_ASCII = """\
 	"formatVersion" : 3.2,
 	"type"          : "scene",
 	"sourceFile"    : "%(fname)s",
-	"generatedBy"   : "Blender 2.65 Exporter",
+	"generatedBy"   : "Blender 2.7 Exporter",
 	"objects"       : %(nobjects)s,
 	"geometries"    : %(ngeometries)s,
 	"materials"     : %(nmaterials)s,
@@ -269,7 +269,7 @@ TEMPLATE_FILE_ASCII = """\
 	"metadata" :
 	{
 		"formatVersion" : 3.1,
-		"generatedBy"   : "Blender 2.65 Exporter",
+		"generatedBy"   : "Blender 2.7 Exporter",
 		"vertices"      : %(nvertex)d,
 		"faces"         : %(nface)d,
 		"normals"       : %(nnormal)d,
@@ -308,7 +308,7 @@ TEMPLATE_MODEL_ASCII = """\
 
 	"skinWeights" : [%(weights)s],
 
-	"animations" : [%(animations)s]
+  "animations" : [%(animations)s]
 """
 
 TEMPLATE_VERTEX = "%g,%g,%g"
@@ -762,44 +762,56 @@ def get_armature():
 # (only the first armature will exported)
 # ##############################################################################
 
-def generate_bones(option_bones, flipyz):
+def generate_bones(meshes, option_bones, flipyz):
 
     if not option_bones:
         return "", 0
 
-    armature, armatureObject = get_armature()
-    if armature is None or armatureObject is None:
+    armature, armature_object = get_armature()
+    if armature_object is None:
         return "", 0
 
     hierarchy = []
+    armature_matrix = armature_object.matrix_world
+    pose_bones = armature_object.pose.bones
+    #pose_bones = armature.bones
 
-    TEMPLATE_BONE = '{"parent":%d,"name":"%s","pos":[%g,%g,%g],"rotq":[0,0,0,1]}'
+    TEMPLATE_BONE = '{"parent":%d,"name":"%s","pos":[%g,%g,%g],"rotq":[%g,%g,%g,%g],"scl":[%g,%g,%g]}'
 
-    for bone in armature.bones:
-        bonePos = None
+    for pose_bone in pose_bones:
+        armature_bone = pose_bone.bone
+        #armature_bone = pose_bone
+        bonePos = armature_matrix * armature_bone.head_local
         boneIndex = None
-        if bone.parent is None:
-            bonePos = bone.head_local
-            boneIndex = -1
+
+        if armature_bone.parent is None:
+            bone_matrix = armature_matrix * armature_bone.matrix_local
+            bone_index = -1
         else:
-            bonePos = bone.head_local - bone.parent.head_local
-            boneIndex = i = 0
-            for parent in armature.bones:
-                if parent.name == bone.parent.name:
-                    boneIndex = i
+            parent_matrix = armature_matrix * armature_bone.parent.matrix_local
+            bone_matrix = armature_matrix * armature_bone.matrix_local
+            bone_matrix = parent_matrix.inverted() * bone_matrix
+
+            bone_index = i = 0
+            for pose_parent in pose_bones:
+                armature_parent = pose_parent.bone
+                #armature_parent = pose_parent
+                if armature_parent.name == armature_bone.parent.name:
+                    bone_index = i
                 i += 1
 
-        bonePosWorld = armatureObject.matrix_world * bonePos
+        pos, rot, scl = bone_matrix.decompose()
+
         if flipyz:
-            joint = TEMPLATE_BONE % (boneIndex, bone.name, bonePosWorld.x, bonePosWorld.z, -bonePosWorld.y)
+            joint = TEMPLATE_BONE % (bone_index, armature_bone.name, pos.x, pos.z, -pos.y, rot.x, rot.z, -rot.y, rot.w, scl.x, scl.z, scl.y)
             hierarchy.append(joint)
         else:
-            joint = TEMPLATE_BONE % (boneIndex, bone.name, bonePosWorld.x, bonePosWorld.y, bonePosWorld.z)
+            joint = TEMPLATE_BONE % (bone_index, armature_bone.name, pos.x, pos.y,  pos.z, rot.x, rot.y,  rot.z, rot.w, scl.x, scl.y, scl.z)
             hierarchy.append(joint)
-                
-    bones_string = ",".join(hierarchy)
 
-    return bones_string, len(armature.bones)
+    bones_string = ",".join(hierarchy)
+    
+    return bones_string, len(pose_bones)
 
 
 # ##############################################################################
@@ -814,7 +826,7 @@ def generate_indices_and_weights(meshes, option_skinning):
     indices = []
     weights = []
 
-    armature, armatureObject = get_armature()
+    armature, armature_object = get_armature()
 
     for mesh, object in meshes:
 
@@ -845,9 +857,9 @@ def generate_indices_and_weights(meshes, option_skinning):
                 weight = group.weight
 
                 bone_array.append( (index, weight) )
-
+                
             bone_array.sort(key = operator.itemgetter(1), reverse=True)
-
+            
             # select first N bones
 
             for i in range(MAX_INFLUENCES):
@@ -859,7 +871,7 @@ def generate_indices_and_weights(meshes, option_skinning):
                     index = bone_proxy[0]
                     weight = bone_proxy[1]
 
-                    for j, bone in enumerate(armature.bones):
+                    for j, bone in enumerate(armature_object.pose.bones):
                         if object.vertex_groups[index].name == bone.name:
                             indices.append('%d' % j)
                             weights.append('%g' % weight)
@@ -873,8 +885,8 @@ def generate_indices_and_weights(meshes, option_skinning):
                 else:
                     indices.append('0')
                     weights.append('0')
-
-
+    
+    
     indices_string = ",".join(indices)
     weights_string = ",".join(weights)
 
@@ -886,23 +898,33 @@ def generate_indices_and_weights(meshes, option_skinning):
 # (only the first action will exported)
 # ##############################################################################
 
-def generate_animation(option_animation_skeletal, option_frame_step, flipyz, action_index):
+def generate_animation(option_animation_skeletal, option_frame_step, flipyz, option_frame_index_as_time, index):
 
-    if not option_animation_skeletal or len(bpy.data.actions) == 0 or len(bpy.data.actions) == 0:
+    if not option_animation_skeletal or len(bpy.data.actions) == 0:
         return ""
 
     # TODO: Add scaling influences
 
-    action = bpy.data.actions[action_index]
-    armature, armatureObject = get_armature()
-    if armature is None or armatureObject is None:
+    action = bpy.data.actions[index]
+    
+    # get current context and then switch to dopesheet temporarily
+    
+    current_context = bpy.context.area.type
+    
+    bpy.context.area.type = "DOPESHEET_EDITOR"
+    bpy.context.space_data.mode = "ACTION"    
+    
+    # set active action
+    bpy.context.area.spaces.active.action = action
+    
+    armature, armature_object = get_armature()
+    if armature_object is None or armature is None:
         return "", 0
-    armatureMat = armatureObject.matrix_world
-    l,r,s = armatureMat.decompose()
-    armatureRotMat = r.to_matrix()
-
-    parents = []
-    parent_index = -1
+        
+    #armature_object = bpy.data.objects['marine_rig']
+    
+        
+    armature_matrix = armature_object.matrix_world
 
     fps = bpy.data.scenes[0].render.fps
 
@@ -911,75 +933,180 @@ def generate_animation(option_animation_skeletal, option_frame_step, flipyz, act
 
     frame_length = end_frame - start_frame
 
-    TEMPLATE_KEYFRAME_FULL  = '{"time":%g,"pos":[%g,%g,%g],"rot":[%g,%g,%g,%g],"scl":[1,1,1]}'
-    TEMPLATE_KEYFRAME       = '{"time":%g,"pos":[%g,%g,%g],"rot":[%g,%g,%g,%g]}'
-    TEMPLATE_KEYFRAME_POS   = '{"time":%g,"pos":[%g,%g,%g]}'
-    TEMPLATE_KEYFRAME_ROT   = '{"time":%g,"rot":[%g,%g,%g,%g]}'
+    used_frames = int(frame_length / option_frame_step) + 1
 
-    for hierarchy in armature.bones:
+    TEMPLATE_KEYFRAME_FULL  = '{"time":%g,"pos":[%g,%g,%g],"rot":[%g,%g,%g,%g],"scl":[%g,%g,%g]}'
+    TEMPLATE_KEYFRAME_BEGIN = '{"time":%g'
+    TEMPLATE_KEYFRAME_END   = '}'
+    TEMPLATE_KEYFRAME_POS   = ',"pos":[%g,%g,%g]'
+    TEMPLATE_KEYFRAME_ROT   = ',"rot":[%g,%g,%g,%g]'
+    TEMPLATE_KEYFRAME_SCL   = ',"scl":[%g,%g,%g]'
 
-        keys = []
+    keys = []
+    channels_location = []
+    channels_rotation = []
+    channels_scale = []
+    
+    # Precompute per-bone data
+    for pose_bone in armature_object.pose.bones:
+        armature_bone = pose_bone.bone
+        keys.append([])
+        channels_location.append(  find_channels(action, armature_bone, "location"))
+        channels_rotation.append(  find_channels(action, armature_bone, "rotation_quaternion"))
+        channels_rotation.append(  find_channels(action, armature_bone, "rotation_euler"))
+        channels_scale.append(     find_channels(action, armature_bone, "scale"))
+
+    # Process all frames
+    for frame_i in range(0, used_frames):
+
+        #print("Processing frame %d/%d" % (frame_i, used_frames))
+        # Compute the index of the current frame (snap the last index to the end)
+        frame = start_frame + frame_i * option_frame_step
+        if frame_i == used_frames-1:
+            frame = end_frame
+
+        # Compute the time of the frame
+        if option_frame_index_as_time:
+            time = frame - start_frame
+        else:
+            time = (frame - start_frame) / fps
 
-        for frame in range(int(start_frame), int(end_frame / option_frame_step) + 1):
+        # Let blender compute the pose bone transformations
+        bpy.data.scenes[0].frame_set(frame)
 
-            pos, pchange = position(hierarchy, frame * option_frame_step, action, armatureMat)
-            rot, rchange = rotation(hierarchy, frame * option_frame_step, action, armatureRotMat)
+        # Process all bones for the current frame
+        bone_index = 0
+        for pose_bone in armature_object.pose.bones:
+
+            # Extract the bone transformations
+            if pose_bone.parent is None:
+                bone_matrix = armature_matrix * pose_bone.matrix
+            else:
+                parent_matrix = armature_matrix * pose_bone.parent.matrix
+                bone_matrix = armature_matrix * pose_bone.matrix
+                bone_matrix = parent_matrix.inverted() * bone_matrix
+            pos, rot, scl = bone_matrix.decompose()
+
+            pchange = True or has_keyframe_at(channels_location[bone_index], frame)
+            rchange = True or has_keyframe_at(channels_rotation[bone_index], frame)
+            schange = True or has_keyframe_at(channels_scale[bone_index], frame)
 
             if flipyz:
                 px, py, pz = pos.x, pos.z, -pos.y
                 rx, ry, rz, rw = rot.x, rot.z, -rot.y, rot.w
+                sx, sy, sz = scl.x, scl.z, scl.y
             else:
                 px, py, pz = pos.x, pos.y, pos.z
                 rx, ry, rz, rw = rot.x, rot.y, rot.z, rot.w
+                sx, sy, sz = scl.x, scl.y, scl.z
 
             # START-FRAME: needs pos, rot and scl attributes (required frame)
 
-            if frame == int(start_frame):
+            if frame == start_frame:
 
-                time = (frame * option_frame_step - start_frame) / fps
-                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw)
-                keys.append(keyframe)
+                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw, sx, sy, sz)
+                keys[bone_index].append(keyframe)
 
             # END-FRAME: needs pos, rot and scl attributes with animation length (required frame)
 
-            elif frame == int(end_frame / option_frame_step):
+            elif frame == end_frame:
 
-                time = frame_length / fps
-                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw)
-                keys.append(keyframe)
+                keyframe = TEMPLATE_KEYFRAME_FULL % (time, px, py, pz, rx, ry, rz, rw, sx, sy, sz)
+                keys[bone_index].append(keyframe)
 
             # MIDDLE-FRAME: needs only one of the attributes, can be an empty frame (optional frame)
 
             elif pchange == True or rchange == True:
 
-                time = (frame * option_frame_step - start_frame) / fps
-
-                if pchange == True and rchange == True:
-                    keyframe = TEMPLATE_KEYFRAME % (time, px, py, pz, rx, ry, rz, rw)
-                elif pchange == True:
-                    keyframe = TEMPLATE_KEYFRAME_POS % (time, px, py, pz)
-                elif rchange == True:
-                    keyframe = TEMPLATE_KEYFRAME_ROT % (time, rx, ry, rz, rw)
+                keyframe = TEMPLATE_KEYFRAME_BEGIN % time
+                if pchange == True:
+                    keyframe = keyframe + TEMPLATE_KEYFRAME_POS % (px, py, pz)
+                if rchange == True:
+                    keyframe = keyframe + TEMPLATE_KEYFRAME_ROT % (rx, ry, rz, rw)
+                if schange == True:
+                    keyframe = keyframe + TEMPLATE_KEYFRAME_SCL % (sx, sy, sz)
+                keyframe = keyframe + TEMPLATE_KEYFRAME_END
 
-                keys.append(keyframe)
+                keys[bone_index].append(keyframe)
+            bone_index += 1
 
-        keys_string = ",".join(keys)
+    # Gather data
+    parents = []
+    bone_index = 0
+    for pose_bone in armature_object.pose.bones:
+        keys_string = ",".join(keys[bone_index])
+        parent_index = bone_index - 1 # WTF? Also, this property is not used by three.js
         parent = '{"parent":%d,"keys":[%s]}' % (parent_index, keys_string)
-        parent_index += 1
+        bone_index += 1
         parents.append(parent)
-
     hierarchy_string = ",".join(parents)
-    animation_string = '"name":"%s","fps":%d,"length":%g,"hierarchy":[%s]' % (action.name, fps, (frame_length / fps), hierarchy_string)
 
+    if option_frame_index_as_time:
+        length = frame_length
+    else:
+        length = frame_length / fps
+
+    animation_string = '"name":"%s","fps":%d,"length":%g,"hierarchy":[%s]' % (action.name, fps, length, hierarchy_string)
+
+    bpy.data.scenes[0].frame_set(start_frame)
+
+    # reset context
+    
+    bpy.context.area.type = current_context
+    
     return animation_string
 
-def generate_all_animations(option_animation_skeletal, option_frame_step, flipyz):
+def find_channels(action, bone, channel_type):
+    bone_name = bone.name
+    ngroups = len(action.groups)
+    result = []
+
+    # Variant 1: channels grouped by bone names
+    if ngroups > 0:
+
+        # Find the channel group for the given bone
+        group_index = -1
+        for i in range(ngroups):
+            if action.groups[i].name == bone_name:
+                group_index = i
+
+        # Get all desired channels in that group
+        if group_index > -1:
+            for channel in action.groups[group_index].channels:
+                if channel_type in channel.data_path:
+                    result.append(channel)
+
+    # Variant 2: no channel groups, bone names included in channel names
+    else:
+
+        bone_label = '"%s"' % bone_name
+
+        for channel in action.fcurves:
+            data_path = channel.data_path
+            if bone_label in data_path and channel_type in data_path:
+                result.append(channel)
+
+    return result
+
+def find_keyframe_at(channel, frame):
+    for keyframe in channel.keyframe_points:
+        if keyframe.co[0] == frame:
+            return keyframe
+    return None
+
+def has_keyframe_at(channels, frame):
+    for channel in channels:
+        if not find_keyframe_at(channel, frame) is None:
+            return True
+    return False
+
+def generate_all_animations(option_animation_skeletal, option_frame_step, flipyz, option_frame_index_as_time):
     all_animations_string = ""
     if option_animation_skeletal:
         for index in range(0, len(bpy.data.actions)):
             if index != 0 :
                 all_animations_string += ", \n"
-            all_animations_string += "{" + generate_animation(option_animation_skeletal, option_frame_step, flipyz, index) + "}"
+            all_animations_string += "{" + generate_animation(option_animation_skeletal, option_frame_step, flipyz, option_frame_index_as_time,index) + "}"
     return all_animations_string
 
 def handle_position_channel(channel, frame, position):
@@ -1036,7 +1163,7 @@ def position(bone, frame, action, armatureMatrix):
 
     position = position * bone.matrix_local.inverted()
 
-    if bone.parent is None:
+    if bone.parent == None:
 
         position.x += bone.head.x
         position.y += bone.head.y
@@ -1344,6 +1471,7 @@ def generate_ascii_model(meshes, morphs,
                          filepath,
                          option_animation_morph,
                          option_animation_skeletal,
+                         option_frame_index_as_time,
                          option_frame_step):
 
     vertices = []
@@ -1421,7 +1549,7 @@ def generate_ascii_model(meshes, morphs,
 
     faces_string, nfaces = generate_faces(normals, uv_layers, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces)
 
-    bones_string, nbone = generate_bones(option_bones, flipyz)
+    bones_string, nbone = generate_bones(meshes, option_bones, flipyz)
     indices_string, weights_string = generate_indices_and_weights(meshes, option_skinning)
 
     materials_string = ",\n\n".join(materials)
@@ -1444,7 +1572,7 @@ def generate_ascii_model(meshes, morphs,
     "bones"     : bones_string,
     "indices"   : indices_string,
     "weights"   : weights_string,
-    "animations" : generate_all_animations(option_animation_skeletal, option_frame_step, flipyz)
+    "animations" : generate_all_animations(option_animation_skeletal, option_frame_step, flipyz, option_frame_index_as_time)
     }
 
     text = TEMPLATE_FILE_ASCII % {
@@ -1483,6 +1611,10 @@ def extract_meshes(objects, scene, export_single_model, option_scale, flipyz):
             if not mesh:
                 raise Exception("Error, could not get mesh data from object [%s]" % object.name)
 
+            # preserve original name
+
+            mesh.name = object.name
+
             if export_single_model:
 
                 if flipyz:
@@ -1523,6 +1655,7 @@ def generate_mesh_string(objects, scene,
                 filepath,
                 option_animation_morph,
                 option_animation_skeletal,
+                option_frame_index_as_time,
                 option_frame_step):
 
     meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
@@ -1587,6 +1720,7 @@ def generate_mesh_string(objects, scene,
                                 filepath,
                                 option_animation_morph,
                                 option_animation_skeletal,
+                                option_frame_index_as_time,
                                 option_frame_step)
 
     # remove temp meshes
@@ -1614,7 +1748,8 @@ def export_mesh(objects,
                 option_copy_textures,
                 option_animation_morph,
                 option_animation_skeletal,
-                option_frame_step):
+                option_frame_step,
+                option_frame_index_as_time):
 
     """Export single mesh"""
 
@@ -1637,6 +1772,7 @@ def export_mesh(objects,
                 filepath,
                 option_animation_morph,
                 option_animation_skeletal,
+                option_frame_index_as_time,
                 option_frame_step)
 
     write_file(filepath, text)
@@ -2273,7 +2409,6 @@ def generate_lights(data):
 
     return ",\n\n".join(chunks), len(chunks)
 
-
 # #####################################################
 # Scene exporter - embedded meshes
 # #####################################################
@@ -2433,7 +2568,8 @@ def save(operator, context, filepath = "",
          option_animation_morph = False,
          option_animation_skeletal = False,
          option_frame_step = 1,
-         option_all_meshes = True):
+         option_all_meshes = True,
+         option_frame_index_as_time = False):
 
     #print("URL TYPE", option_url_base_html)
 
@@ -2497,9 +2633,10 @@ def save(operator, context, filepath = "",
                                                         filepath,
                                                         option_animation_morph,
                                                         option_animation_skeletal,
+                                                        option_frame_index_as_time,
                                                         option_frame_step)
 
-                        embeds[name] = model_string
+                        embeds[object.data.name] = model_string
 
                     else:
 
@@ -2522,7 +2659,8 @@ def save(operator, context, filepath = "",
                                     option_copy_textures,
                                     option_animation_morph,
                                     option_animation_skeletal,
-                                    option_frame_step)
+                                    option_frame_step,
+                                    option_frame_index_as_time)
 
                     geo_set.add(name)
 
@@ -2555,6 +2693,7 @@ def save(operator, context, filepath = "",
                     option_copy_textures,
                     option_animation_morph,
                     option_animation_skeletal,
-                    option_frame_step)
+                    option_frame_step,
+                    option_frame_index_as_time)
 
     return {'FINISHED'}

+ 0 - 2
utils/exporters/blender/2.65/scripts/addons/io_mesh_threejs/import_threejs.py

@@ -130,7 +130,6 @@ def create_mesh_object(name, vertices, materials, face_data, flipYZ, recalculate
     if face_data["hasVertexNormals"]:
 
         print("setting vertex normals")
-        me.update(calc_tessface = True)
 
         for fi in range(len(faces)):
 
@@ -269,7 +268,6 @@ def create_mesh_object(name, vertices, materials, face_data, flipYZ, recalculate
             me.materials.append(m)
 
         print("setting materials (faces)")
-        me.update(calc_tessface = True)
 
         for fi in range(len(faces)):