Open rcorre opened 1 year ago
You need to save the model as a local resource in the project preferably as a .tscn file, you can then remove the source .glb from the project directory and use the model locally. Any changes made to the animation tracks including looping will be saved then. Simply create a new scene, chuck the model in there and then right click -> make local
Saving the model as a local resource would break the inheritance relationship with the GLTF model. I want to be able to make future changes to the model and reimport it while keeping animation tracks I've added. The setting "Keep on Reimport" seems to imply this is possible. Is that not the case?
In Godot3, an animation named "run-loop" in GLTF would be called "run-loop" in Godot, and would loop. In Godot4, it removes the "-loop" suffix, but still sets it to loop. I'm guessing that when you save the animations to ".scn" files, it loses the loop information which is no longer encoded in the name.
I usually just set the model up again after making changes keeping any custom nodes I created, if you are using scripts and or animation trees to control the model you can just re-attach them to the model/animation player node after re-importing and replacing the old model. It is cumbersome but it suffices for the time being. This issue persists in versions 3.x too, if you set an animation to loop within the editor, if the resource has not been localized it will lose that information upon restart.
I was having the same problem with importing models. As a workaround, I have found that you can run the Advanced import and save all the external files, and then just click the Reimport button in the Import tab. This worked most of the time for me. Though I had a post import script running to set all the loops. I've attached the import script in case seeing it is helpful for anyone else encountering the problem.
@tool
extends EditorScenePostImport
enum LoopMode { LOOP_NONE, LOOP_LINEAR, LOOP_PINGPONG }
const LOOPMODE = ["LOOP_NONE", "[b][color=green]LOOP_LINEAR[/color][/b]", "[b][color=orange]LOOP_PINGPONG[/color][/b]"]
var scene_name: StringName
# Import script for characters to set up everything so no editing is needed once the character is
# instantiated.
func _post_import(scene):
scene_name = scene.name
print_rich("\n[b][color=red]Begin Post-import[/color] -> [color=purple]%s[/color] as [color=green]%s[/color][/b]" % [scene_name, scene.get_class()])
print_rich("[b]Time/Date Stamp: %s[/b]\n" % [Time.get_datetime_string_from_system(false, true)])
iterate(scene)
return scene
func iterate(node):
if node != null:
# Put the character on the character layer (5) and make sure they can't walk through
# walls (2) or destructibles (3), they can pick up loot (4), and they will bump into
# other players (5), NPCs (6), and enemies (7).
if node is CharacterBody3D:
node.set_collision_layer_value(1, false)
node.set_collision_layer_value(5, true)
for i in range(2,8):
node.set_collision_mask_value(i, true)
print_rich("Post-import: [b]Masked Layer [color=green]%s[/color] [color=yellow]%s[/color][/b] -> [color=yellow][b]%s[/b][/color]" % [node.get_class(), i, get_color_string(true)])
# Add looping animations
if node is AnimationPlayer:
for animation_name in node.get_animation_list():
if animation_name.contains("Idle") or animation_name.contains("ing") and not animation_name.contains("Standing"):
node.get_animation(animation_name).set_loop_mode(LoopMode.LOOP_LINEAR)
print_rich("Post-import: [b]%s[/b] -> [b]%s[/b]" % [animation_name, LOOPMODE[node.get_animation(animation_name).get_loop_mode()]])
# Append "_Bone" to BoneAttachment3D nodes just to prevent duplicate names in our scene tree.
if node is BoneAttachment3D:
node.name = node.name + "_Bone"
print_rich("Post-import: [b]Renamed [color=green]%s[/color] [color=yellow]%s[/color][/b] -> [color=yellow][b]%s[/b][/color]" % [node.get_class(), node.name, node.name + "_Bone"])
# We want to hide everything in the character's hands, and everything they are wearing that is removeable.
if node is MeshInstance3D and node.get_parent() is BoneAttachment3D:
node.set_visible(false)
print_rich("Post-import: [b]Visibile [color=green]%s[/color] [color=yellow]%s[/color][/b] -> [color=yellow][b]%s[/b][/color]" % [node.get_class(), node.name, get_color_string(node.visible)])
# Rotating the model to face the other direction so it moves in the correct direction when animated.
if node is Skeleton3D:
node.rotate_y(deg_to_rad(-180.0))
print_rich("Post-import: [b]Rotated [color=green]%s[/color] [color=yellow]-180 degrees[/color][/b] on the [b][color=green]y-axis[/color][/b]" % [node.get_class()])
# Recursively call this function on any child nodes that exist.
for child in node.get_children():
iterate(child)
# Return rich text color string for true (green)/red (false).
func get_color_string(value: bool):
if value:
return "[color=green]true[/color]"
else:
return "[color=red]false[/color]"
Godot version
4.0.dev
System information
Linux
Issue description
Importing animations to
.res
files removes the looping attribute that was inferred from the "-loop" suffixSteps to reproduce
-loop
suffix as a new inherited sceneMinimal reproduction project
example.zip