GuilhermeGSousa / godot-motion-matching

A Motion Matching plugin for Godot 4
30 stars 5 forks source link

Implement Motion Matching as an `AnimationRootNode` #41

Closed GuilhermeGSousa closed 1 week ago

GuilhermeGSousa commented 1 month ago

As the API for motion matching evolves, its becoming clear that motion matching should be implemented as an AnimationRootNode, that receives its query inputs as a parameter. As I see it, the advantages to this would be:

There are some changes required at the engine level to be able to do this:

fire commented 1 month ago

Are you working on this openly?

GuilhermeGSousa commented 1 month ago

I am! I am starting to learn that the only way to do it on Godot's latest version is through a custom module, the GDExtension bindings aren't in a place where extending a AnimationRootNode is doable (and probably won't be until structs are in the engine). The way I see it right now we either:

I'm curious to know what you think!

fire commented 1 month ago

I've done this before with a different project. This is a practical way of implementing motion matching.

https://github.com/V-Sekai/godot/tree/vsk-motion-matching-4.3/modules/motion_matching

https://github.com/V-Sekai/motion_matching

Note the project is archived.

fire commented 1 month ago

I use https://github.com/ingydotnet/git-subrepo to import a standalone git repo into a branch of godot engine.

GuilhermeGSousa commented 1 month ago

This is perfect, making a submodule out of a directory of this repo is just what I need, I'll set that up. This repo has a working motion matching implementation, but I now think the correct way of doing it for a 1.0 version is to have motion matching queries run on animation nodes. The two big advantages of this approach imo:

I saw V-Sekai and Remi's motion matching implementation, I also had the chance to discuss this with him!

fire commented 1 month ago

My dream for when we get the basic implementation is to also implement https://peizhuoli.github.io/walkthedog/index.html

fire commented 1 month ago

You may have missed the branch for module https://github.com/V-Sekai/motion_matching/tree/module

fire commented 1 month ago

Are you on discord? I exceeded my friend limit of 1000 so if we want to talk it'll have to be the V-Sekai discord here.

https://linktr.ee/chibifire

GuilhermeGSousa commented 1 month ago

I am! I'll ping you on discord

GuilhermeGSousa commented 1 month ago

Just joined the discord!

GeorgeS2019 commented 1 month ago

@fire

https://github.com/GuilhermeGSousa/godot-motion-matching/issues/41#issuecomment-2436441892 It is important to respect where the codes come from

https://github.com/V-Sekai/godot/tree/vsk-motion-matching-4.3/modules/motion_matching is basically copy from Remi without clearly acknowledging.

https://github.com/V-Sekai/motion_matching is simply clearly stating that it is a fork.

Both links provided come from one same source. One is a fork, One is copying without acknowledging.

In both cases, there are no evidence that the CI works.

This ethical in respecting others contribution is critical in Godot community project and the foundation of trust-worthiness collaboration.

fire commented 1 month ago

The code vsk-motion-matching-4.3/modules/motion_matching/LICENSE clearly acknowledges Remi.

image

GeorgeS2019 commented 1 month ago

@fire

I appreciate your enthusiasm:

I want to trust your enthusiasm I know your strengths : Please make sure your codes are CI working before recommending merger.

When I work with Malcolm This is what I learned from him

fire commented 1 month ago

The primary HEAD of development is https://github.com/GuilhermeGSousa/godot-motion-matching/tree/engine-module.

The cicd for the branch is failing https://github.com/GuilhermeGSousa/godot-motion-matching/pull/42

image

So that's what I'm working on.

GeorgeS2019 commented 1 month ago

@fire

Yes, please help this project to get the CI working in reliable way

I know you have a lot of experience in this area.

The community depends on you :-)

fire commented 1 month ago

Notes from トカゲ

To explain the fundamental design, AnimationTree does not have a process for playing back animations; AnimationNodeAnimation does all the work for playback

AnimationNodeAnimation generates/stores a timeline from the length of each animation, manages the playback position, and passes it to the AnimationMixer.

So, if you do not want to write such playback position management from scratch, you should refer to AnimationNodeTransition or AnimationBlendSpace2D, which blend multiple AnimationNodeAnimation AnimationNode.

There you don't need to manage the playback position, just seek instructions and blend amount adjustments to the AnimationNodes connected as a result of the matching

fire commented 1 month ago

I have marked all non motion-matching node discussions as offtopic.

GeorgeS2019 commented 1 month ago

https://github.com/GuilhermeGSousa/godot-motion-matching/issues/41#issuecomment-2436441892

This is the cause of triggering off topic ...do learn the truth will always prevail

fire commented 1 month ago

トカゲ — Today at 18:22

There is no API to directly transition keyframes from AnimationA to AnimationB. Although you can pass weight information to the AnimationPlaybackInfo passed to AnimationMixer::make_animation_instance to blend the results of AnimationA and AnimationB by 0.5

make_animation_instance() is the essential playback API of AnimationMixer, which extracts the values at a given frame of a given animation resource and stacks them for blending.

In AnimationNodes, only AnimationNodeAnimation calls make_animation_instance() as blend_animation(), while upstream API such as AnimationNodeBlend2 only passes weight information to AnimationNodeAnimation. The weight information in the PlaybackInfo includes the overall animation weight weight and the track_weights per track, and the AnimationTree blend probably computes the track_weights mainly

The blend_animation() method exposed in GDScript lacks a way to specify track_weights and start/end parameters, which is why it is not available in GDScript anyway; The struct PlaybackInfo passed upstream has track_weights information that must be passed to blend_animation(), but due to a missing struct, track_weights can neither be retrieved nor passed in GDScript/GDExtention. Also, make_animation_instance() cannot be exposed now, because it requires a struct argument as well

In summary, AnimationNode::_process() has a p_playback_info argument that contains weight information, which can be passed to blend_animation() to play the animation.In other words, multiple calls to blend_animation() will blend multiple animations. However, there is no time information. Time information must be managed by each AnimationNode individually. In this situation, it is sufficient for an AnimationNode to have a single NodeTimeInfo. For this reason, in Godot's AnimationTree, one AnimationNodeAnimation calls only one blend_animation().

If you want to manage the time of multiple animations in one AnimationNode, it means you need multiple NodeTimeInfo, so you need to write a full-scratch struct or something to manage the time information. Therefore, I recommended having an internal AnimationNodeAnimation for each Animation like BlendSpace2D, and managing only its seek and weight in motion matching.

GuilhermeGSousa commented 1 week ago

Done! Yey!