浏览代码

Squashed commit, multiple bug fixes + improvements.

----------------

Fixed pylint errors.

Removed commented code.
Formatted code.

Update test scene

Include Godot Resource Name in to MeshResourceKey

Same mesh may be used both as CollisionShape and ArrayMesh

Simplify MeshResourceKey construction

The previously implementation is kind of risk because of the recursive
calling, here introduce a simpler one with some fault allowance.

Minor changes and fixes to last commit.

- Added functionality to export all object types.
  - Replaced 'MESH' in object_types with more general 'GEOMETRY' option, allowing for all the following types to be converted: MESH, CURVE, SURFACE, META, FONT. These are all treated similarly using mesh.py. Beziers and Surfaces shapekeys tested and working.
- Moved + rejigged Mesh/Skeleton path resolving to end of export_scene() in export_godot.py for better functionality.
- Fixed bugs when attempting to export empty geometry.
- Added MeshResourceKey to mesh.py, this produces an identifier key for meshes with modifiers. Now, if more than one object use the exact same object data and modifiers then the exporter refers to a single resource.
- Reverted ArrayMeshResource resource_name values to object.data.name.
- Fixed some newline spacing inconsistencies that happened during serialization, so it now matches the same spacing that Godot uses.

Fully updated to work with latest Blender 2.8 build (March 31st 2019)
- Fixed use_mesh_modifiers when converting meshes.
- Added MeshConverter class to assist in all object to mesh conversions.
- Implemented new mesh naming convention to prevent clashing resource names.
- Commented out modifier disabling during ArrayMeshResourceExporter's export_morphs(), based on several tests that suggested it was not necessary.
- Fixed default_settings in __init__.py.
- Renamed MeshResourceExporter to ArrayMeshResourceExporter for consistency.

Implemented property "use_mesh_modifiers" prior to which was no longer working and had no effect on the resulting mesh.

Updated all props to use Python's type annotations, fixes start-up warning.

Updated all references of Object.to_mesh() to work with latest changes to Blender 2.8 API.
Tom Wilson 6 年之前
父节点
当前提交
b534efb0aa
共有 65 个文件被更改,包括 485 次插入369 次删除
  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. 二进制
      tests/test_scenes/armature/armature_not_ancester_of_mesh.blend
  65. 二进制
      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"}
     bl_options = {"PRESET"}
 
 
     filename_ext = ".escn"
     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
     # List of operator properties, the attributes will be assigned
     # to the class instance from the operator settings before calling
     # to the class instance from the operator settings before calling
-    object_types = EnumProperty(
+    object_types: EnumProperty(
         name="Object Types",
         name="Object Types",
         options={"ENUM_FLAG"},
         options={"ENUM_FLAG"},
         items=(
         items=(
@@ -58,41 +58,39 @@ class ExportGodot(bpy.types.Operator, ExportHelper):
             ("CAMERA", "Camera", ""),
             ("CAMERA", "Camera", ""),
             ("LIGHT", "Light", ""),
             ("LIGHT", "Light", ""),
             ("ARMATURE", "Armature", ""),
             ("ARMATURE", "Armature", ""),
-            ("MESH", "Mesh", ""),
-            # ("CURVE", "Curve", ""),
+            ("GEOMETRY", "Geometry", "")
         ),
         ),
         default={
         default={
             "EMPTY",
             "EMPTY",
             "CAMERA",
             "CAMERA",
             "LIGHT",
             "LIGHT",
             "ARMATURE",
             "ARMATURE",
-            "MESH",
-            # "CURVE"
+            "GEOMETRY"
         },
         },
     )
     )
 
 
-    use_visible_objects = BoolProperty(
+    use_visible_objects: BoolProperty(
         name="Only Visible Object",
         name="Only Visible Object",
         description="Export only objects which are in the current view layer "
         description="Export only objects which are in the current view layer "
                     "and are visible.",
                     "and are visible.",
         default=True,
         default=True,
     )
     )
-    use_export_selected = BoolProperty(
+    use_export_selected: BoolProperty(
         name="Only Selected Objects",
         name="Only Selected Objects",
         description="Export only selected objects",
         description="Export only selected objects",
         default=False,
         default=False,
     )
     )
-    use_mesh_modifiers = BoolProperty(
+    use_mesh_modifiers: BoolProperty(
         name="Apply Modifiers",
         name="Apply Modifiers",
         description="Apply modifiers to mesh objects (on a copy!).",
         description="Apply modifiers to mesh objects (on a copy!).",
         default=True,
         default=True,
     )
     )
-    use_exclude_ctrl_bone = BoolProperty(
+    use_exclude_ctrl_bone: BoolProperty(
         name="Exclude Control Bones",
         name="Exclude Control Bones",
         description="Do not export control bones (bone.use_deform = false)",
         description="Do not export control bones (bone.use_deform = false)",
         default=True,
         default=True,
     )
     )
-    use_export_animation = BoolProperty(
+    use_export_animation: BoolProperty(
         name="Export Animation",
         name="Export Animation",
         description="Export all the animation actions (include actions "
         description="Export all the animation actions (include actions "
                     "in nla_tracks), note that by default blender animation "
                     "in nla_tracks), note that by default blender animation "
@@ -100,40 +98,35 @@ class ExportGodot(bpy.types.Operator, ExportHelper):
                     "own AnimationPlayer hold their actions",
                     "own AnimationPlayer hold their actions",
         default=True,
         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",
         description="Export all the material associated with mesh surfaces",
         default=True,
         default=True,
     )
     )
-    use_export_shape_key = BoolProperty(
+    use_export_shape_key: BoolProperty(
         name="Export Shape Key",
         name="Export Shape Key",
         description="Export all the shape keys in mesh objects",
         description="Export all the shape keys in mesh objects",
         default=True,
         default=True,
     )
     )
-    use_stashed_action = BoolProperty(
+    use_stashed_action: BoolProperty(
         name="Export Stashed Actions",
         name="Export Stashed Actions",
         description="Export stashed actions and muted nla_strip as separate "
         description="Export stashed actions and muted nla_strip as separate "
                     "animation and place into AnimationPlayer",
                     "animation and place into AnimationPlayer",
         default=True,
         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",
         name="Use Beta Features",
         description="Export using new features coming in Godot beta versions",
         description="Export using new features coming in Godot beta versions",
         default=True,
         default=True,
     )
     )
-    generate_external_material = BoolProperty(
+    generate_external_material: BoolProperty(
         name="Generate External Material",
         name="Generate External Material",
         description="If turned on, materials in the exported scene would "
         description="If turned on, materials in the exported scene would "
                     "generate external .material files when imported to "
                     "generate external .material files when imported to "
                     "godot,  thus make it easy for material reusing",
                     "godot,  thus make it easy for material reusing",
         default=False,
         default=False,
     )
     )
-    animation_modes = EnumProperty(
+    animation_modes: EnumProperty(
         name="Animation Modes",
         name="Animation Modes",
         description="Configuration of how blender animation data being "
         description="Configuration of how blender animation data being "
                     "exported to godot AnimationPlayer as well as the "
                     "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",
         name="Material Search Paths",
         description="Search for existing godot materials with names that match"
         description="Search for existing godot materials with names that match"
                     "the blender material names (ie the file <matname>.tres"
                     "the blender material names (ie the file <matname>.tres"
@@ -243,8 +236,8 @@ def export(filename, overrides=None):
     """
     """
 
 
     default_settings = dict()
     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
         # This introspection is not very robust and may break in future blende
         # versions. This is becase for some reason you can't compare against
         # versions. This is becase for some reason you can't compare against
         # bpy.types.Property because. well, they end up not being subclasses
         # 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 .armature import export_armature_node, export_bone_attachment
 from .animation import export_animation_data
 from .animation import export_animation_data
 
 
-
+# TODO: What about Empties which refer to group instances? (in 2.8 Collection
+# Instances)
 BLENDER_TYPE_TO_EXPORTER = {
 BLENDER_TYPE_TO_EXPORTER = {
     "MESH": export_mesh_node,
     "MESH": export_mesh_node,
     "ARMATURE": export_armature_node,
     "ARMATURE": export_armature_node,
     "CAMERA": export_camera_node,
     "CAMERA": export_camera_node,
     "LIGHT": export_light_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
 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
     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:
 class Bone:
     """A Bone has almost same attributes as Godot bones"""
     """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
 import mathutils
 
 
 from .material import export_material
 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 physics
 from . import armature
 from . import armature
 from . import animation
 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(
         parent_gd_node = physics.export_physics_properties(
             escn_file, export_settings, obj, parent_gd_node
             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
         # 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_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_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
     # Transform of rigid mesh is moved up to its collision
     # shapes.
     # 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)
         mesh_node['transform'] = mathutils.Matrix.Identity(4)
+    else:
+        mesh_node['transform'] = obj.matrix_local
 
 
     escn_file.add_node(mesh_node)
     escn_file.add_node(mesh_node)
 
 
-    export_object_link_material(
-        escn_file, export_settings, obj, mesh_node
-    )
-
     # export shape key animation
     # export shape key animation
     if (export_settings['use_export_shape_key'] and
     if (export_settings['use_export_shape_key'] and
-            obj.data.shape_keys is not None):
+            has_shape_keys(obj.data)):
         animation.export_animation_data(
         animation.export_animation_data(
             escn_file, export_settings, mesh_node,
             escn_file, export_settings, mesh_node,
             obj.data.shape_keys, 'shapekey')
             obj.data.shape_keys, 'shapekey')
@@ -87,22 +93,19 @@ def fix_vertex(vtx):
     return mathutils.Vector((vtx.x, vtx.z, -vtx.y))
     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"""
     if does not have one, return None"""
     for modifier in mesh_object.modifiers:
     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
     return None
 
 
 
 
 def export_object_link_material(escn_file, export_settings, mesh_object,
 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,
     """Export object linked material, if multiple object link material,
     only export the first one in the material slots"""
     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):
     for index, slot in enumerate(mesh_object.material_slots):
         if slot.link == 'OBJECT' and slot.material is not None:
         if slot.link == 'OBJECT' and slot.material is not None:
             surface_id = mesh_resource.get_surface_id(index)
             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):
 class ArrayMeshResource(InternalResource):
     """Godot ArrayMesh resource, containing surfaces"""
     """Godot ArrayMesh resource, containing surfaces"""
+
     def __init__(self, name):
     def __init__(self, name):
         super().__init__('ArrayMesh', name)
         super().__init__('ArrayMesh', name)
         self._mat_to_surf_mapping = dict()
         self._mat_to_surf_mapping = dict()
@@ -131,8 +214,9 @@ class ArrayMeshResource(InternalResource):
         self._mat_to_surf_mapping[material_index] = surface_id
         self._mat_to_surf_mapping[material_index] = surface_id
 
 
 
 
-class MeshResourceExporter:
+class ArrayMeshResourceExporter:
     """Export a mesh resource from a blender mesh object"""
     """Export a mesh resource from a blender mesh object"""
+
     def __init__(self, mesh_object):
     def __init__(self, mesh_object):
         # blender mesh object
         # blender mesh object
         self.object = mesh_object
         self.object = mesh_object
@@ -141,82 +225,50 @@ class MeshResourceExporter:
         self.has_tangents = False
         self.has_tangents = False
         self.vgroup_to_bone_mapping = dict()
         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
         """Find the mapping relation between vertex groups
         and bone id"""
         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):
     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:
         if mesh_id is not None:
             return mesh_id
             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
     @staticmethod
     def validate_morph_mesh_modifiers(mesh_object):
     def validate_morph_mesh_modifiers(mesh_object):
@@ -249,44 +301,17 @@ class MeshResourceExporter:
         )
         )
         self.mesh_resource["blend_shape/mode"] = 0
         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
                 continue
 
 
             self.mesh_resource["blend_shape/names"].append(
             self.mesh_resource["blend_shape/names"].append(
                 '"{}"'.format(shape_key.name)
                 '"{}"'.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)
             surfaces_morph_data = self.intialize_surfaces_morph_data(surfaces)
 
 
@@ -314,14 +339,7 @@ class MeshResourceExporter:
             for surf_index, surf in enumerate(surfaces):
             for surf_index, surf in enumerate(surfaces):
                 surf.morph_arrays.append(surfaces_morph_data[surf_index])
                 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):
     def generate_surfaces(self, escn_file, export_settings, mesh):
         """Splits up the mesh into surfaces with a single material each.
         """Splits up the mesh into surfaces with a single material each.
@@ -384,7 +402,7 @@ class MeshResourceExporter:
                 surface.vertex_data.indices.append(vertex_indices)
                 surface.vertex_data.indices.append(vertex_indices)
 
 
         if (export_settings['use_export_shape_key'] and
         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)
             self.export_morphs(export_settings, surfaces)
 
 
         has_bone = bool(self.vgroup_to_bone_mapping)
         has_bone = bool(self.vgroup_to_bone_mapping)
@@ -448,7 +466,7 @@ class VerticesArrays:
         uv_layer_count = len(self.vertices[0].uv)
         uv_layer_count = len(self.vertices[0].uv)
         if uv_index >= uv_layer_count:
         if uv_index >= uv_layer_count:
             # If lacking 2 UV layers, mark them as null
             # 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(")
         uv_vals = Array("Vector2Array(")
         for vert in self.vertices:
         for vert in self.vertices:
@@ -656,3 +674,68 @@ class Vertex:
         self.uv = []
         self.uv = []
         self.bones = []
         self.bones = []
         self.weights = []
         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 logging
-import bpy
 import mathutils
 import mathutils
-import bmesh
 from ..structures import NodeTemplate, InternalResource, Array, _AXIS_CORRECT
 from ..structures import NodeTemplate, InternalResource, Array, _AXIS_CORRECT
 
 
 PHYSICS_TYPES = {'KinematicBody', 'RigidBody', 'StaticBody'}
 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
         col_shape['height'] = bounds.z - col_shape['radius'] * 2
         shape_id = escn_file.add_internal_resource(col_shape, rbd)
         shape_id = escn_file.add_internal_resource(col_shape, rbd)
     elif rbd.collision_shape == "CONVEX_HULL":
     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,
             escn_file, export_settings,
-            node
+            node, convex=True
         )
         )
     elif rbd.collision_shape == "MESH":
     elif rbd.collision_shape == "MESH":
-        col_shape, shape_id = generate_triangle_mesh_array(
+        col_shape, shape_id = generate_mesh_array(
             escn_file, export_settings,
             escn_file, export_settings,
-            node
+            node, convex=False
         )
         )
     else:
     else:
         logging.warning("Unable to export physics shape for %s", node.name)
         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":
         if rbd.use_margin or rbd.collision_shape == "MESH":
             col_shape['margin'] = rbd.collision_margin
             col_shape['margin'] = rbd.collision_margin
         col_node['shape'] = "SubResource({})".format(shape_id)
         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
     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)
     resource_id = escn_file.get_internal_resource(key)
     if resource_id is not None:
     if resource_id is not None:
         return resource_id
         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,
 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 collections
 import functools
 import functools
 import logging
 import logging
-import math
 import bpy
 import bpy
-import mathutils
 
 
 from . import structures
 from . import structures
 from . import converters
 from . import converters
+from .structures import (_AXIS_CORRECT, NodePath)
 
 
 logging.basicConfig(level=logging.INFO, format="[%(levelname)s]: %(message)s")
 logging.basicConfig(level=logging.INFO, format="[%(levelname)s]: %(message)s")
 
 
@@ -93,19 +92,17 @@ class GodotExporter:
         bpy.context.view_layer.objects.active = obj
         bpy.context.view_layer.objects.active = obj
 
 
         # Figure out what function will perform the export of this object
         # 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]
             exporter = converters.BLENDER_TYPE_TO_EXPORTER[obj.type]
         else:
         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"]
             exporter = converters.BLENDER_TYPE_TO_EXPORTER["EMPTY"]
 
 
         is_bone_attachment = False
         is_bone_attachment = False
@@ -124,6 +121,8 @@ class GodotExporter:
         exported_node = exporter(self.escn_file, self.config, obj,
         exported_node = exporter(self.escn_file, self.config, obj,
                                  parent_gd_node)
                                  parent_gd_node)
 
 
+        self.bl_object_gd_node_map[obj] = exported_node
+
         if is_bone_attachment:
         if is_bone_attachment:
             for child in parent_gd_node.children:
             for child in parent_gd_node.children:
                 child['transform'] = structures.fix_bone_attachment_transform(
                 child['transform'] = structures.fix_bone_attachment_transform(
@@ -136,7 +135,7 @@ class GodotExporter:
         if (exported_node.parent is not None and
         if (exported_node.parent is not None and
                 exported_node.parent.get_type() == 'CollisionShape'):
                 exported_node.parent.get_type() == 'CollisionShape'):
             exported_node['transform'] = (
             exported_node['transform'] = (
-                mathutils.Matrix.Rotation(math.radians(90), 4, 'X') @
+                _AXIS_CORRECT.inverted() @
                 exported_node['transform'])
                 exported_node['transform'])
 
 
         # if the blender node is exported and it has animation data
         # 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():
         if self.config["use_export_selected"] and not obj.select_get():
             return False
             return False
 
 
-        self.exporting_objects.add(obj)
         return True
         return True
 
 
     def export_scene(self):
     def export_scene(self):
         """Decide what objects to export, and export them!"""
         """Decide what objects to export, and export them!"""
         logging.info("Exporting scene: %s", self.scene.name)
         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
         # Decide what objects to export
         for obj in self.scene.objects:
         for obj in self.scene.objects:
             if obj in self.exporting_objects:
             if obj in self.exporting_objects:
                 continue
                 continue
             if self.should_export_object(obj):
             if self.should_export_object(obj):
+                self.exporting_objects.add(obj)
                 # Ensure parents of current valid object is
                 # Ensure parents of current valid object is
                 # going to the exporting recursion
                 # going to the exporting recursion
                 tmp = obj
                 tmp = obj
@@ -204,6 +208,18 @@ class GodotExporter:
                 # recursive exporting on root object
                 # recursive exporting on root object
                 self.export_object(obj, root_gd_node)
                 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):
     def load_supported_features(self):
         """According to `project.godot`, determine all new feature supported
         """According to `project.godot`, determine all new feature supported
         by that godot version"""
         by that godot version"""
@@ -275,6 +291,7 @@ class GodotExporter:
             self.load_supported_features()
             self.load_supported_features()
 
 
         self.escn_file = None
         self.escn_file = None
+        self.bl_object_gd_node_map = {}
 
 
     def __enter__(self):
     def __enter__(self):
         return self
         return self
@@ -288,6 +305,13 @@ def save(operator, context, filepath="", **kwargs):
     exporter_log_handler = ExporterLogHandler(operator)
     exporter_log_handler = ExporterLogHandler(operator)
     logging.getLogger().addHandler(exporter_log_handler)
     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:
     with GodotExporter(filepath, kwargs, operator) as exp:
         exp.export()
         exp.export()
 
 

+ 13 - 11
io_scene_godot/structures.py

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

文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/action_animation/animation_bone_transform.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/action_animation/animation_loop.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/action_animation/animation_object_transform.escn


文件差异内容过多而无法显示
+ 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/path = NodePath(".:")
 tracks/0/interp = 1
 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]
 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="."]
 [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"]
 [sub_resource id=1 type="ConvexPolygonShape"]
 
 
 resource_name = "Cube"
 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"]
 [sub_resource id=2 type="ArrayMesh"]
 
 
@@ -27,7 +27,7 @@ surfaces/0 = {
 [sub_resource id=3 type="ConvexPolygonShape"]
 [sub_resource id=3 type="ConvexPolygonShape"]
 
 
 resource_name = "Cube003"
 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"]
 [sub_resource id=4 type="Animation"]
 
 
@@ -58,8 +58,8 @@ surfaces/0 = {
 	],
 	],
 	"morph_arrays":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="CubePhysics" type="RigidBody" parent="."]
 [node name="CubePhysics" type="RigidBody" parent="."]
 
 
@@ -82,7 +82,7 @@ shape = SubResource(1)
 
 
 mesh = SubResource(2)
 mesh = SubResource(2)
 visible = true
 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"]
 [node name="Cube003Collision" type="CollisionShape" parent="CubePhysics"]
 
 
@@ -98,4 +98,4 @@ anims/Cube.003Action.001 = SubResource(4)
 
 
 mesh = SubResource(5)
 mesh = SubResource(5)
 visible = true
 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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Armature" type="Skeleton" parent="."]
 [node name="Armature" type="Skeleton" parent="."]
 
 

文件差异内容过多而无法显示
+ 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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Armature" type="Skeleton" parent="."]
 [node name="Armature" type="Skeleton" parent="."]
 
 
@@ -70,7 +70,7 @@ anims/ArmatureAction = SubResource(1)
 
 
 [node name="Cylinder" type="MeshInstance" parent="Armature"]
 [node name="Cylinder" type="MeshInstance" parent="Armature"]
 
 
-skeleton = NodePath("..:")
 mesh = SubResource(2)
 mesh = SubResource(2)
 visible = true
 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)
 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("..:")

文件差异内容过多而无法显示
+ 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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Armature" type="Skeleton" parent="."]
 [node name="Armature" type="Skeleton" parent="."]
 
 
@@ -70,7 +70,7 @@ anims/ArmatureAction = SubResource(1)
 
 
 [node name="Cylinder" type="MeshInstance" parent="Armature"]
 [node name="Cylinder" type="MeshInstance" parent="Armature"]
 
 
-skeleton = NodePath("..:")
 mesh = SubResource(2)
 mesh = SubResource(2)
 visible = true
 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)
 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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Armature" type="Skeleton" parent="."]
 [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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Armature" type="Skeleton" parent="."]
 [node name="Armature" type="Skeleton" parent="."]
 
 
@@ -64,7 +64,7 @@ bones/0/bound_children = []
 bones/1/name = "bone"
 bones/1/name = "bone"
 bones/1/parent = 0
 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/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/enabled = true
 bones/1/bound_children = []
 bones/1/bound_children = []
 bones/2/name = "bone001"
 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"]
 [node name="Cube" type="MeshInstance" parent="Armature"]
 
 
-skeleton = NodePath("..:")
 mesh = SubResource(3)
 mesh = SubResource(3)
 visible = true
 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)
 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("..:")

文件差异内容过多而无法显示
+ 8 - 0
tests/reference_exports/armature/armature_not_ancester_of_mesh.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/armature/armature_with_mesh.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/armature/armature_with_non_deform_bone.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/armature/armature_with_other_vertex_groups.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/armature/armature_with_physics.escn


文件差异内容过多而无法显示
+ 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]
 [gd_scene load_steps=1 format=2]
 
 
-
 [node type="Spatial" name="Scene"]
 [node type="Spatial" name="Scene"]
 
 
-
 [node name="Armature" type="Skeleton" parent="."]
 [node name="Armature" type="Skeleton" parent="."]
 
 
 bones_in_world_transform = true
 bones_in_world_transform = true

文件差异内容过多而无法显示
+ 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,
 	"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]
 	"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="."]
 [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]
 [gd_scene load_steps=1 format=2]
 
 
-
 [node type="Spatial" name="Scene"]
 [node type="Spatial" name="Scene"]
 
 
-
 [node name="Camera004" type="Camera" parent="."]
 [node name="Camera004" type="Camera" parent="."]
 
 
 far = 10.0
 far = 10.0

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

@@ -34,8 +34,8 @@ tracks/0/keys = {
 	"update":0,
 	"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]
 	"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="."]
 [node name="Plane" type="MeshInstance" parent="."]
 
 

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

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

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

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

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

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

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

@@ -56,8 +56,8 @@ surfaces/0 = {
 	],
 	],
 	"morph_arrays":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Lamp007" type="SpotLight" parent="."]
 [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]
 [gd_scene load_steps=1 format=2]
+
 [ext_resource id=1 path="../../uv_tester_material.tres" type="SpatialMaterial"]
 [ext_resource id=1 path="../../uv_tester_material.tres" type="SpatialMaterial"]
 
 
 [sub_resource id=1 type="ArrayMesh"]
 [sub_resource id=1 type="ArrayMesh"]
@@ -20,8 +21,8 @@ surfaces/0 = {
 	],
 	],
 	"morph_arrays":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Cube" type="MeshInstance" parent="."]
 [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 = ""
 resource_name = ""
 albedo_color = Color(0.121702, 0.903545, 0.139942, 1.0)
 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="."]
 [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)
 mesh = SubResource(3)
 visible = true
 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/1 = SubResource(4)
 material/0 = SubResource(5)
 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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Cube" type="MeshInstance" parent="."]
 [node name="Cube" type="MeshInstance" parent="."]
 
 

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

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

文件差异内容过多而无法显示
+ 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]
 [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"]
 [ext_resource id=2 path="bump.png" type="Texture"]
 
 
@@ -1105,8 +1105,8 @@ surfaces/0 = {
 	],
 	],
 	"morph_arrays":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="test_normal_tangent" type="MeshInstance" parent="."]
 [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)
 mesh = SubResource(6)
 visible = true
 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)
 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="."]
 [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)
 mesh = SubResource(6)
 visible = true
 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)
 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="."]
 [node name="test_mapping_point" type="MeshInstance" parent="."]
 
 
 mesh = SubResource(6)
 mesh = SubResource(6)
 visible = true
 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)
 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="."]
 [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]
 [gd_scene load_steps=1 format=2]
+
 [ext_resource id=1 path="brick_4_diff_1k.jpg" type="Texture"]
 [ext_resource id=1 path="brick_4_diff_1k.jpg" type="Texture"]
 
 
 [sub_resource id=1 type="Shader"]
 [sub_resource id=1 type="Shader"]
@@ -96,8 +97,8 @@ surfaces/0 = {
 	],
 	],
 	"morph_arrays":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Cube" type="MeshInstance" parent="."]
 [node name="Cube" type="MeshInstance" parent="."]
 
 

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

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

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

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

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

@@ -155,8 +155,8 @@ surfaces/0 = {
 
 
 resource_name = "Sphere003Collision"
 resource_name = "Sphere003Collision"
 radius = 0.5
 radius = 0.5
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Cube002Physics" type="StaticBody" parent="."]
 [node name="Cube002Physics" type="StaticBody" parent="."]
 
 
@@ -175,7 +175,7 @@ shape = SubResource(1)
 
 
 mesh = SubResource(2)
 mesh = SubResource(2)
 visible = true
 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="."]
 [node name="Cube001Physics" type="StaticBody" parent="."]
 
 
@@ -211,7 +211,7 @@ shape = SubResource(4)
 
 
 mesh = SubResource(5)
 mesh = SubResource(5)
 visible = true
 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="."]
 [node name="PlanePhysics" type="StaticBody" parent="."]
 
 
@@ -230,7 +230,7 @@ shape = SubResource(6)
 
 
 mesh = SubResource(7)
 mesh = SubResource(7)
 visible = true
 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="."]
 [node name="CubePhysics" type="RigidBody" parent="."]
 
 
@@ -253,7 +253,7 @@ shape = SubResource(8)
 
 
 mesh = SubResource(9)
 mesh = SubResource(9)
 visible = true
 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="."]
 [node name="SpherePhysics" type="RigidBody" parent="."]
 
 
@@ -276,7 +276,7 @@ shape = SubResource(10)
 
 
 mesh = SubResource(11)
 mesh = SubResource(11)
 visible = true
 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"]
 [node name="Sphere002Collision" type="CollisionShape" parent="SpherePhysics"]
 
 
@@ -287,7 +287,7 @@ shape = SubResource(12)
 
 
 mesh = SubResource(13)
 mesh = SubResource(13)
 visible = true
 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="."]
 [node name="Sphere003Physics" type="RigidBody" parent="."]
 
 
@@ -310,7 +310,7 @@ shape = SubResource(14)
 
 
 mesh = SubResource(13)
 mesh = SubResource(13)
 visible = true
 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="."]
 [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]
 [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 type="Spatial" name="Scene"]
 
 
-
 [node name="SingleEdge" type="MeshInstance" parent="."]
 [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)
 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="."]
 [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)
 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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Plane" type="MeshInstance" parent="."]
 [node name="Plane" type="MeshInstance" parent="."]
 
 

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

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

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

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

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

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

文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/misc/invisible_objects.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/nla_animation/animation_multi_strip.escn


文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/nla_animation/animation_with_empty_strip.escn


文件差异内容过多而无法显示
+ 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,
 	"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]
 	"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="."]
 [node name="Suzanne" type="MeshInstance" parent="."]
 
 

文件差异内容过多而无法显示
+ 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":[]
 	"morph_arrays":[]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Cube" type="MeshInstance" parent="."]
 [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,
 	"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]
 	"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="."]
 [node name="Suzanne002" type="MeshInstance" parent="."]
 
 

文件差异内容过多而无法显示
+ 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
 		null, ; Morph Object
 	]]
 	]]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Suzanne002" type="MeshInstance" parent="."]
 [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
 		null, ; Morph Object
 	]]
 	]]
 }
 }
-[node type="Spatial" name="Scene"]
 
 
+[node type="Spatial" name="Scene"]
 
 
 [node name="Suzanne" type="MeshInstance" parent="."]
 [node name="Suzanne" type="MeshInstance" parent="."]
 
 

文件差异内容过多而无法显示
+ 0 - 0
tests/reference_exports/shape_key/shapekey_with_pose.escn


文件差异内容过多而无法显示
+ 10 - 0
tests/reference_exports/shape_key/shapekey_with_subdivision.escn


二进制
tests/test_scenes/armature/armature_not_ancester_of_mesh.blend


二进制
tests/test_scenes/shape_key/shapekey_with_subdivision.blend


部分文件因为文件数量过多而无法显示