Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AnimationPlayer.play_flipped() to play mirrored 3D animations #8478

Open
TheNetherPug opened this issue Nov 20, 2023 · 6 comments · May be fixed by godotengine/godot#89070
Open

Add AnimationPlayer.play_flipped() to play mirrored 3D animations #8478

TheNetherPug opened this issue Nov 20, 2023 · 6 comments · May be fixed by godotengine/godot#89070

Comments

@TheNetherPug
Copy link

Describe the project you are working on

I am currently working on a 3D, first person video game in Godot 4.2 which contains a full body mesh. In my game, there are multiple instances in which I have complex animations that need to be flipped (mirrored) depending on certain situations.

Describe the problem or limitation you are having in your project

I need the ability to flip complex animations with ease in-engine in order for the game to look, and feel much smoother and polished in a reasonable timeframe. It would take much longer to manually copy and paste the flipped animations in Blender, and reimport them than having a simple function. This would also reduce the size of the exported glb file.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

A large portion of developers may need to flip complex animations (such as motion captured animations with many keyframes) to fit different situations, but may not have the time to do so manually.

Having two animations, one mirrored and unmirrored causes issues long term, as modifying one animation will require the second flipped animation to be modified as well. Having a simple and easy function or way to easily mirror 3D animations with rigs will be greatly beneficial, as well as in some cases reducing the size of files.

For example, a wall running animation with one arm extended outwards, would need to be flipped depending on which wall the player is on. Another example is mirroring idle animations to match a walk or run animation to ensure feet placement are correct and smoothly transitioned to without complex interpolation logic.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

A simple function.

@onready var anim = $AnimationPlayer

if flipped:
  anim.play_flipped("WALLRUNNING")
else:
  anim.play("WALLRUNNING")

If this enhancement will not be used often, can it be worked around with a few lines of script?

I am not aware of any way this can be worked around using a few lines of script.

Is there a reason why this should be core and not an add-on in the asset library?

I believe this should be a core addition and not an add-on in the asset library as there are other animation-based nodes that allow mirroring of animations as well as greatly improving Godot's animation feature set from out of the box.

@AThousandShips
Copy link
Member

@Calinou Calinou changed the title Easily Flipping (Mirroring) 3D Animations Add AnimationPlayer.play_flipped() to play mirrored 3D animations Nov 20, 2023
@Calinou
Copy link
Member

Calinou commented Nov 20, 2023

A full-body mesh likely requires the use of AnimationTree for animation blending, so having this in AnimationPlayer alone wouldn't cut it.

@TheNetherPug
Copy link
Author

A full-body mesh likely requires the use of AnimationTree for animation blending, so having this in AnimationPlayer alone wouldn't cut it.

In my game, I chose to use an AnimationPlayer instead of an AnimationTree as it was simpler to use. Having this functionality in both AnimationTree and AnimationPlayer would be excellent as well, though i'm not too certain about AnimationTree.

@Remi123
Copy link

Remi123 commented Jan 4, 2024

Just adding my inputs as I've solved this issue in my code, so here is some info on how to do this.

By flipping we mostly mean inverse the location and rotation of the right and left side of the skeleton, usually on the X axis. So rotation from right side are applied to left side, and vice versa.

What I did was inspect each track of the animation and basically modify the key value depending of its type.
If it a position track, I multiply the value by Vector3(-1,0,0)
If it's a rotation, I multiply the Y and Z component of the Quaternion by -1. This mirror a quaternion on the X axis.

The only thing left is switching the track NodePath, since we mirrored the bone orientation but it's still applied to the incorrect bone. And this is where we need a mapping for each bone to let it define it's mirror counterpart. I have a simple Right/Left nomenclature so it's easy in my workflow, but to be general I suggest the class SkeletonProfile to add a variable for each bone to let it define it's mirror bone, and empty if no mirror like the head.

Once the mapping is done, it's trivial to know which bone mirror which and create mirror animation in editor and at runtime.

If I want to create a new animation, I just use this mapping to swap the node path, and mirror the bone position and rotation.
At runtime, the AnimationMixer ( the class that AnimationTree and AnimationPlayer inherit since 4.2 ) could blend using a SkeletonProfile with the mirror info and use it if required.

This logic is basically what Unreal and Unity does.

Hope it help

@Lunatix89
Copy link

I've did some research on this and came out with this solution: godotengine/godot#89070
However, I found out that it's not only about mirroring positions, rotations and bone names, it also needs to have a proper rest pose on the animations to work.

The PR also features the bone counterpart mapping which @Remi123 mentioned.
It's in draft mode and meant to be used for discussing this one further.

I also have a separate repo where I have the implementation in a standalone version so it would also be possible to use this in custom builds for users who really need it.

https://github.com/Lunatix89/godot-mirror-animations

@TokageItLab
Copy link
Member

TokageItLab commented Mar 2, 2024

The demand to do this without the use of DCC software such as Blender is understandable. However, to make the workflow completely independent of any DCC software, it would require a large amount of functionality, so I think it would be better to make it an add-on.

For example, we could consider a function like RootMotionExtructor that transfers the movement of hips to the root bone, or a function that separates the upper and lower body, but we may not be able to include everything in the importer/editor. We can come up with so many useful functions for editing these kinds of humanoid animations, so it is not realistic to include them all in the core and continue to maintain them.

Especially for editing functions that depend on Humanoid-focused workflows, it is not so generic and depends much on how users handle their data. It is possible that there are many people who do not need it, which could result in providing unstable functionality for a small amount of demand.

If there is a feature missing to create an add-on, it makes sense to implement an API for it. We know that AnimationTrackEditor is not extensible, so we may need to start working on those improvements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants