Explorar el Código

Merge pull request #215 from hedgehog90/blender2.8

Further Object.to_mesh() fixes for latest Blender 2.8 build
Lu Jiacheng hace 6 años
padre
commit
24880c1cf6
Se han modificado 65 ficheros con 485 adiciones y 369 borrados
  1. 19 26
      io_scene_godot/__init__.py
  2. 7 2
      io_scene_godot/converters/__init__.py
  3. 0 10
      io_scene_godot/converters/armature.py
  4. 223 140
      io_scene_godot/converters/mesh.py
  5. 31 64
      io_scene_godot/converters/physics.py
  6. 39 15
      io_scene_godot/export_godot.py
  7. 13 11
      io_scene_godot/structures.py
  8. 0 0
      tests/reference_exports/action_animation/animation_bone_transform.escn
  9. 0 0
      tests/reference_exports/action_animation/animation_loop.escn
  10. 0 0
      tests/reference_exports/action_animation/animation_object_transform.escn
  11. 0 0
      tests/reference_exports/action_animation/animation_rotation_euler.escn
  12. 1 1
      tests/reference_exports/action_animation/animation_shared_action.escn
  13. 5 5
      tests/reference_exports/action_animation/physics_animation.escn
  14. 1 1
      tests/reference_exports/action_with_constraint/bone_attachment_ik.escn
  15. 0 0
      tests/reference_exports/action_with_constraint/constraint_external_IK.escn
  16. 2 2
      tests/reference_exports/action_with_constraint/constraint_internal_IK.escn
  17. 0 0
      tests/reference_exports/action_with_constraint/constraint_with_undeform_bone.escn
  18. 2 2
      tests/reference_exports/action_with_constraint/stashed_constraint.escn
  19. 1 1
      tests/reference_exports/armature/armature_bone_attachment.escn
  20. 3 3
      tests/reference_exports/armature/armature_illegal_bone_name.escn
  21. 8 0
      tests/reference_exports/armature/armature_not_ancester_of_mesh.escn
  22. 0 0
      tests/reference_exports/armature/armature_with_mesh.escn
  23. 0 0
      tests/reference_exports/armature/armature_with_non_deform_bone.escn
  24. 0 0
      tests/reference_exports/armature/armature_with_other_vertex_groups.escn
  25. 0 0
      tests/reference_exports/armature/armature_with_physics.escn
  26. 0 0
      tests/reference_exports/armature/armature_with_pose.escn
  27. 0 2
      tests/reference_exports/armature/just_armature.escn
  28. 0 0
      tests/reference_exports/armature/non-inherit-bone.escn
  29. 1 1
      tests/reference_exports/camera/animation_camera.escn
  30. 0 2
      tests/reference_exports/camera/just_cameras.escn
  31. 1 1
      tests/reference_exports/light/animation_sun.escn
  32. 1 1
      tests/reference_exports/light/animation_various_lights.escn
  33. 1 1
      tests/reference_exports/light/cycles_lights.escn
  34. 1 1
      tests/reference_exports/light/just_point_lights.escn
  35. 1 1
      tests/reference_exports/light/just_spot_lights.escn
  36. 2 1
      tests/reference_exports/material/material_search.escn
  37. 2 2
      tests/reference_exports/material/object_link_material.escn
  38. 1 1
      tests/reference_exports/material/simple_materials.escn
  39. 1 1
      tests/reference_exports/material_cycle/material_anistropy.escn
  40. 82 34
      tests/reference_exports/material_cycle/material_cycle.escn
  41. 5 5
      tests/reference_exports/material_cycle/material_normal.escn
  42. 2 1
      tests/reference_exports/material_cycle/material_unpack_texture.escn
  43. 1 1
      tests/reference_exports/mesh/just_mesh.escn
  44. 1 1
      tests/reference_exports/mesh/parented_meshes.escn
  45. 8 8
      tests/reference_exports/mesh/physics.escn
  46. 0 12
      tests/reference_exports/mesh/single_edge_and_vertex.escn
  47. 1 1
      tests/reference_exports/mesh/tangent_test.escn
  48. 1 1
      tests/reference_exports/mesh/uv_testing.escn
  49. 1 1
      tests/reference_exports/mesh/vertex_color.escn
  50. 1 1
      tests/reference_exports/misc/duplicate_name.escn
  51. 0 0
      tests/reference_exports/misc/invisible_objects.escn
  52. 0 0
      tests/reference_exports/nla_animation/animation_multi_strip.escn
  53. 0 0
      tests/reference_exports/nla_animation/animation_with_empty_strip.escn
  54. 0 0
      tests/reference_exports/nla_animation/nla_with_active_action.escn
  55. 1 1
      tests/reference_exports/nla_animation/nla_with_no_active_action.escn
  56. 0 0
      tests/reference_exports/nla_animation/nla_with_stashed_action.escn
  57. 1 1
      tests/reference_exports/scene_animation/animation_parented_objects.escn
  58. 1 1
      tests/reference_exports/shape_key/animation_shapekey.escn
  59. 0 0
      tests/reference_exports/shape_key/animation_shapekey_with_transform.escn
  60. 1 1
      tests/reference_exports/shape_key/just_shapekey.escn
  61. 1 1
      tests/reference_exports/shape_key/shapekey_with_multi_surface.escn
  62. 0 0
      tests/reference_exports/shape_key/shapekey_with_pose.escn
  63. 10 0
      tests/reference_exports/shape_key/shapekey_with_subdivision.escn
  64. BIN
      tests/test_scenes/armature/armature_not_ancester_of_mesh.blend
  65. BIN
      tests/test_scenes/shape_key/shapekey_with_subdivision.blend

+ 19 - 26
io_scene_godot/__init__.py

@@ -46,11 +46,11 @@ class ExportGodot(bpy.types.Operator, ExportHelper):
     bl_options = {"PRESET"}
 
     filename_ext = ".escn"
-    filter_glob = StringProperty(default="*.escn", options={"HIDDEN"})
+    filter_glob: StringProperty(default="*.escn", options={"HIDDEN"})
 
     # List of operator properties, the attributes will be assigned
     # to the class instance from the operator settings before calling
-    object_types = EnumProperty(
+    object_types: EnumProperty(
         name="Object Types",
         options={"ENUM_FLAG"},
         items=(
@@ -58,41 +58,39 @@ class ExportGodot(bpy.types.Operator, ExportHelper):
             ("CAMERA", "Camera", ""),
             ("LIGHT", "Light", ""),
             ("ARMATURE", "Armature", ""),
-            ("MESH", "Mesh", ""),
-            # ("CURVE", "Curve", ""),
+            ("GEOMETRY", "Geometry", "")
         ),
         default={
             "EMPTY",
             "CAMERA",
             "LIGHT",
             "ARMATURE",
-            "MESH",
-            # "CURVE"
+            "GEOMETRY"
         },
     )
 
-    use_visible_objects = BoolProperty(
+    use_visible_objects: BoolProperty(
         name="Only Visible Object",
         description="Export only objects which are in the current view layer "
                     "and are visible.",
         default=True,
     )
-    use_export_selected = BoolProperty(
+    use_export_selected: BoolProperty(
         name="Only Selected Objects",
         description="Export only selected objects",
         default=False,
     )
-    use_mesh_modifiers = BoolProperty(
+    use_mesh_modifiers: BoolProperty(
         name="Apply Modifiers",
         description="Apply modifiers to mesh objects (on a copy!).",
         default=True,
     )
-    use_exclude_ctrl_bone = BoolProperty(
+    use_exclude_ctrl_bone: BoolProperty(
         name="Exclude Control Bones",
         description="Do not export control bones (bone.use_deform = false)",
         default=True,
     )
-    use_export_animation = BoolProperty(
+    use_export_animation: BoolProperty(
         name="Export Animation",
         description="Export all the animation actions (include actions "
                     "in nla_tracks), note that by default blender animation "
@@ -100,40 +98,35 @@ class ExportGodot(bpy.types.Operator, ExportHelper):
                     "own AnimationPlayer hold their actions",
         default=True,
     )
-    use_export_material = BoolProperty(
-        name="Export Materinal",
+    use_export_material: BoolProperty(
+        name="Export Material",
         description="Export all the material associated with mesh surfaces",
         default=True,
     )
-    use_export_shape_key = BoolProperty(
+    use_export_shape_key: BoolProperty(
         name="Export Shape Key",
         description="Export all the shape keys in mesh objects",
         default=True,
     )
-    use_stashed_action = BoolProperty(
+    use_stashed_action: BoolProperty(
         name="Export Stashed Actions",
         description="Export stashed actions and muted nla_strip as separate "
                     "animation and place into AnimationPlayer",
         default=True,
     )
-    use_export_material = BoolProperty(
-        name="Export Materinal",
-        description="Export all the material associated with mesh surfaces",
-        default=True,
-    )
-    use_beta_features = BoolProperty(
+    use_beta_features: BoolProperty(
         name="Use Beta Features",
         description="Export using new features coming in Godot beta versions",
         default=True,
     )
-    generate_external_material = BoolProperty(
+    generate_external_material: BoolProperty(
         name="Generate External Material",
         description="If turned on, materials in the exported scene would "
                     "generate external .material files when imported to "
                     "godot,  thus make it easy for material reusing",
         default=False,
     )
-    animation_modes = EnumProperty(
+    animation_modes: EnumProperty(
         name="Animation Modes",
         description="Configuration of how blender animation data being "
                     "exported to godot AnimationPlayer as well as the "
@@ -158,7 +151,7 @@ class ExportGodot(bpy.types.Operator, ExportHelper):
             )
         )
     )
-    material_search_paths = EnumProperty(
+    material_search_paths: EnumProperty(
         name="Material Search Paths",
         description="Search for existing godot materials with names that match"
                     "the blender material names (ie the file <matname>.tres"
@@ -243,8 +236,8 @@ def export(filename, overrides=None):
     """
 
     default_settings = dict()
-    for attr_name in ExportGodot.__dict__:
-        attr = ExportGodot.__dict__[attr_name]
+    for attr_name in ExportGodot.__annotations__:
+        attr = ExportGodot.__annotations__[attr_name]
         # This introspection is not very robust and may break in future blende
         # versions. This is becase for some reason you can't compare against
         # bpy.types.Property because. well, they end up not being subclasses

+ 7 - 2
io_scene_godot/converters/__init__.py

@@ -21,13 +21,18 @@ from .physics import export_physics_properties
 from .armature import export_armature_node, export_bone_attachment
 from .animation import export_animation_data
 
-
+# TODO: What about Empties which refer to group instances? (in 2.8 Collection
+# Instances)
 BLENDER_TYPE_TO_EXPORTER = {
     "MESH": export_mesh_node,
     "ARMATURE": export_armature_node,
     "CAMERA": export_camera_node,
     "LIGHT": export_light_node,
-    "EMPTY": export_empty_node
+    "EMPTY": export_empty_node,
+    "CURVE": export_mesh_node,
+    "SURFACE": export_mesh_node,
+    "META": export_mesh_node,
+    "FONT": export_mesh_node
 }
 
 BONE_ATTACHMENT_EXPORTER = export_bone_attachment

+ 0 - 10
io_scene_godot/converters/armature.py

@@ -27,16 +27,6 @@ def export_bone_attachment(escn_file, node, parent_gd_node):
     return bone_attachment
 
 
-def find_skeletion_node(node):
-    """Return the cloest Skeleton from node to root,
-    if not found, return None"""
-    node_ptr = node
-    while (node_ptr is not None and
-           node_ptr.get_type() != "Skeleton"):
-        node_ptr = node_ptr.parent
-    return node_ptr
-
-
 class Bone:
     """A Bone has almost same attributes as Godot bones"""
 

+ 223 - 140
io_scene_godot/converters/mesh.py

@@ -5,8 +5,8 @@ import bmesh
 import mathutils
 
 from .material import export_material
-from ..structures import (Array, NodeTemplate, InternalResource, NodePath,
-                          Map, gamma_correct)
+from ..structures import (
+    Array, NodeTemplate, InternalResource, Map, gamma_correct)
 from . import physics
 from . import armature
 from . import animation
@@ -25,44 +25,50 @@ def export_mesh_node(escn_file, export_settings, obj, parent_gd_node):
         parent_gd_node = physics.export_physics_properties(
             escn_file, export_settings, obj, parent_gd_node
         )
-
-    if physics.has_physics(obj) and obj.display_type == "WIRE":
         # skip wire mesh which is used as collision mesh
-        return parent_gd_node
+        if obj.display_type == "WIRE":
+            return parent_gd_node
 
     mesh_node = NodeTemplate(obj.name, "MeshInstance", parent_gd_node)
-    mesh_exporter = MeshResourceExporter(obj)
-
-    armature_data = get_modifier_armature_data(obj)
-    if ("ARMATURE" in export_settings['object_types'] and
-            armature_data is not None):
-        skeleton_node = armature.find_skeletion_node(parent_gd_node)
-        if skeleton_node is not None:
-            mesh_exporter.init_mesh_bones_data(skeleton_node)
-            mesh_node['skeleton'] = NodePath(
-                mesh_node.get_path(), skeleton_node.get_path())
+    mesh_exporter = ArrayMeshResourceExporter(obj)
+
+    armature_obj = None
+    if "ARMATURE" in export_settings['object_types']:
+        armature_obj = get_modifier_armature(obj)
+        if armature_obj:
+            mesh_exporter.init_mesh_bones_data(armature_obj, export_settings)
+            # set armature to REST so current pose does not affect converted
+            # meshes.
+            armature_pose_position = armature_obj.data.pose_position
+            armature_obj.data.pose_position = "REST"
 
     mesh_id = mesh_exporter.export_mesh(escn_file, export_settings)
 
-    mesh_node['mesh'] = "SubResource({})".format(mesh_id)
-    mesh_node['visible'] = obj.visible_get()
+    if armature_obj:
+        # set armature back to previous pose_position
+        armature_obj.data.pose_position = armature_pose_position
+
+    if mesh_id is not None:
+        mesh_node['mesh'] = "SubResource({})".format(mesh_id)
+        mesh_node['visible'] = obj.visible_get()
+
+        mesh_resource = escn_file.internal_resources[mesh_id - 1]
+        export_object_link_material(
+            escn_file, export_settings, obj, mesh_resource, mesh_node
+        )
 
     # Transform of rigid mesh is moved up to its collision
     # shapes.
-    if not physics.has_physics(obj):
-        mesh_node['transform'] = obj.matrix_local
-    else:
+    if physics.has_physics(obj):
         mesh_node['transform'] = mathutils.Matrix.Identity(4)
+    else:
+        mesh_node['transform'] = obj.matrix_local
 
     escn_file.add_node(mesh_node)
 
-    export_object_link_material(
-        escn_file, export_settings, obj, mesh_node
-    )
-
     # export shape key animation
     if (export_settings['use_export_shape_key'] and
-            obj.data.shape_keys is not None):
+            has_shape_keys(obj.data)):
         animation.export_animation_data(
             escn_file, export_settings, mesh_node,
             obj.data.shape_keys, 'shapekey')
@@ -87,22 +93,19 @@ def fix_vertex(vtx):
     return mathutils.Vector((vtx.x, vtx.z, -vtx.y))
 
 
-def get_modifier_armature_data(mesh_object):
-    """Get the armature modifier of a blender object
+def get_modifier_armature(mesh_object):
+    """Get the armature modifier target object of a blender object
     if does not have one, return None"""
     for modifier in mesh_object.modifiers:
-        if (isinstance(modifier, bpy.types.ArmatureModifier) and
-                modifier.object is not None):
-            return modifier.object.data
+        if isinstance(modifier, bpy.types.ArmatureModifier):
+            return modifier.object
     return None
 
 
 def export_object_link_material(escn_file, export_settings, mesh_object,
-                                gd_node):
+                                mesh_resource, gd_node):
     """Export object linked material, if multiple object link material,
     only export the first one in the material slots"""
-    mesh_resource_id = escn_file.get_internal_resource(mesh_object.data)
-    mesh_resource = escn_file.internal_resources[mesh_resource_id - 1]
     for index, slot in enumerate(mesh_object.material_slots):
         if slot.link == 'OBJECT' and slot.material is not None:
             surface_id = mesh_resource.get_surface_id(index)
@@ -115,8 +118,88 @@ def export_object_link_material(escn_file, export_settings, mesh_object,
                 )
 
 
+def get_applicable_modifiers(obj, export_settings):
+    """Returns a list of all the modifiers that'll be applied to the final
+    godot mesh"""
+    ignore_modifiers = []
+    if not export_settings['use_mesh_modifiers']:
+        return []
+    if "ARMATURE" in export_settings['object_types']:
+        ignore_modifiers.append(bpy.types.ArmatureModifier)
+    ignore_modifiers = tuple(ignore_modifiers)
+    return [m for m in obj.modifiers if not isinstance(m, ignore_modifiers)
+            and m.show_viewport]
+
+
+def record_modifier_config(obj):
+    """Returns modifiers viewport visibility config"""
+    modifier_config_cache = []
+    for mod in obj.modifiers:
+        modifier_config_cache.append(mod.show_viewport)
+    return modifier_config_cache
+
+
+def restore_modifier_config(obj, modifier_config_cache):
+    """Applies modifiers viewport visibility config"""
+    for i, mod in enumerate(obj.modifiers):
+        mod.show_viewport = modifier_config_cache[i]
+
+
+def has_shape_keys(object_data):
+    """Determine if object data has shape keys"""
+    return (hasattr(object_data, "shape_keys") and
+            object_data.shape_keys is not None)
+
+
+class MeshResourceKey:
+    """Produces a key based on an mesh object's data, every different
+    Mesh Resource would have a unique key"""
+
+    def __init__(self, rsc_type, obj, export_settings):
+        mesh_data = obj.data
+
+        # Resource type included because same blender mesh may be used as
+        # MeshResource or CollisionShape, but they are different resource
+        gd_rsc_type = rsc_type
+
+        # Here collect info of all the modifiers applied on the mesh.
+        # Modifiers along with the original mesh data would determine
+        # the evaluated mesh.
+        mod_info_list = list()
+        for modifier in get_applicable_modifiers(obj, export_settings):
+            # Modifier name indicates its type, its an identifier
+            mod_info_list.append(modifier.name)
+
+            # First property is always 'rna_type', skip it
+            for prop in modifier.bl_rna.properties.keys()[1:]:
+                # Note that Property may be `BoolProperty`,
+                # `CollectionProperty`, `EnumProperty`, `FloatProperty`,
+                # `IntProperty`, `PointerProperty`, `StringProperty`"
+                # Most of them are primary type when accessed with `getattr`,
+                # so they are fine to be hashed.
+                # For `PointerProperty`, it is mostly an bpy.types.ID, hash it
+                # would get its python object identifier, which is also good.
+                # For `CollectionProperty`, it would make more sense to
+                # traversal it, however, we cut down it here to allow
+                # some of mesh resource not be shared because of simplicity
+                mod_info_list.append(getattr(modifier, prop))
+
+        self._data = tuple([mesh_data, gd_rsc_type] + mod_info_list)
+        # Precalculate the hash now for better efficiency later
+        self._hash = hash(self._data)
+
+    def __hash__(self):
+        return self._hash
+
+    def __eq__(self, other):
+        # pylint: disable=protected-access
+        return (self.__class__ == other.__class__ and
+                self._data == other._data)
+
+
 class ArrayMeshResource(InternalResource):
     """Godot ArrayMesh resource, containing surfaces"""
+
     def __init__(self, name):
         super().__init__('ArrayMesh', name)
         self._mat_to_surf_mapping = dict()
@@ -131,8 +214,9 @@ class ArrayMeshResource(InternalResource):
         self._mat_to_surf_mapping[material_index] = surface_id
 
 
-class MeshResourceExporter:
+class ArrayMeshResourceExporter:
     """Export a mesh resource from a blender mesh object"""
+
     def __init__(self, mesh_object):
         # blender mesh object
         self.object = mesh_object
@@ -141,82 +225,50 @@ class MeshResourceExporter:
         self.has_tangents = False
         self.vgroup_to_bone_mapping = dict()
 
-    def init_mesh_bones_data(self, skeleton_node):
+    def init_mesh_bones_data(self, armature_obj, export_settings):
         """Find the mapping relation between vertex groups
         and bone id"""
-        for bone_name, bone_info in skeleton_node.bones.items():
-            group = self.object.vertex_groups.get(bone_name)
-            if group is not None:
-                self.vgroup_to_bone_mapping[group.index] = bone_info.id
+        if armature_obj is None:
+            return
+        export_bones = []
+        for bone in armature_obj.data.bones:
+            if armature.should_export(export_settings, armature_obj, bone):
+                export_bones.append(bone)
+        for bone_id, bone in enumerate(export_bones):
+            if armature.should_export(export_settings, armature_obj, bone):
+                group = self.object.vertex_groups.get(bone.name)
+                if group is not None:
+                    self.vgroup_to_bone_mapping[group.index] = bone_id
 
     def export_mesh(self, escn_file, export_settings):
-        """Saves a mesh into the escn file """
-        # Check if it exists so we don't bother to export it twice
-        mesh = self.object.data
-        mesh_id = escn_file.get_internal_resource(mesh)
-
+        """Saves a mesh into the escn file"""
+        mesh_converter = MeshConverter(self.object, export_settings)
+        key = MeshResourceKey('ArrayMesh', self.object, export_settings)
+        # Check if mesh resource exists so we don't bother to export it twice,
+        mesh_id = escn_file.get_internal_resource(key)
         if mesh_id is not None:
             return mesh_id
 
-        self.mesh_resource = ArrayMeshResource(mesh.name)
-
-        self.make_arrays(
-            escn_file,
-            export_settings,
-        )
-
-        mesh_id = escn_file.add_internal_resource(self.mesh_resource, mesh)
-        assert mesh_id is not None
+        mesh = mesh_converter.to_mesh()
+        self.has_tangents = mesh_converter.has_tangents
 
-        return mesh_id
-
-    def make_arrays(self, escn_file, export_settings):
-        """Generates arrays of positions, normals etc"""
-        apply_modifiers = export_settings['use_mesh_modifiers']
+        if mesh is not None and mesh.polygons:
+            self.mesh_resource = ArrayMeshResource(mesh.name)
 
-        # set shape key to basis key which would have index 0
-        self.object.show_only_shape_key = True
-        self.object.active_shape_key_index = 0
+            # Separate by materials into single-material surfaces
+            self.generate_surfaces(
+                escn_file,
+                export_settings,
+                mesh
+            )
 
-        mesh = self.object.to_mesh()
+            mesh_id = escn_file.add_internal_resource(self.mesh_resource, key)
+            assert mesh_id is not None
 
-        self.object.show_only_shape_key = False
+        # free mesh from memory
+        mesh_converter.to_mesh_clear()
 
-        # if the original mesh has an object link material,
-        # the new created mesh would use it as data link material,
-        # seems a bug of Blender,
-        # here is a simple fix, not sure if it is robust enough..
-        for idx in range(len(mesh.materials)):
-            mesh.materials[idx] = self.object.data.materials[idx]
-
-        # Prepare the mesh for export
-        triangulate_mesh(mesh)
-
-        # godot engine supports two uv channels
-        uv_layer_count = min(len(mesh.uv_layers), 2)
-
-        if mesh.uv_layers:
-            self.has_tangents = True
-            try:
-                mesh.calc_tangents()
-            except RuntimeError:
-                # This fails if the mesh is a single vertex (and presumably an
-                # edge). Since this won't be rendered by visualserver (the only
-                # user of the tangents), we'll just disable tangents and hope
-                # for the best....
-                self.has_tangents = False
-        else:
-            mesh.calc_normals_split()
-            self.has_tangents = False
-
-        # Separate by materials into single-material surfaces
-        self.generate_surfaces(
-            escn_file,
-            export_settings,
-            mesh
-        )
-
-        bpy.data.meshes.remove(mesh)
+        return mesh_id
 
     @staticmethod
     def validate_morph_mesh_modifiers(mesh_object):
@@ -249,44 +301,17 @@ class MeshResourceExporter:
         )
         self.mesh_resource["blend_shape/mode"] = 0
 
-        # toggle shapekey uncompatible modifiers to false
-        modifier_config_cache = list()
-        if export_settings['use_mesh_modifiers']:
-            if not self.validate_morph_mesh_modifiers(
-                    self.object):
-                logging.warning(
-                    "Mesh object '%s' has modifiers "
-                    "incompatible with shape key",
-                    self.object.name
-                )
-
-            for modifier in self.object.modifiers:
-                modifier_config_cache.append(modifier.show_viewport)
-                modifier.show_viewport = False
-
-        # turn on shape key mode
-        self.object.show_only_shape_key = True
-        blender_shape_keys = self.object.data.shape_keys
-        for index, shape_key in enumerate(blender_shape_keys.key_blocks):
-            if shape_key == blender_shape_keys.reference_key:
+        shape_keys = self.object.data.shape_keys
+        for index, shape_key in enumerate(shape_keys.key_blocks):
+            if shape_key == shape_keys.reference_key:
                 continue
 
             self.mesh_resource["blend_shape/names"].append(
                 '"{}"'.format(shape_key.name)
             )
 
-            self.object.active_shape_key_index = index
-
-            bpy.context.view_layer.depsgraph.update()
-            shape_key_mesh = self.object.evaluated_get(
-                bpy.context.view_layer.depsgraph).to_mesh()
-
-            triangulate_mesh(shape_key_mesh)
-
-            if self.has_tangents:
-                shape_key_mesh.calc_tangents()
-            else:
-                shape_key_mesh.calc_normals_split()
+            mesh_converter = MeshConverter(self.object, export_settings)
+            shape_key_mesh = mesh_converter.to_mesh(index)
 
             surfaces_morph_data = self.intialize_surfaces_morph_data(surfaces)
 
@@ -314,14 +339,7 @@ class MeshResourceExporter:
             for surf_index, surf in enumerate(surfaces):
                 surf.morph_arrays.append(surfaces_morph_data[surf_index])
 
-            bpy.data.meshes.remove(shape_key_mesh)
-
-        # turn off shape key mode
-        self.object.show_only_shape_key = False
-        # revert modifiers
-        if export_settings['use_mesh_modifiers']:
-            for index, modifier in enumerate(self.object.modifiers):
-                modifier.show_render = modifier_config_cache[index]
+            mesh_converter.to_mesh_clear()
 
     def generate_surfaces(self, escn_file, export_settings, mesh):
         """Splits up the mesh into surfaces with a single material each.
@@ -384,7 +402,7 @@ class MeshResourceExporter:
                 surface.vertex_data.indices.append(vertex_indices)
 
         if (export_settings['use_export_shape_key'] and
-                self.object.data.shape_keys):
+                has_shape_keys(self.object.data)):
             self.export_morphs(export_settings, surfaces)
 
         has_bone = bool(self.vgroup_to_bone_mapping)
@@ -448,7 +466,7 @@ class VerticesArrays:
         uv_layer_count = len(self.vertices[0].uv)
         if uv_index >= uv_layer_count:
             # If lacking 2 UV layers, mark them as null
-            return Array("null, ; No UV"+str(uv_index+1), "", "")
+            return Array("null, ; No UV%d" % (uv_index+1), "", "")
 
         uv_vals = Array("Vector2Array(")
         for vert in self.vertices:
@@ -656,3 +674,68 @@ class Vertex:
         self.uv = []
         self.bones = []
         self.weights = []
+
+
+class MeshConverter:
+    """MeshConverter evaulates and converts objects to meshes, triangulates
+    and calculates tangents"""
+
+    def __init__(self, obj, export_settings):
+        self.object = obj
+        self.eval_object = None
+        self.use_mesh_modifiers = export_settings["use_mesh_modifiers"]
+        self.use_export_shape_key = export_settings['use_export_shape_key']
+        self.has_tangents = False
+
+    def to_mesh(self, shape_key_index=0, calculate_tangents=True):
+        """Evaluates object & converts to final mesh, ready for export.
+        The mesh is only temporary, call to_mesh_clear() afterwards."""
+        # set shape key to basis key which would have index 0
+        orig_shape_key_index = self.object.active_shape_key_index
+        self.object.show_only_shape_key = True
+        self.object.active_shape_key_index = shape_key_index
+
+        self.eval_object = self.object
+
+        modifier_config_cache = None
+        if not self.use_mesh_modifiers:
+            modifier_config_cache = record_modifier_config(self.object)
+            for mod in self.object.modifiers:
+                mod.show_viewport = False
+
+        depsgraph = bpy.context.view_layer.depsgraph
+        depsgraph.update()
+        self.eval_object = self.object.evaluated_get(depsgraph)
+
+        # These parameters are required for preserving vertex groups.
+        mesh = self.eval_object.to_mesh(
+            preserve_all_data_layers=True, depsgraph=depsgraph)
+
+        if not self.use_mesh_modifiers:
+            restore_modifier_config(self.object, modifier_config_cache)
+
+        self.has_tangents = False
+
+        # mesh result can be none if the source geometry has no faces, so we
+        # need to consider this if we want a robust exporter.
+        if mesh is not None:
+            triangulate_mesh(mesh)
+
+            self.has_tangents = mesh.uv_layers and mesh.polygons
+            if calculate_tangents:
+                if self.has_tangents:
+                    mesh.calc_tangents()
+                else:
+                    mesh.calc_normals_split()
+
+        self.object.show_only_shape_key = False
+        self.object.active_shape_key_index = orig_shape_key_index
+
+        return mesh
+
+    def to_mesh_clear(self):
+        """Clears the temporary generated mesh from memory"""
+        if self.object is None:
+            return
+        self.eval_object.to_mesh_clear()
+        self.object = self.eval_object = None

+ 31 - 64
io_scene_godot/converters/physics.py

@@ -5,9 +5,7 @@ physics owns the object.
 """
 
 import logging
-import bpy
 import mathutils
-import bmesh
 from ..structures import NodeTemplate, InternalResource, Array, _AXIS_CORRECT
 
 PHYSICS_TYPES = {'KinematicBody', 'RigidBody', 'StaticBody'}
@@ -89,20 +87,19 @@ def export_collision_shape(escn_file, export_settings, node, parent_gd_node,
         col_shape['height'] = bounds.z - col_shape['radius'] * 2
         shape_id = escn_file.add_internal_resource(col_shape, rbd)
     elif rbd.collision_shape == "CONVEX_HULL":
-        col_shape, shape_id = generate_convex_mesh_array(
+        col_shape, shape_id = generate_mesh_array(
             escn_file, export_settings,
-            node
+            node, convex=True
         )
     elif rbd.collision_shape == "MESH":
-        col_shape, shape_id = generate_triangle_mesh_array(
+        col_shape, shape_id = generate_mesh_array(
             escn_file, export_settings,
-            node
+            node, convex=False
         )
     else:
         logging.warning("Unable to export physics shape for %s", node.name)
 
-    if shape_id is not None:
-
+    if shape_id is not None and col_shape is not None:
         if rbd.use_margin or rbd.collision_shape == "MESH":
             col_shape['margin'] = rbd.collision_margin
         col_node['shape'] = "SubResource({})".format(shape_id)
@@ -111,68 +108,38 @@ def export_collision_shape(escn_file, export_settings, node, parent_gd_node,
     return col_node
 
 
-def generate_convex_mesh_array(escn_file, export_settings, node):
-    """Generates godots ConvexPolygonShape from an object"""
-    mesh = node.data
-    key = (mesh, "ConvexCollisionMesh")
-    resource_id = escn_file.get_internal_resource(key)
-    if resource_id is not None:
-        return resource_id
-
-    col_shape = InternalResource("ConvexPolygonShape", mesh.name)
-
-    mesh = node.to_mesh()
-
-    # Triangulate
-    triangulated_mesh = bmesh.new()
-    triangulated_mesh.from_mesh(mesh)
-    # For some reason, generateing the convex hull here causes Godot to crash
-    # bmesh.ops.convex_hull(triangulated_mesh, input=triangulated_mesh.verts)
-    bmesh.ops.triangulate(triangulated_mesh, faces=triangulated_mesh.faces)
-    triangulated_mesh.to_mesh(mesh)
-    triangulated_mesh.free()
-
-    vert_array = list()
-    for poly in mesh.polygons:
-        for vert_id in poly.vertices:
-            vert_array.append(list(mesh.vertices[vert_id].co))
-
-    bpy.data.meshes.remove(mesh)
-
-    col_shape['points'] = Array("PoolVector3Array(", values=vert_array)
-
-    return col_shape, escn_file.add_internal_resource(col_shape, key)
-
-
-def generate_triangle_mesh_array(escn_file, export_settings, node):
-    """Generates godots ConcavePolygonShape from an object"""
-    mesh = node.data
-    key = (mesh, "TriangleCollisionMesh")
+def generate_mesh_array(escn_file, export_settings, node, convex=False):
+    """Generates godots PolygonShape from an object"""
+    from .mesh import (MeshConverter, MeshResourceKey)
+    mesh_converter = MeshConverter(node, export_settings)
+    if convex:
+        key = MeshResourceKey("ConvexPolygonShape", node, export_settings)
+    else:
+        key = MeshResourceKey("ConcavePolygonShape", node, export_settings)
     resource_id = escn_file.get_internal_resource(key)
     if resource_id is not None:
         return resource_id
 
-    col_shape = InternalResource("ConcavePolygonShape", mesh.name)
-
-    mesh = node.to_mesh()
-
-    # Triangulate
-    triangulated_mesh = bmesh.new()
-    triangulated_mesh.from_mesh(mesh)
-    bmesh.ops.triangulate(triangulated_mesh, faces=triangulated_mesh.faces)
-    triangulated_mesh.to_mesh(mesh)
-    triangulated_mesh.free()
-
-    vert_array = list()
-    for poly in mesh.polygons:
-        for vert_id in poly.vertices:
-            vert_array.append(list(mesh.vertices[vert_id].co))
-
-    bpy.data.meshes.remove(mesh)
+    col_shape = None
+    shape_id = None
+    mesh = mesh_converter.to_mesh(calculate_tangents=False)
+    if mesh is not None and mesh.polygons:
+        vert_array = list()
+        for poly in mesh.polygons:
+            for vert_id in poly.vertices:
+                vert_array.append(list(mesh.vertices[vert_id].co))
+
+        if convex:
+            col_shape = InternalResource("ConvexPolygonShape", mesh.name)
+            col_shape['points'] = Array("PoolVector3Array(", values=vert_array)
+        else:
+            col_shape = InternalResource("ConcavePolygonShape", mesh.name)
+            col_shape['data'] = Array("PoolVector3Array(", values=vert_array)
+        shape_id = escn_file.add_internal_resource(col_shape, key)
 
-    col_shape['data'] = Array("PoolVector3Array(", values=vert_array)
+    mesh_converter.to_mesh_clear()
 
-    return col_shape, escn_file.add_internal_resource(col_shape, key)
+    return col_shape, shape_id
 
 
 def export_physics_controller(escn_file, export_settings, node,

+ 39 - 15
io_scene_godot/export_godot.py

@@ -28,12 +28,11 @@ import os
 import collections
 import functools
 import logging
-import math
 import bpy
-import mathutils
 
 from . import structures
 from . import converters
+from .structures import (_AXIS_CORRECT, NodePath)
 
 logging.basicConfig(level=logging.INFO, format="[%(levelname)s]: %(message)s")
 
@@ -93,19 +92,17 @@ class GodotExporter:
         bpy.context.view_layer.objects.active = obj
 
         # Figure out what function will perform the export of this object
-        if (obj.type in converters.BLENDER_TYPE_TO_EXPORTER and
-                obj in self.exporting_objects):
+        if obj.type not in converters.BLENDER_TYPE_TO_EXPORTER:
+            logging.warning(
+                "Unknown object type. Treating as empty: %s", obj.name
+            )
+        elif obj in self.exporting_objects:
             exporter = converters.BLENDER_TYPE_TO_EXPORTER[obj.type]
         else:
-            if obj not in self.exporting_objects:
-                logging.warning(
-                    "Object is parent of exported objects. "
-                    "Treating as empty: %s", obj.name
-                )
-            else:
-                logging.warning(
-                    "Unknown object type. Treating as empty: %s", obj.name
-                )
+            logging.warning(
+                "Object is parent of exported objects. "
+                "Treating as empty: %s", obj.name
+            )
             exporter = converters.BLENDER_TYPE_TO_EXPORTER["EMPTY"]
 
         is_bone_attachment = False
@@ -124,6 +121,8 @@ class GodotExporter:
         exported_node = exporter(self.escn_file, self.config, obj,
                                  parent_gd_node)
 
+        self.bl_object_gd_node_map[obj] = exported_node
+
         if is_bone_attachment:
             for child in parent_gd_node.children:
                 child['transform'] = structures.fix_bone_attachment_transform(
@@ -136,7 +135,7 @@ class GodotExporter:
         if (exported_node.parent is not None and
                 exported_node.parent.get_type() == 'CollisionShape'):
             exported_node['transform'] = (
-                mathutils.Matrix.Rotation(math.radians(90), 4, 'X') @
+                _AXIS_CORRECT.inverted() @
                 exported_node['transform'])
 
         # if the blender node is exported and it has animation data
@@ -169,18 +168,23 @@ class GodotExporter:
         if self.config["use_export_selected"] and not obj.select_get():
             return False
 
-        self.exporting_objects.add(obj)
         return True
 
     def export_scene(self):
         """Decide what objects to export, and export them!"""
         logging.info("Exporting scene: %s", self.scene.name)
 
+        in_edit_mode = False
+        if bpy.context.object and bpy.context.object.mode == "EDIT":
+            in_edit_mode = True
+            bpy.ops.object.editmode_toggle()
+
         # Decide what objects to export
         for obj in self.scene.objects:
             if obj in self.exporting_objects:
                 continue
             if self.should_export_object(obj):
+                self.exporting_objects.add(obj)
                 # Ensure parents of current valid object is
                 # going to the exporting recursion
                 tmp = obj
@@ -204,6 +208,18 @@ class GodotExporter:
                 # recursive exporting on root object
                 self.export_object(obj, root_gd_node)
 
+        if "ARMATURE" in self.config['object_types']:
+            for bl_obj in self.bl_object_gd_node_map:
+                for mod in bl_obj.modifiers:
+                    if mod.type == "ARMATURE":
+                        mesh_node = self.bl_object_gd_node_map[bl_obj]
+                        skeleton_node = self.bl_object_gd_node_map[mod.object]
+                        mesh_node['skeleton'] = NodePath(
+                            mesh_node.get_path(), skeleton_node.get_path())
+
+        if in_edit_mode:
+            bpy.ops.object.editmode_toggle()
+
     def load_supported_features(self):
         """According to `project.godot`, determine all new feature supported
         by that godot version"""
@@ -275,6 +291,7 @@ class GodotExporter:
             self.load_supported_features()
 
         self.escn_file = None
+        self.bl_object_gd_node_map = {}
 
     def __enter__(self):
         return self
@@ -288,6 +305,13 @@ def save(operator, context, filepath="", **kwargs):
     exporter_log_handler = ExporterLogHandler(operator)
     logging.getLogger().addHandler(exporter_log_handler)
 
+    object_types = kwargs["object_types"]
+    # GEOMETRY isn't an object type so replace it with all valid geometry based
+    # object types
+    if "GEOMETRY" in object_types:
+        object_types.remove("GEOMETRY")
+        object_types |= {"MESH", "CURVE", "SURFACE", "META", "FONT"}
+
     with GodotExporter(filepath, kwargs, operator) as exp:
         exp.export()
 

+ 13 - 11
io_scene_godot/structures.py

@@ -93,13 +93,13 @@ class ESCNFile:
 
     def to_string(self):
         """Serializes the file ready to dump out to disk"""
-
-        return "{}{}\n{}\n{}\n".format(
+        sections = (
             self.heading.to_string(),
             '\n\n'.join(i.to_string() for i in self.external_resources),
             '\n\n'.join(e.to_string() for e in self.internal_resources),
             '\n\n'.join(n.to_string() for n in self.nodes)
         )
+        return "\n\n".join([s for s in sections if s]) + "\n"
 
 
 class FileEntry(collections.OrderedDict):
@@ -111,6 +111,7 @@ class FileEntry(collections.OrderedDict):
         self.entry_type = entry_type
         self.heading = collections.OrderedDict(heading_dict)
 
+        # NOTE: contents is unused. Remove?
         # This string is copied verbaitum, so can be used for custom writing
         self.contents = ''
 
@@ -132,21 +133,22 @@ class FileEntry(collections.OrderedDict):
     def generate_body_string(self):
         """Convert the contents of the super/internal dict into newline
         separated key=val pairs"""
-        out_str = ''
+        lines = []
         for var in self:
             val = self[var]
             val = to_string(val)
-
-            out_str += '\n{} = {}'.format(var, val)
-        return out_str
+            lines.append('{} = {}'.format(var, val))
+        return "\n".join(lines)
 
     def to_string(self):
         """Serialize this entire entry"""
-        return "{}\n{}{}".format(
-            self.generate_heading_string(),
-            self.generate_body_string(),
-            self.contents
-        )
+        heading = self.generate_heading_string()
+        body = self.generate_body_string()
+        if body and self.contents:
+            return "{}\n\n{}\n{}".format(heading, body, self.contents)
+        if body:
+            return "{}\n\n{}".format(heading, body)
+        return heading
 
 
 class NodeTemplate(FileEntry):

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/action_animation/animation_bone_transform.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/action_animation/animation_loop.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/action_animation/animation_object_transform.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/action_animation/animation_rotation_euler.escn


+ 1 - 1
tests/reference_exports/action_animation/animation_shared_action.escn

@@ -59,8 +59,8 @@ tracks/0/type = "transform"
 tracks/0/path = NodePath(".:")
 tracks/0/interp = 1
 tracks/0/keys = [0.0, 1.0, -0.0829935, -0.0705722, -0.022377, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0416667, 1.0, -0.0829935, -0.0705722, 0.0411448, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0833333, 1.0, -0.0829935, -0.0705722, 0.237523, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.125, 1.0, -0.0829935, -0.0705722, 0.566712, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.166667, 1.0, -0.0829935, -0.0705722, 1.01117, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.208333, 1.0, -0.0829935, -0.0705722, 1.53291, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.25, 1.0, -0.0829935, -0.0705722, 2.08052, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.291667, 1.0, -0.0829935, -0.0705722, 2.60399, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.333333, 1.0, -0.0829935, -0.0705722, 3.06703, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.375, 1.0, -0.0829935, -0.0705722, 3.45022, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.416667, 1.0, -0.0852899, -0.0355096, 3.80904, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.458333, 1.0, -0.092201, 0.0700142, 4.2004, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.5, 1.0, -0.103438, 0.24159, 4.61307, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.541667, 1.0, -0.118136, 0.466003, 5.02871, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.583333, 1.0, -0.134786, 0.720226, 5.42298, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.625, 1.0, -0.151436, 0.974449, 5.76998, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.666667, 1.0, -0.166133, 1.19886, 6.0486, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.708333, 1.0, -0.17737, 1.37044, 6.24686, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.75, 1.0, -0.184282, 1.47596, 6.36227, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.791667, 1.0, -0.186578, 1.51102, 6.39911, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0]
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Empty" type="Spatial" parent="."]
 

+ 5 - 5
tests/reference_exports/action_animation/physics_animation.escn

@@ -3,7 +3,7 @@
 [sub_resource id=1 type="ConvexPolygonShape"]
 
 resource_name = "Cube"
-points = PoolVector3Array(1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 4.09789, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, -1.0, -1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 0.999999, -1.0, 4.09789, 1.0, -1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, 4.09789, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 4.09789, -1.0, 1.0, 4.09789, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789)
+points = PoolVector3Array(1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 4.09789, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, -1.0, -1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 0.999999, -1.0, 4.09789, 1.0, -1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, 4.09789, -1.0, -1.0, -1.0, -1.0, -1.0, 4.09789, -1.0, 1.0, 4.09789, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789)
 
 [sub_resource id=2 type="ArrayMesh"]
 
@@ -27,7 +27,7 @@ surfaces/0 = {
 [sub_resource id=3 type="ConvexPolygonShape"]
 
 resource_name = "Cube003"
-points = PoolVector3Array(1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 4.09789, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, -1.0, -1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 0.999999, -1.0, 4.09789, 1.0, -1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, 4.09789, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 4.09789, -1.0, 1.0, 4.09789, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789)
+points = PoolVector3Array(1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 4.09789, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, 1.0, 0.999999, 4.09789, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789, -1.0, -1.0, 4.09789, 0.999999, -1.0, 4.09789, 1.0, 0.999999, 4.09789, 0.999999, -1.0, 4.09789, 1.0, -1.0, -1.0, 0.999999, -1.0, 4.09789, -1.0, -1.0, 4.09789, -1.0, -1.0, -1.0, -1.0, -1.0, 4.09789, -1.0, 1.0, 4.09789, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 4.09789)
 
 [sub_resource id=4 type="Animation"]
 
@@ -58,8 +58,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="CubePhysics" type="RigidBody" parent="."]
 
@@ -82,7 +82,7 @@ shape = SubResource(1)
 
 mesh = SubResource(2)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="Cube003Collision" type="CollisionShape" parent="CubePhysics"]
 
@@ -98,4 +98,4 @@ anims/Cube.003Action.001 = SubResource(4)
 
 mesh = SubResource(5)
 visible = true
-transform = Transform(1.65289, 0.0, 0.0, 0.0, 1.2479e-07, -1.65289, 0.0, 1.65289, 1.2479e-07, 0.0, 0.0, 0.0)
+transform = Transform(1.65289, 0.0, 0.0, 0.0, -7.22502e-08, -1.65289, 0.0, 1.65289, -7.22502e-08, 0.0, 0.0, 0.0)

+ 1 - 1
tests/reference_exports/action_with_constraint/bone_attachment_ik.escn

@@ -52,8 +52,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Armature" type="Skeleton" parent="."]
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/action_with_constraint/constraint_external_IK.escn


+ 2 - 2
tests/reference_exports/action_with_constraint/constraint_internal_IK.escn

@@ -37,8 +37,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Armature" type="Skeleton" parent="."]
 
@@ -70,7 +70,7 @@ anims/ArmatureAction = SubResource(1)
 
 [node name="Cylinder" type="MeshInstance" parent="Armature"]
 
-skeleton = NodePath("..:")
 mesh = SubResource(2)
 visible = true
 transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.936288, 0.0)
+skeleton = NodePath("..:")

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/action_with_constraint/constraint_with_undeform_bone.escn


+ 2 - 2
tests/reference_exports/action_with_constraint/stashed_constraint.escn

@@ -37,8 +37,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Armature" type="Skeleton" parent="."]
 
@@ -70,7 +70,7 @@ anims/ArmatureAction = SubResource(1)
 
 [node name="Cylinder" type="MeshInstance" parent="Armature"]
 
-skeleton = NodePath("..:")
 mesh = SubResource(2)
 visible = true
 transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.936288, 0.0)
+skeleton = NodePath("..:")

+ 1 - 1
tests/reference_exports/armature/armature_bone_attachment.escn

@@ -18,8 +18,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Armature" type="Skeleton" parent="."]
 

+ 3 - 3
tests/reference_exports/armature/armature_illegal_bone_name.escn

@@ -48,8 +48,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Armature" type="Skeleton" parent="."]
 
@@ -64,7 +64,7 @@ bones/0/bound_children = []
 bones/1/name = "bone"
 bones/1/parent = 0
 bones/1/rest = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0)
-bones/1/pose = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0)
+bones/1/pose = Transform(0.99961, -0.00771234, -0.0268356, 0.00777253, 0.999968, 0.00213956, 0.0268182, -0.0023473, 0.999638, 0.0, 0.0, 0.0)
 bones/1/enabled = true
 bones/1/bound_children = []
 bones/2/name = "bone001"
@@ -91,7 +91,7 @@ transform = Transform(0.430514, 2.1646e-10, 0.0, -1.27329e-11, 0.430514, 0.0, 0.
 
 [node name="Cube" type="MeshInstance" parent="Armature"]
 
-skeleton = NodePath("..:")
 mesh = SubResource(3)
 visible = true
 transform = Transform(0.706204, 0.0, 0.0, 0.0, 2.62841, 0.0, 0.0, 0.0, 0.48724, -0.0546017, 2.43518, 0.0)
+skeleton = NodePath("..:")

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 8 - 0
tests/reference_exports/armature/armature_not_ancester_of_mesh.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/armature/armature_with_mesh.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/armature/armature_with_non_deform_bone.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/armature/armature_with_other_vertex_groups.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/armature/armature_with_physics.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/armature/armature_with_pose.escn


+ 0 - 2
tests/reference_exports/armature/just_armature.escn

@@ -1,9 +1,7 @@
 [gd_scene load_steps=1 format=2]
 
-
 [node type="Spatial" name="Scene"]
 
-
 [node name="Armature" type="Skeleton" parent="."]
 
 bones_in_world_transform = true

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/armature/non-inherit-bone.escn


+ 1 - 1
tests/reference_exports/camera/animation_camera.escn

@@ -70,8 +70,8 @@ tracks/4/keys = {
 	"update":0,
 	"values":[49.1343, 49.1343, 49.1343, 48.7259, 47.5342, 45.7099, 43.5151, 41.2598, 39.2179, 37.5705, 36.3983, 35.7119, 35.4893, 35.5137, 35.5876, 35.7119, 35.8878, 36.1163, 36.3983, 36.7346, 37.1254, 37.5705, 38.0689, 38.619, 39.2179, 39.8614, 40.5443, 41.2598, 41.9998, 42.7551, 43.5151, 44.2688, 45.0043, 45.7099, 46.3738, 46.9853, 47.5342, 48.0119, 48.411, 48.7259, 48.9526, 49.089, 49.1343]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube" type="MeshInstance" parent="."]
 

+ 0 - 2
tests/reference_exports/camera/just_cameras.escn

@@ -1,9 +1,7 @@
 [gd_scene load_steps=1 format=2]
 
-
 [node type="Spatial" name="Scene"]
 
-
 [node name="Camera004" type="Camera" parent="."]
 
 far = 10.0

+ 1 - 1
tests/reference_exports/light/animation_sun.escn

@@ -34,8 +34,8 @@ tracks/0/keys = {
 	"update":0,
 	"values":[1.0, 0.992688, 0.970082, 0.931923, 0.879461, 0.815882, 0.746055, 0.675477, 0.608971, 0.549881, 0.5, 0.452336, 0.399918, 0.34426, 0.287871, 0.234118, 0.186613, 0.14834, 0.121029, 0.105095, 0.1, 0.115518, 0.162222, 0.23816, 0.337483, 0.45, 0.562517, 0.66184, 0.737778, 0.784482, 0.8, 0.8, 0.8]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Plane" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/light/animation_various_lights.escn

@@ -140,8 +140,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="SpotDistanceChange" type="SpotLight" parent="."]
 

+ 1 - 1
tests/reference_exports/light/cycles_lights.escn

@@ -18,8 +18,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="MissingEmission" type="OmniLight" parent="."]
 

+ 1 - 1
tests/reference_exports/light/just_point_lights.escn

@@ -56,8 +56,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Lamp003" type="OmniLight" parent="."]
 

+ 1 - 1
tests/reference_exports/light/just_spot_lights.escn

@@ -56,8 +56,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Lamp007" type="SpotLight" parent="."]
 

+ 2 - 1
tests/reference_exports/material/material_search.escn

@@ -1,4 +1,5 @@
 [gd_scene load_steps=1 format=2]
+
 [ext_resource id=1 path="../../uv_tester_material.tres" type="SpatialMaterial"]
 
 [sub_resource id=1 type="ArrayMesh"]
@@ -20,8 +21,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube" type="MeshInstance" parent="."]
 

+ 2 - 2
tests/reference_exports/material/object_link_material.escn

@@ -55,8 +55,8 @@ albedo_color = Color(0.903545, 0.169508, 0.242857, 1.0)
 
 resource_name = ""
 albedo_color = Color(0.121702, 0.903545, 0.139942, 1.0)
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube000" type="MeshInstance" parent="."]
 
@@ -68,6 +68,6 @@ transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.804941, -0.
 
 mesh = SubResource(3)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, -0.0116182, 0.681681, -0.190806)
 material/1 = SubResource(4)
 material/0 = SubResource(5)
+transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, -0.0116182, 0.681681, -0.190806)

+ 1 - 1
tests/reference_exports/material/simple_materials.escn

@@ -45,8 +45,8 @@ surfaces/1 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/material_cycle/material_anistropy.escn

@@ -313,8 +313,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Point" type="DirectionalLight" parent="."]
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 82 - 34
tests/reference_exports/material_cycle/material_cycle.escn


+ 5 - 5
tests/reference_exports/material_cycle/material_normal.escn

@@ -1,6 +1,6 @@
 [gd_scene load_steps=1 format=2]
-[ext_resource id=1 path="Normal_OGL.png" type="Texture"]
 
+[ext_resource id=1 path="Normal_OGL.png" type="Texture"]
 
 [ext_resource id=2 path="bump.png" type="Texture"]
 
@@ -1105,8 +1105,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="test_normal_tangent" type="MeshInstance" parent="."]
 
@@ -1118,8 +1118,8 @@ transform = Transform(2.17434, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.089, 5.56855
 
 mesh = SubResource(6)
 visible = true
-transform = Transform(1.87169, 0.0, 0.0, 0.0, 1.87169, 0.0, 0.0, 0.0, 1.87169, -7.39736, 6.91874, -7.43003)
 material/0 = SubResource(8)
+transform = Transform(1.87169, 0.0, 0.0, 0.0, 1.87169, 0.0, 0.0, 0.0, 1.87169, -7.39736, 6.91874, -7.43003)
 
 [node name="test_mapping_texture" type="MeshInstance" parent="."]
 
@@ -1131,15 +1131,15 @@ transform = Transform(1.87169, 0.0, 0.0, 0.0, 1.87169, 0.0, 0.0, 0.0, 1.87169, -
 
 mesh = SubResource(6)
 visible = true
-transform = Transform(1.87169, 0.0, 0.0, 0.0, 1.87169, 0.0, 0.0, 0.0, 1.87169, -4.71194, 9.35422, 0.926832)
 material/0 = SubResource(10)
+transform = Transform(1.87169, 0.0, 0.0, 0.0, 1.87169, 0.0, 0.0, 0.0, 1.87169, -4.71194, 9.35422, 0.926832)
 
 [node name="test_mapping_point" type="MeshInstance" parent="."]
 
 mesh = SubResource(6)
 visible = true
-transform = Transform(1.87169, 0.0, 0.0, 0.0, 1.87169, 0.0, 0.0, 0.0, 1.87169, -2.75008, 9.34185, 5.68027)
 material/0 = SubResource(12)
+transform = Transform(1.87169, 0.0, 0.0, 0.0, 1.87169, 0.0, 0.0, 0.0, 1.87169, -2.75008, 9.34185, 5.68027)
 
 [node name="Lamp" type="DirectionalLight" parent="."]
 

+ 2 - 1
tests/reference_exports/material_cycle/material_unpack_texture.escn

@@ -1,4 +1,5 @@
 [gd_scene load_steps=1 format=2]
+
 [ext_resource id=1 path="brick_4_diff_1k.jpg" type="Texture"]
 
 [sub_resource id=1 type="Shader"]
@@ -96,8 +97,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/mesh/just_mesh.escn

@@ -56,8 +56,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cylinder002" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/mesh/parented_meshes.escn

@@ -18,8 +18,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Suzanne006" type="MeshInstance" parent="."]
 

+ 8 - 8
tests/reference_exports/mesh/physics.escn

@@ -155,8 +155,8 @@ surfaces/0 = {
 
 resource_name = "Sphere003Collision"
 radius = 0.5
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube002Physics" type="StaticBody" parent="."]
 
@@ -175,7 +175,7 @@ shape = SubResource(1)
 
 mesh = SubResource(2)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="Cube001Physics" type="StaticBody" parent="."]
 
@@ -211,7 +211,7 @@ shape = SubResource(4)
 
 mesh = SubResource(5)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="PlanePhysics" type="StaticBody" parent="."]
 
@@ -230,7 +230,7 @@ shape = SubResource(6)
 
 mesh = SubResource(7)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="CubePhysics" type="RigidBody" parent="."]
 
@@ -253,7 +253,7 @@ shape = SubResource(8)
 
 mesh = SubResource(9)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="SpherePhysics" type="RigidBody" parent="."]
 
@@ -276,7 +276,7 @@ shape = SubResource(10)
 
 mesh = SubResource(11)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="Sphere002Collision" type="CollisionShape" parent="SpherePhysics"]
 
@@ -287,7 +287,7 @@ shape = SubResource(12)
 
 mesh = SubResource(13)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="Sphere003Physics" type="RigidBody" parent="."]
 
@@ -310,7 +310,7 @@ shape = SubResource(14)
 
 mesh = SubResource(13)
 visible = true
-transform = Transform(1.0, 0.0, 0.0, 0.0, 7.54979e-08, -1.0, 0.0, 1.0, 7.54979e-08, 0.0, 0.0, 0.0)
+transform = Transform(1.0, 0.0, 0.0, 0.0, -4.37114e-08, -1.0, 0.0, 1.0, -4.37114e-08, 0.0, 0.0, 0.0)
 
 [node name="Lamp" type="OmniLight" parent="."]
 

+ 0 - 12
tests/reference_exports/mesh/single_edge_and_vertex.escn

@@ -1,23 +1,11 @@
 [gd_scene load_steps=1 format=2]
 
-[sub_resource id=1 type="ArrayMesh"]
-
-resource_name = "Cube001"
-
-[sub_resource id=2 type="ArrayMesh"]
-
-resource_name = "Cube"
 [node type="Spatial" name="Scene"]
 
-
 [node name="SingleEdge" type="MeshInstance" parent="."]
 
-mesh = SubResource(1)
-visible = true
 transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0)
 
 [node name="SingleVert" type="MeshInstance" parent="."]
 
-mesh = SubResource(2)
-visible = true
 transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0)

+ 1 - 1
tests/reference_exports/mesh/tangent_test.escn

@@ -18,8 +18,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Plane" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/mesh/uv_testing.escn

@@ -75,8 +75,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube001" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/mesh/vertex_color.escn

@@ -18,8 +18,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Plane" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/misc/duplicate_name.escn

@@ -56,8 +56,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube" type="MeshInstance" parent="."]
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/misc/invisible_objects.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/nla_animation/animation_multi_strip.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/nla_animation/animation_with_empty_strip.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/nla_animation/nla_with_active_action.escn


+ 1 - 1
tests/reference_exports/nla_animation/nla_with_no_active_action.escn

@@ -66,8 +66,8 @@ tracks/1/keys = {
 	"update":0,
 	"values":[0.0, 0.119438, 0.353741, 0.611825, 0.891865, 1.0, 0.935595, 0.756443, 0.564626, 0.341587, 0.095626, 0.0]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Suzanne" type="MeshInstance" parent="."]
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/nla_animation/nla_with_stashed_action.escn


+ 1 - 1
tests/reference_exports/scene_animation/animation_parented_objects.escn

@@ -52,8 +52,8 @@ surfaces/0 = {
 	],
 	"morph_arrays":[]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Cube" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/shape_key/animation_shapekey.escn

@@ -46,8 +46,8 @@ tracks/0/keys = {
 	"update":0,
 	"values":[0.0, 0.00261531, 0.0105104, 0.0237313, 0.0422801, 0.0661052, 0.095091, 0.129048, 0.167705, 0.2107, 0.257579, 0.307793, 0.360707, 0.415611, 0.471734, 0.528267, 0.584389, 0.639293, 0.692207, 0.742421, 0.7893, 0.832295, 0.870952, 0.904909, 0.933895, 0.95772, 0.976269, 0.98949, 0.997385, 1.0, 0.997557, 0.990181, 0.977831, 0.9605, 0.938228, 0.911111, 0.879307, 0.843044, 0.802629, 0.758447, 0.710968, 0.660738, 0.608376, 0.554558, 0.5, 0.445442, 0.391624, 0.339262, 0.289032, 0.241553, 0.197372, 0.156956, 0.120693, 0.088889, 0.0617719, 0.0395004, 0.0221692, 0.00981867, 0.00244331, 0.0]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Suzanne002" type="MeshInstance" parent="."]
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/shape_key/animation_shapekey_with_transform.escn


+ 1 - 1
tests/reference_exports/shape_key/just_shapekey.escn

@@ -30,8 +30,8 @@ surfaces/0 = {
 		null, ; Morph Object
 	]]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Suzanne002" type="MeshInstance" parent="."]
 

+ 1 - 1
tests/reference_exports/shape_key/shapekey_with_multi_surface.escn

@@ -67,8 +67,8 @@ surfaces/1 = {
 		null, ; Morph Object
 	]]
 }
-[node type="Spatial" name="Scene"]
 
+[node type="Spatial" name="Scene"]
 
 [node name="Suzanne" type="MeshInstance" parent="."]
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
tests/reference_exports/shape_key/shapekey_with_pose.escn


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 10 - 0
tests/reference_exports/shape_key/shapekey_with_subdivision.escn


BIN
tests/test_scenes/armature/armature_not_ancester_of_mesh.blend


BIN
tests/test_scenes/shape_key/shapekey_with_subdivision.blend


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio