瀏覽代碼

support bezier track as beta feature

Jason0214 6 年之前
父節點
當前提交
ce76bb279e

+ 101 - 82
io_scene_godot/converters/animation/action.py

@@ -36,6 +36,7 @@ def get_strip_frame_range(strip):
 class ActionStrip:
     """Abstract of blender action strip, it may override attributes
     of an action object"""
+
     def __init__(self, action_or_strip):
         self.action = None
         self.frame_range = (0, 0)
@@ -103,9 +104,9 @@ def has_obj_fcurves(action_strip):
 
 
 # pylint: disable-msg=too-many-locals
-def export_constrained_xform_action(godot_node, animation_player,
+def export_constrained_xform_action(godot_node, export_settings,
                                     blender_object, action_strip,
-                                    animation_resource):
+                                    anim_rsc):
     """Export transform animation of any object has constraints,
     it use frame_set to traversal each frame, so it's costly"""
     def build_pbone_parent_map(godot_node, blender_object):
@@ -160,7 +161,7 @@ def export_constrained_xform_action(godot_node, animation_player,
         ]
 
         track_path = NodePath(
-            animation_player.parent.get_path(),
+            anim_rsc.anim_player.parent.get_path(),
             godot_node.get_path()
         )
 
@@ -170,7 +171,7 @@ def export_constrained_xform_action(godot_node, animation_player,
                 for x in xform_frames_list
             ]
 
-        animation_resource.add_obj_xform_track(
+        anim_rsc.add_obj_xform_track(
             godot_node.get_type(), track_path,
             xform_frames_list, action_strip.frame_range,
             # no need for parent_inverse, as it is directly access matrix_local
@@ -185,12 +186,12 @@ def export_constrained_xform_action(godot_node, animation_player,
                 ]
 
                 track_path = NodePath(
-                    animation_player.parent.get_path(),
+                    anim_rsc.anim_player.parent.get_path(),
                     godot_node.get_path(),
                     godot_node.find_bone_name(pbone_name),
                 )
 
-                animation_resource.add_track(
+                anim_rsc.add_track(
                     TransformTrack(
                         track_path,
                         frames_iter=range(first_frame, last_frame),
@@ -199,8 +200,8 @@ def export_constrained_xform_action(godot_node, animation_player,
                 )
 
 
-def export_transform_action(godot_node, animation_player, blender_object,
-                            action_strip, animation_resource):
+def export_transform_action(godot_node, export_settings, blender_object,
+                            action_strip, anim_rsc):
     """Export a action with bone and object transform"""
     def init_transform_frames_list(object_path, blender_object, godot_node,
                                    first_frame, last_frame):
@@ -275,7 +276,7 @@ def export_transform_action(godot_node, animation_player, blender_object,
         if object_path == '':
             # empty object_path represents transform of object itself
             track_path = NodePath(
-                animation_player.parent.get_path(),
+                anim_rsc.anim_player.parent.get_path(),
                 godot_node.get_path()
             )
 
@@ -285,7 +286,7 @@ def export_transform_action(godot_node, animation_player, blender_object,
                     for x in frame_value_list
                 ]
 
-            animation_resource.add_obj_xform_track(
+            anim_rsc.add_obj_xform_track(
                 godot_node.get_type(), track_path,
                 frame_value_list, action_strip.frame_range,
                 blender_object.matrix_parent_inverse
@@ -293,13 +294,13 @@ def export_transform_action(godot_node, animation_player, blender_object,
 
         elif object_path.startswith('pose'):
             track_path = NodePath(
-                animation_player.parent.get_path(),
+                anim_rsc.anim_player.parent.get_path(),
                 godot_node.get_path(),
                 godot_node.find_bone_name(
                     blender_path_to_bone_name(object_path)
                 ),
             )
-            animation_resource.add_track(
+            anim_rsc.add_track(
                 TransformTrack(
                     track_path,
                     frames_iter=range(first_frame, last_frame),
@@ -308,124 +309,142 @@ def export_transform_action(godot_node, animation_player, blender_object,
             )
 
 
-def export_shapekey_action(godot_node, animation_player, blender_object,
-                           action_strip, animation_resource):
+def export_shapekey_action(godot_node, export_settings, blender_object,
+                           action_strip, anim_rsc):
     """Export shapekey value action"""
-    first_frame, last_frame = action_strip.frame_range
+    base_node_path = NodePath(
+        anim_rsc.anim_player.parent.get_path(), godot_node.get_path()
+    )
     for fcurve in action_strip.action.fcurves:
-
         object_path, attribute = split_fcurve_data_path(fcurve.data_path)
 
         if attribute == 'value':
             shapekey_name = re.search(r'key_blocks\["([^"]+)"\]',
                                       object_path).group(1)
 
-            track_path = NodePath(
-                animation_player.parent.get_path(),
-                godot_node.get_path(),
-                "blend_shapes/{}".format(shapekey_name)
+            anim_rsc.add_attribute_track(
+                action_strip,
+                fcurve,
+                lambda x: x,
+                base_node_path.new_copy(
+                    "blend_shapes/{}".format(shapekey_name)),
+                use_bezier=export_settings['feature_bezier_track']
             )
 
-            track = FloatTrack(track_path)
 
-            for frame in range(first_frame, last_frame):
-                track.add_frame_data(
-                    frame,
-                    action_strip.evaluate_fcurve(fcurve, frame)
-                )
-
-            animation_resource.add_track(track)
-
-
-def export_light_action(light_node, animation_player, blender_lamp,
-                        action_strip, animation_resource):
+def export_light_action(light_node, export_settings, blender_lamp,
+                        action_strip, anim_rsc):
     """Export light(lamp in Blender) action"""
-    # pylint: disable-msg=R0914
+    # pylint: disable-msg=too-many-branches
     base_node_path = NodePath(
-        animation_player.parent.get_path(), light_node.get_path()
+        anim_rsc.anim_player.parent.get_path(), light_node.get_path()
     )
 
     fcurves = action_strip.action.fcurves
-
-    animation_resource.add_attribute_track(
+    # CONSTANT tracks
+    anim_rsc.add_attribute_track(
         action_strip,
         fcurves.find('shadow_method'),
         lambda x: x > 0.0,
         base_node_path.new_copy('shadow_enabled'),
     )
 
+    color_attr_conversion = list()
+    # simple value tracks
     for item in light_node.attribute_conversion:
         bl_attr, gd_attr, converter = item
-        if bl_attr not in ('color', 'shadow_color'):
-            animation_resource.add_attribute_track(
+        if bl_attr in ('color', 'shadow_color'):
+            color_attr_conversion.append(item)
+        else:
+            anim_rsc.add_attribute_track(
                 action_strip,
                 fcurves.find(bl_attr),
                 converter,
-                base_node_path.new_copy(gd_attr)
+                base_node_path.new_copy(gd_attr),
+                use_bezier=export_settings["feature_bezier_track"]
             )
 
-    # color tracks is not one-one mapping to fcurve, they
-    # need to be treated like transform track
-    color_frame_values_map = collections.OrderedDict()
+    if export_settings["feature_bezier_track"]:
+        rgba_names = ('r', 'g', 'b', 'a')
+        for fcurve in fcurves:
+            if fcurve is None:
+                continue
+            _, attribute = split_fcurve_data_path(fcurve.data_path)
+
+            for bl_attr, gd_attr, converter in color_attr_conversion:
+                if bl_attr == attribute:
+                    track_path = base_node_path.new_copy(
+                        gd_attr + ':' + rgba_names[fcurve.array_index]
+                    )
+                    anim_rsc.add_attribute_track(
+                        action_strip,
+                        fcurve,
+                        converter,
+                        track_path,
+                        use_bezier=True)
+    else:
+        # color tracks is not one-one mapping to fcurve, they
+        # need to be treated like transform track
+        color_frame_values_map = collections.OrderedDict()
+
+        first_frame, last_frame = action_strip.frame_range
+        for fcurve in fcurves:
+            _, attribute = split_fcurve_data_path(fcurve.data_path)
+
+            if attribute in ('color', 'shadow_color'):
+                if attribute not in color_frame_values_map:
+                    color_frame_values_map[attribute] = [
+                        mathutils.Color()
+                        for _ in range(first_frame, last_frame)
+                    ]
+                color_list = color_frame_values_map[attribute]
+                for frame in range(first_frame, last_frame):
+                    color_list[frame - first_frame][fcurve.array_index] = (
+                        action_strip.evaluate_fcurve(fcurve, frame)
+                    )
 
-    first_frame, last_frame = action_strip.frame_range
-    for fcurve in fcurves:
-        _, attribute = split_fcurve_data_path(fcurve.data_path)
-
-        if attribute in ('color', 'shadow_color'):
-            if attribute not in color_frame_values_map:
-                color_frame_values_map[attribute] = [
-                    mathutils.Color()
-                    for _ in range(first_frame, last_frame)
+        for bl_attr, _, converter in light_node.attribute_conversion:
+            if (bl_attr in ('color', 'shadow_color') and
+                    bl_attr in color_frame_values_map):
+                color_frame_values_map[bl_attr] = [
+                    converter(x) for x in color_frame_values_map[bl_attr]
                 ]
-            color_list = color_frame_values_map[attribute]
-            for frame in range(first_frame, last_frame):
-                color_list[frame - first_frame][fcurve.array_index] = (
-                    action_strip.evaluate_fcurve(fcurve, frame)
-                )
 
-    for bl_attr, _, converter in light_node.attribute_conversion:
-        if (bl_attr in ('color', 'shadow_color') and
-                bl_attr in color_frame_values_map):
-            color_frame_values_map[bl_attr] = [
-                converter(x) for x in color_frame_values_map[bl_attr]
-            ]
+        for attribute, frame_value_list in color_frame_values_map.items():
+            if attribute == 'color':
+                track_path = base_node_path.new_copy('light_color')
+            else:
+                track_path = base_node_path.new_copy('shadow_color')
 
-    for attribute, frame_value_list in color_frame_values_map.items():
-        if attribute == 'color':
-            track_path = base_node_path.new_copy('light_color')
-        else:
-            track_path = base_node_path.new_copy('shadow_color')
-
-        animation_resource.add_track(
-            ColorTrack(
-                track_path,
-                frames_iter=range(first_frame, last_frame),
-                values_iter=frame_value_list
+            anim_rsc.add_track(
+                ColorTrack(
+                    track_path,
+                    frames_iter=range(first_frame, last_frame),
+                    values_iter=frame_value_list
+                )
             )
-        )
 
 
-def export_camera_action(camera_node, animation_player, blender_cam,
-                         action_strip, animation_resource):
+def export_camera_action(camera_node, export_settings, blender_cam,
+                         action_strip, anim_rsc):
     """Export camera action"""
-    # pylint: disable-msg=R0914
     first_frame, last_frame = action_strip.frame_range
     base_node_path = NodePath(
-        animation_player.parent.get_path(), camera_node.get_path()
+        anim_rsc.anim_player.parent.get_path(), camera_node.get_path()
     )
 
     fcurves = action_strip.action.fcurves
     for item in camera_node.attribute_conversion:
         bl_attr, gd_attr, converter = item
-        animation_resource.add_attribute_track(
+        anim_rsc.add_attribute_track(
             action_strip,
             fcurves.find(bl_attr),
             converter,
-            base_node_path.new_copy(gd_attr)
+            base_node_path.new_copy(gd_attr),
+            use_bezier=export_settings['feature_bezier_track'],
         )
 
-    animation_resource.add_attribute_track(
+    anim_rsc.add_attribute_track(
         action_strip,
         fcurves.find('type'),
         lambda x: 0 if x == 0.0 else 1,
@@ -470,7 +489,7 @@ def export_camera_action(camera_node, animation_player, blender_cam,
                 )
             ))
 
-        animation_resource.add_track(
+        anim_rsc.add_track(
             FloatTrack(
                 base_node_path.new_copy('fov'),
                 frames_iter=range(first_frame, last_frame),

+ 15 - 11
io_scene_godot/converters/animation/animation_data.py

@@ -28,6 +28,7 @@ ACTION_EXPORTER_MAP = {
 class ObjectAnimationExporter:
     """A helper class holding states while exporting
     animation data from a blender object"""
+
     def __init__(self, godot_node, blender_object, action_type):
         self.godot_node = godot_node
         self.blender_object = blender_object
@@ -69,7 +70,7 @@ class ObjectAnimationExporter:
                 else:
                     self.mute_nla_tracks.append(nla_track)
 
-    def export_active_action(self, escn_file, active_action):
+    def export_active_action(self, escn_file, export_settings, active_action):
         """Export the active action, if needed, would call bake.
         Note that active_action maybe None, which would happen when object has
         some constraint (so even no action it is still animated)"""
@@ -87,7 +88,7 @@ class ObjectAnimationExporter:
 
         self.action_exporter_func(
             self.godot_node,
-            self.animation_player,
+            export_settings,
             self.blender_object,
             ActionStrip(active_action),
             self.animation_player.active_animation
@@ -102,13 +103,13 @@ class ObjectAnimationExporter:
                     if strip.action:
                         self.action_exporter_func(
                             self.godot_node,
-                            self.animation_player,
+                            export_settings,
                             self.blender_object,
                             ActionStrip(strip),
                             self.animation_player.active_animation
                         )
 
-    def export_active_action_from_nla(self, escn_file):
+    def export_active_action_from_nla(self, escn_file, export_settings):
         """Export all unmute nla_tracks into an active action.
         Note that it would not do baking for constraint"""
         if self.animation_player.active_animation is None:
@@ -121,13 +122,13 @@ class ObjectAnimationExporter:
                 if strip.action:
                     self.action_exporter_func(
                         self.godot_node,
-                        self.animation_player,
+                        export_settings,
                         self.blender_object,
                         ActionStrip(strip),
                         self.animation_player.active_animation
                     )
 
-    def export_stashed_track(self, escn_file, stashed_track):
+    def export_stashed_track(self, escn_file, export_settings, stashed_track):
         """Export a muted nla_track, track with all its contained action
         is exported to a single animation_resource.
         It works as an action lib"""
@@ -152,7 +153,7 @@ class ObjectAnimationExporter:
             if strip.action:
                 self.action_exporter_func(
                     self.godot_node,
-                    self.animation_player,
+                    export_settings,
                     self.blender_object,
                     ActionStrip(strip),
                     anim_resource
@@ -167,7 +168,7 @@ class ObjectAnimationExporter:
                     if strip.action:
                         self.action_exporter_func(
                             self.godot_node,
-                            self.animation_player,
+                            export_settings,
                             self.blender_object,
                             ActionStrip(strip),
                             anim_resource
@@ -201,10 +202,12 @@ def export_animation_data(escn_file, export_settings, godot_node,
         active_action = None
 
     if (active_action is not None or anim_exporter.need_baking):
-        anim_exporter.export_active_action(escn_file, active_action)
+        anim_exporter.export_active_action(
+            escn_file, export_settings, active_action)
     elif anim_exporter.unmute_nla_tracks:
         # if has effective nla_tracks but no active action, fake one
-        anim_exporter.export_active_action_from_nla(escn_file)
+        anim_exporter.export_active_action_from_nla(
+            escn_file, export_settings)
 
     # export actions in nla_tracks, each exported to seperate
     # animation resources
@@ -215,7 +218,8 @@ def export_animation_data(escn_file, export_settings, godot_node,
             obj_use_nla_backup = blender_object.animation_data.use_nla
             blender_object.animation_data.use_nla = True
         for stashed_track in anim_exporter.mute_nla_tracks:
-            anim_exporter.export_stashed_track(escn_file, stashed_track)
+            anim_exporter.export_stashed_track(
+                escn_file, export_settings, stashed_track)
         if blender_object.animation_data:
             blender_object.animation_data.use_nla = obj_use_nla_backup
 

+ 69 - 7
io_scene_godot/converters/animation/serializer.py

@@ -45,6 +45,14 @@ def strip_adjacent_dup_keyframes(frames, values):
     return stripped_frames, stripped_values
 
 
+class BezierFrame:
+    """A keyframe point in a bezier fcurve"""
+    def __init__(self, value, left_handle, right_handle):
+        self.value = value
+        self.left_handle = left_handle
+        self.right_handle = right_handle
+
+
 class TransformFrame:
     """A data structure hold transform values of an animation key,
     it is used as an intermedia data structure, being updated during
@@ -386,9 +394,33 @@ class ColorTrack(ValueTrack):
         )
 
 
-def get_fcurve_frame_range(fcurve):
-    """Return the a tuple denoting the frame range of fcurve"""
-    return int(fcurve.range()[0]), int(fcurve.range()[1]) + 1
+class BezierTrack(Track):
+    """Track using bezier interpolcation"""
+    def __init__(self, track_path, frames_iter=(), values_iter=()):
+        super().__init__("bezier", track_path, frames_iter, values_iter)
+
+    def blend_frames(self, frame_val1, frame_val2):
+        # xxx: default use REPLACE
+        return max(frame_val1, frame_val2)
+
+    def convert_to_keys_object(self):
+        """Convert a list of bezier point to a pool real array"""
+        time_array = Array(prefix='PoolRealArray(', suffix=')')
+        points_array = Array(prefix='PoolRealArray(', suffix=')')
+        fps = bpy.context.scene.render.fps
+        scene_frame_start = bpy.context.scene.frame_start
+        for frame, frame_val in zip(self.frames, self.values):
+            time = (frame - scene_frame_start) / fps
+            time_array.append(time)
+            points_array.append(frame_val.value)
+            points_array.append((frame_val.left_handle[0] - frame) / fps)
+            points_array.append(frame_val.left_handle[1])
+            points_array.append((frame_val.right_handle[0] - frame) / fps)
+            points_array.append(frame_val.right_handle[1])
+        keys_map = Map()
+        keys_map["points"] = points_array
+        keys_map["times"] = time_array
+        return keys_map
 
 
 def build_const_interp_value_track(track_path, action_strip, converter,
@@ -414,7 +446,7 @@ def build_linear_interp_value_track(track_path, action_strip, converter,
     """Build a godot value track by evaluate every frame of Blender fcurve"""
     track = FloatTrack(track_path)
 
-    frame_range = get_fcurve_frame_range(fcurve)
+    frame_range = action_strip.frame_range
     if converter is None:
         for frame in range(frame_range[0], frame_range[1]):
             track.add_frame_data(
@@ -429,13 +461,38 @@ def build_linear_interp_value_track(track_path, action_strip, converter,
     return track
 
 
+def build_beizer_interp_value_track(track_path, action_strip, converter,
+                                    fcurve):
+    """Build a godot bezier track"""
+    track = BezierTrack(track_path)
+
+    for keyframe in fcurve.keyframe_points:
+        point_value = converter(keyframe.co[1])
+        # bezier curve handle use margin
+        track.add_frame_data(
+            int(keyframe.co[0]),
+            BezierFrame(
+                point_value,
+                (keyframe.handle_left.x,
+                 converter(keyframe.handle_left.y) - point_value),
+                (keyframe.handle_right.x,
+                 converter(keyframe.handle_right.y) - point_value),
+            )
+        )
+
+    return track
+
+
 class AnimationResource(InternalResource):
     """Internal resource with type Animation"""
-    def __init__(self, name):
+    def __init__(self, name, owner_anim_player):
         super().__init__('Animation', name)
         self['step'] = 0.1
         self['length'] = 0
+
+        # helper attributes, not exported to ESCN
         self.tracks = collections.OrderedDict()
+        self.anim_player = owner_anim_player
 
     def add_track(self, track):
         """add a track to animation resource"""
@@ -475,8 +532,9 @@ class AnimationResource(InternalResource):
 
         self.add_track(track)
 
+    # pylint: disable-msg=too-many-arguments
     def add_attribute_track(self, action_strip, fcurve,
-                            converter, node_path):
+                            converter, node_path, use_bezier=False):
         """Add a track into AnimationResource, the track is a
         one-one mapping to one fcurve."""
         if fcurve is not None and fcurve.keyframe_points:
@@ -485,6 +543,10 @@ class AnimationResource(InternalResource):
                 new_track = build_const_interp_value_track(
                     node_path, action_strip, converter, fcurve
                 )
+            elif use_bezier and interpolation == 'BEZIER':
+                new_track = build_beizer_interp_value_track(
+                    node_path, action_strip, converter, fcurve
+                )
             else:
                 new_track = build_linear_interp_value_track(
                     node_path, action_strip, converter, fcurve
@@ -513,7 +575,7 @@ class AnimationPlayer(NodeTemplate):
         """Create a new animation resource and add it into escn file"""
         resource_name_filtered = re.sub(r'[\[\]\{\}]+', '', resource_name)
 
-        new_anim_resource = AnimationResource(resource_name_filtered)
+        new_anim_resource = AnimationResource(resource_name_filtered, self)
         # add animation resource without checking hash,
         # blender action is in world space, while godot animation
         # is in local space (parent space),  so identical actions

+ 7 - 0
io_scene_godot/structures.py

@@ -386,6 +386,13 @@ def fix_bone_attachment_location(attachment_obj, location_vec):
 
 def gamma_correct(color):
     """Apply sRGB color space gamma correction to the given color"""
+    if isinstance(color, float):
+        # seperate color channel
+        return color ** (1 / 2.2)
+
+    # mathutils.Color does not support alpha yet, so just use RGB
+    # see: https://developer.blender.org/T53540
+    color = color[0:3]
     # note that here use a widely mentioned sRGB approximation gamma = 2.2
     # it is good enough, the exact gamma of sRGB can be find at
     # https://en.wikipedia.org/wiki/SRGB

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

@@ -28,28 +28,28 @@ tracks/0/type = "value"
 tracks/0/path = NodePath(".:far")
 tracks/0/interp = 1
 tracks/0/keys = {
-	"times":PoolRealArray(0.5, 0.541667, 0.583333, 0.625, 0.666667, 0.708333, 0.75, 0.791667),
-	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1),
+	"times":PoolRealArray(0.0, 0.0416667, 0.5, 0.541667, 0.583333, 0.625, 0.666667, 0.708333, 0.75, 0.791667, 0.833333, 2.875),
+	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
 	"update":0,
-	"values":[100.0, 95.9174, 83.8392, 65.4366, 44.5634, 26.1609, 14.0826, 10.0]
+	"values":[100.0, 100.0, 100.0, 95.9174, 83.8392, 65.4366, 44.5634, 26.1609, 14.0826, 10.0, 10.0, 10.0]
 }
 tracks/1/type = "value"
 tracks/1/path = NodePath(".:near")
 tracks/1/interp = 1
 tracks/1/keys = {
-	"times":PoolRealArray(0.0, 0.0416667, 0.0833333, 0.125, 0.166667, 0.208333, 0.25, 0.291667, 0.333333, 0.375),
-	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+	"times":PoolRealArray(0.0, 0.0416667, 0.0833333, 0.125, 0.166667, 0.208333, 0.25, 0.291667, 0.333333, 0.375, 0.416667, 2.875),
+	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
 	"update":0,
-	"values":[0.1, 1.46695, 5.56822, 12.1535, 20.5309, 29.5691, 37.9465, 44.5318, 48.633, 50.0]
+	"values":[0.1, 1.46695, 5.56822, 12.1535, 20.5309, 29.5691, 37.9465, 44.5318, 48.633, 50.0, 50.0, 50.0]
 }
 tracks/2/type = "value"
 tracks/2/path = NodePath(".:size")
 tracks/2/interp = 1
 tracks/2/keys = {
-	"times":PoolRealArray(2.45833, 2.5, 2.54167, 2.58333, 2.625, 2.66667, 2.70833, 2.75, 2.79167, 2.83333, 2.875),
-	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+	"times":PoolRealArray(0.0, 0.0416667, 2.45833, 2.5, 2.54167, 2.58333, 2.625, 2.66667, 2.70833, 2.75, 2.79167, 2.83333, 2.875),
+	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
 	"update":0,
-	"values":[7.31429, 7.1743, 6.75302, 6.06803, 5.17209, 4.15714, 3.14219, 2.24626, 1.56127, 1.13998, 1.0]
+	"values":[7.31429, 7.31429, 7.31429, 7.1743, 6.75302, 6.06803, 5.17209, 4.15714, 3.14219, 2.24626, 1.56127, 1.13998, 1.0]
 }
 tracks/3/type = "value"
 tracks/3/path = NodePath(".:projection")

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

@@ -23,15 +23,15 @@ surfaces/0 = {
 
 resource_name = "SunAction001"
 step = 0.1
-length = 1.25
+length = 4.58333
 tracks/0/type = "value"
 tracks/0/path = NodePath(".:light_energy")
 tracks/0/interp = 1
 tracks/0/keys = {
-	"times":PoolRealArray(0.0, 0.0416667, 0.0833333, 0.125, 0.166667, 0.208333, 0.25, 0.291667, 0.333333, 0.375, 0.416667, 0.458333, 0.5, 0.541667, 0.583333, 0.625, 0.666667, 0.708333, 0.75, 0.791667, 0.833333, 0.875, 0.916667, 0.958333, 1.0, 1.04167, 1.08333, 1.125, 1.16667, 1.20833, 1.25),
-	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
+	"times":PoolRealArray(0.0, 0.0416667, 0.0833333, 0.125, 0.166667, 0.208333, 0.25, 0.291667, 0.333333, 0.375, 0.416667, 0.458333, 0.5, 0.541667, 0.583333, 0.625, 0.666667, 0.708333, 0.75, 0.791667, 0.833333, 0.875, 0.916667, 0.958333, 1.0, 1.04167, 1.08333, 1.125, 1.16667, 1.20833, 1.25, 1.29167, 4.58333),
+	"transitions":PoolRealArray(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
 	"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]
+	"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"]