Browse Source

Refactor CollisionShape generating in physics

1. Remove triangulating in exporting any convex CollisionShape
2. Add utils to reuse mesh exporting related functions in CollisionShape
exporting
Jason0214 6 năm trước cách đây
mục cha
commit
bae7431678

+ 10 - 161
io_scene_godot/converters/mesh.py

@@ -1,15 +1,15 @@
 """Exports a normal triangle mesh"""
 import logging
 import bpy
-import bmesh
 import mathutils
 
 from .material import export_material
 from ..structures import (
     Array, NodeTemplate, InternalResource, Map, gamma_correct)
-from . import physics
-from . import armature
-from . import animation
+from .utils import MeshConverter, MeshResourceKey
+from .physics import has_physics, export_physics_properties
+from .armature import generate_bones_mapping
+from .animation import export_animation_data
 
 MAX_BONE_PER_VERTEX = 4
 
@@ -21,8 +21,8 @@ def export_mesh_node(escn_file, export_settings, obj, parent_gd_node):
     # If this mesh object has physics properties, we need to export them first
     # because they need to be higher in the scene-tree
 
-    if physics.has_physics(obj):
-        parent_gd_node = physics.export_physics_properties(
+    if has_physics(obj):
+        parent_gd_node = export_physics_properties(
             escn_file, export_settings, obj, parent_gd_node
         )
         # skip wire mesh which is used as collision mesh
@@ -59,7 +59,7 @@ def export_mesh_node(escn_file, export_settings, obj, parent_gd_node):
 
     # Transform of rigid mesh is moved up to its collision
     # shapes.
-    if physics.has_physics(obj):
+    if has_physics(obj):
         mesh_node['transform'] = mathutils.Matrix.Identity(4)
     else:
         mesh_node['transform'] = obj.matrix_local
@@ -69,25 +69,13 @@ def export_mesh_node(escn_file, export_settings, obj, parent_gd_node):
     # export shape key animation
     if (export_settings['use_export_shape_key'] and
             has_shape_keys(obj.data)):
-        animation.export_animation_data(
+        export_animation_data(
             escn_file, export_settings, mesh_node,
             obj.data.shape_keys, 'shapekey')
 
     return mesh_node
 
 
-def triangulate_mesh(mesh):
-    """Triangulate a mesh"""
-    tri_mesh = bmesh.new()
-    tri_mesh.from_mesh(mesh)
-    bmesh.ops.triangulate(
-        tri_mesh, faces=tri_mesh.faces, quad_method="ALTERNATE")
-    tri_mesh.to_mesh(mesh)
-    tri_mesh.free()
-
-    mesh.update(calc_loop_triangles=True)
-
-
 def fix_vertex(vtx):
     """Changes a single position vector from y-up to z-up"""
     return mathutils.Vector((vtx.x, vtx.z, -vtx.y))
@@ -119,85 +107,12 @@ 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"""
 
@@ -232,8 +147,7 @@ class ArrayMeshResourceExporter:
         if armature_obj is None:
             return
 
-        bones_mapping = armature.generate_bones_mapping(export_settings,
-                                                        armature_obj)
+        bones_mapping = generate_bones_mapping(export_settings, armature_obj)
         for bl_bone_name, gd_bone_id in bones_mapping.items():
             group = self.object.vertex_groups.get(bl_bone_name)
             if group is not None:
@@ -310,7 +224,7 @@ class ArrayMeshResourceExporter:
             )
 
             mesh_converter = MeshConverter(self.object, export_settings)
-            shape_key_mesh = mesh_converter.to_mesh(index)
+            shape_key_mesh = mesh_converter.to_mesh(shape_key_index=index)
 
             surfaces_morph_data = self.intialize_surfaces_morph_data(surfaces)
 
@@ -675,68 +589,3 @@ 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

+ 77 - 30
io_scene_godot/converters/physics.py

@@ -7,6 +7,7 @@ physics owns the object.
 import logging
 import mathutils
 from ..structures import NodeTemplate, InternalResource, Array, _AXIS_CORRECT
+from .utils import MeshConverter, MeshResourceKey
 
 PHYSICS_TYPES = {'KinematicBody', 'RigidBody', 'StaticBody'}
 
@@ -72,10 +73,17 @@ def export_collision_shape(escn_file, export_settings, node, parent_gd_node,
     col_shape = None
     if rbd.collision_shape in ("CONVEX_HULL", "MESH"):
         is_convex = rbd.collision_shape == "CONVEX_HULL"
-        shape_id = generate_shape_mesh(
-            escn_file, export_settings,
-            node, is_convex
-        )
+        if rbd.collision_shape == "CONVEX_HULL":
+            shape_id = generate_convex_shape(
+                escn_file, export_settings, node
+            )
+        else:  # "MESH"
+            shape_id = generate_concave_shape(
+                escn_file, export_settings, node
+            )
+
+        if shape_id is not None:
+            col_node['shape'] = "SubResource({})".format(shape_id)
     else:
         bounds = get_extents(node)
         if rbd.collision_shape == "BOX":
@@ -96,56 +104,95 @@ def export_collision_shape(escn_file, export_settings, node, parent_gd_node,
         else:
             logging.warning("Unable to export physics shape for %s", node.name)
 
+        col_node['shape'] = "SubResource({})".format(shape_id)
         if col_shape is not None and rbd.use_margin:
             col_shape['margin'] = rbd.collision_margin
 
-    if shape_id is not None:
-        col_node['shape'] = "SubResource({})".format(shape_id)
     escn_file.add_node(col_node)
 
     return col_node
 
 
-def generate_shape_mesh(escn_file, export_settings, node, is_convex):
-    """Generates godots PolygonShape from a blender mesh object"""
-    # pylint: disable-msg=cyclic-import
-    from .mesh import (MeshConverter, MeshResourceKey)
+class MeshCollisionShapeKey:
+    """Produces a resource key based on an mesh object's data and rigid
+    propertys"""
+    def __init__(self, shape_type, bl_object, export_settings):
+        assert shape_type in ("ConvexPolygonShape", "ConcavePolygonShape")
 
-    margin = 0
-    if node.rigid_body.use_margin:
-        margin = node.rigid_body.collision_margin
+        mesh_data_key = MeshResourceKey(shape_type, bl_object, export_settings)
+        # margin is the property that stores in CollisionShape in Godot
+        margin = 0
+        if bl_object.rigid_body.use_margin:
+            margin = bl_object.rigid_body.collision_margin
 
-    # Build the Shape resource hash key with rigid margin and mesh data
-    if is_convex:
-        shape_rsc_type = "ConvexPolygonShape"
-    else:
-        shape_rsc_type = "ConcavePolygonShape"
-    mesh_data_key = MeshResourceKey(shape_rsc_type, node, export_settings)
-    shape_rsc_key = (margin, mesh_data_key)
+        self._data = tuple((margin, mesh_data_key))
+
+    def __hash__(self):
+        return hash(self._data)
+
+    def __eq__(self, other):
+        # pylint: disable=protected-access
+        return (self.__class__ == other.__class__ and
+                self._data == other._data)
 
+
+def generate_convex_shape(escn_file, export_settings, bl_object):
+    """Generates godots ConvexCollisionShape from a blender mesh object"""
+    shape_rsc_key = MeshCollisionShapeKey(
+        "ConvexPolygonShape", bl_object, export_settings)
     shape_id = escn_file.get_internal_resource(shape_rsc_key)
     if shape_id is not None:
         return shape_id
 
     # No cached Shape found, build new one
     col_shape = None
-    mesh_converter = MeshConverter(node, export_settings)
-    mesh = mesh_converter.to_mesh(calculate_tangents=False)
+    mesh_converter = MeshConverter(bl_object, export_settings)
+    mesh = mesh_converter.to_mesh(
+        triangulate=False,
+        preserve_vertex_groups=False,
+        calculate_tangents=False
+    )
+    if mesh is not None:
+        vert_array = [vert.co for vert in mesh.vertices]
+        col_shape = InternalResource("ConvexPolygonShape", mesh.name)
+        col_shape['points'] = Array("PoolVector3Array(", values=vert_array)
+        if bl_object.rigid_body.use_margin:
+            col_shape['margin'] = bl_object.rigid_body.collision_margin
+
+        shape_id = escn_file.add_internal_resource(col_shape, shape_rsc_key)
+
+    mesh_converter.to_mesh_clear()
+
+    return shape_id
+
+
+def generate_concave_shape(escn_file, export_settings, bl_object):
+    """Generates godots ConcaveCollisionShape from a blender mesh object"""
+    shape_rsc_key = MeshCollisionShapeKey(
+        "ConcavePolygonShape", bl_object, export_settings)
+    shape_id = escn_file.get_internal_resource(shape_rsc_key)
+    if shape_id is not None:
+        return shape_id
+
+    # No cached Shape found, build new one
+    col_shape = None
+    mesh_converter = MeshConverter(bl_object, export_settings)
+    mesh = mesh_converter.to_mesh(
+        triangulate=True,
+        preserve_vertex_groups=False,
+        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 is_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)
+        col_shape = InternalResource("ConcavePolygonShape", mesh.name)
+        col_shape['data'] = Array("PoolVector3Array(", values=vert_array)
 
-        if node.rigid_body.use_margin:
-            col_shape['margin'] = node.rigid_body.collision_margin
+        if bl_object.rigid_body.use_margin:
+            col_shape['margin'] = bl_object.rigid_body.collision_margin
 
         shape_id = escn_file.add_internal_resource(col_shape, shape_rsc_key)
 

+ 158 - 0
io_scene_godot/converters/utils.py

@@ -0,0 +1,158 @@
+"""Util functions and structs shared by multiple resource converters"""
+
+import bpy
+import bmesh
+
+
+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 triangulate_mesh(mesh):
+    """Triangulate a mesh"""
+    tri_mesh = bmesh.new()
+    tri_mesh.from_mesh(mesh)
+    bmesh.ops.triangulate(
+        tri_mesh, faces=tri_mesh.faces, quad_method="ALTERNATE")
+    tri_mesh.to_mesh(mesh)
+    tri_mesh.free()
+
+    mesh.update(calc_loop_triangles=True)
+
+
+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 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, triangulate=True, preserve_vertex_groups=True,
+                calculate_tangents=True, shape_key_index=0):
+        """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=preserve_vertex_groups,
+            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:
+            if triangulate:
+                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

+ 2 - 2
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, 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)
+points = PoolVector3Array(1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 0.999999, 4.09789, 0.999999, -1.0, 4.09789, -1.0, -1.0, 4.09789, -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, 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)
+points = PoolVector3Array(1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 0.999999, 4.09789, 0.999999, -1.0, 4.09789, -1.0, -1.0, 4.09789, -1.0, 1.0, 4.09789)
 
 [sub_resource id=4 type="Animation"]
 

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

@@ -3,7 +3,7 @@
 [sub_resource id=1 type="ConvexPolygonShape"]
 
 resource_name = "Cube002"
-points = PoolVector3Array(-0.8, -0.8, 1.2, -0.8, 0.8, -1.2, -0.8, -0.8, -1.2, -0.8, 0.8, 1.2, 0.8, 0.8, -1.2, -0.8, 0.8, -1.2, 0.8, 0.8, 1.2, 0.8, -0.8, -1.2, 0.8, 0.8, -1.2, 0.8, -0.8, 1.2, -0.8, -0.8, -1.2, 0.8, -0.8, -1.2, 0.8, 0.8, -1.2, -0.8, -0.8, -1.2, -0.8, 0.8, -1.2, -0.8, 0.8, 1.2, 0.8, -0.8, 1.2, 0.8, 0.8, 1.2, -0.8, -0.8, 1.2, -0.8, 0.8, 1.2, -0.8, 0.8, -1.2, -0.8, 0.8, 1.2, 0.8, 0.8, 1.2, 0.8, 0.8, -1.2, 0.8, 0.8, 1.2, 0.8, -0.8, 1.2, 0.8, -0.8, -1.2, 0.8, -0.8, 1.2, -0.8, -0.8, 1.2, -0.8, -0.8, -1.2, 0.8, 0.8, -1.2, 0.8, -0.8, -1.2, -0.8, -0.8, -1.2, -0.8, 0.8, 1.2, -0.8, -0.8, 1.2, 0.8, -0.8, 1.2)
+points = PoolVector3Array(-0.8, -0.8, -1.2, -0.8, -0.8, 1.2, -0.8, 0.8, -1.2, -0.8, 0.8, 1.2, 0.8, -0.8, -1.2, 0.8, -0.8, 1.2, 0.8, 0.8, -1.2, 0.8, 0.8, 1.2)
 
 [sub_resource id=2 type="ArrayMesh"]
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
tests/reference_exports/mesh/physics.escn


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác