Skip to content
This repository has been archived by the owner on Nov 14, 2024. It is now read-only.

Commit

Permalink
Merge pull request #22 from V-Sekai/motion-maching
Browse files Browse the repository at this point in the history
Add motion matching.
  • Loading branch information
fire authored Nov 3, 2024
2 parents 44dd36d + b1a353a commit 8fe19f2
Show file tree
Hide file tree
Showing 60 changed files with 4,533 additions and 4 deletions.
4 changes: 2 additions & 2 deletions godot/.gitrepo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/V-Sekai/godot.git
branch = groups-4.4
commit = b39f5c504d42c4f2342b6e543ce726be7086831f
parent = ec3a7471acf2e85dbc612384c337bec43c14e16f
commit = 594de0a65a2d1e595c96c16ad74dc9fb487eea2e
parent = 39aa131db43c8f1f934d29e80a68750f46b67b3b
method = merge
cmdver = 0.4.6
4 changes: 2 additions & 2 deletions godot/modules/many_bone_ik/.gitrepo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/V-Sekai/many_bone_ik.git
branch = main
commit = 55050bf851e3bbb90aaf857528616090f593f21b
parent = 7a47e1cbc07174a2a1986a5a2e42071e852fafe1
commit = ad2e65ba6c63924d61171ef2b25c46cb5a9f9edb
parent = ccfdadee38e32204dd2f5ac00fba4995ff461c7e
method = merge
cmdver = 0.4.6
6 changes: 6 additions & 0 deletions godot/modules/many_bone_ik/doc_classes/ManyBoneIK3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@
Registers the skeleton to the IK system. This should be called after all bones and constraints have been added to the system.
</description>
</method>
<method name="remove_constraint_at_index">
<return type="void" />
<param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="reset_constraints">
<return type="void" />
<description>
Expand Down
14 changes: 14 additions & 0 deletions godot/modules/many_bone_ik/src/many_bone_ik_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ void ManyBoneIK3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_orientation_transform_of_constraint", "index", "transform"), &ManyBoneIK3D::set_orientation_transform_of_constraint);
ClassDB::bind_method(D_METHOD("get_direction_transform_of_bone", "index"), &ManyBoneIK3D::get_direction_transform_of_bone);
ClassDB::bind_method(D_METHOD("set_direction_transform_of_bone", "index", "transform"), &ManyBoneIK3D::set_direction_transform_of_bone);
ClassDB::bind_method(D_METHOD("remove_constraint_at_index", "index"), &ManyBoneIK3D::remove_pin_at_index);
ClassDB::bind_method(D_METHOD("register_skeleton"), &ManyBoneIK3D::register_skeleton);
ClassDB::bind_method(D_METHOD("reset_constraints"), &ManyBoneIK3D::reset_constraints);
ClassDB::bind_method(D_METHOD("set_dirty"), &ManyBoneIK3D::set_dirty);
Expand Down Expand Up @@ -736,6 +737,19 @@ int32_t ManyBoneIK3D::find_constraint(String p_string) const {
return -1;
}

void ManyBoneIK3D::remove_pin_at_index(int32_t p_index) {
ERR_FAIL_INDEX(p_index, constraint_count);

constraint_names.remove_at(p_index);
kusudama_open_cone_count.remove_at(p_index);
kusudama_open_cones.remove_at(p_index);
joint_twist.remove_at(p_index);

constraint_count--;

set_dirty();
}

void ManyBoneIK3D::_set_bone_count(int32_t p_count) {
bone_damp.resize(p_count);
for (int32_t bone_i = p_count; bone_i-- > bone_count;) {
Expand Down
1 change: 1 addition & 0 deletions godot/modules/many_bone_ik/src/many_bone_ik_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class ManyBoneIK3D : public SkeletonModifier3D {
void queue_print_skeleton();
int32_t get_pin_count() const;
void set_pin_count(int32_t p_pin_count);
void remove_pin_at_index(int32_t p_index);
void set_pin_bone_name(int32_t p_pin_index, const String &p_bone);
StringName get_pin_bone_name(int32_t p_effector_index) const;
void set_pin_node_path(int32_t p_effector_index, NodePath p_node_path);
Expand Down
25 changes: 25 additions & 0 deletions godot/modules/motion_matching/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Language: Cpp
BasedOnStyle: LLVM
IndentWidth: 4
UseTab: Never
ColumnLimit: 0
AccessModifierOffset: -4
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
PointerAlignment: Left
SortIncludes: true
32 changes: 32 additions & 0 deletions godot/modules/motion_matching/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.sconsign.dblite

bin

*.os

*.obj

*.dll
*.exp
*.lib
*.ilk
*.pdb
*.so
*.universal
*.dylib
*.wasm
*.plist
*.enabled
*.tmp
*.TMP

.vscode
.cache

compile_commands.json

# Ignored demos
demo_*/

# Python
__pycache__
12 changes: 12 additions & 0 deletions godot/modules/motion_matching/.gitrepo
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; DO NOT EDIT (unless you know what you are doing)
;
; This subdirectory is a git "subrepo", and this file is maintained by the
; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme
;
[subrepo]
remote = https://github.com/GuilhermeGSousa/godot-motion-matching.git
branch = engine-module
commit = 3fbb34f56e99da4a7aca16142e40fd75f66c4e46
parent = 24cb8e640b8ec0c18ba00bc9716156e6f4576691
method = merge
cmdver = 0.4.6
40 changes: 40 additions & 0 deletions godot/modules/motion_matching/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Motion Matching for Godot 4.3

![](https://github.com/GuilhermeGSousa/godot-motion-matching/blob/master/motion_matching_demo.gif)

A motion matching implementation in Godot 4.3, implemented following [Dan Holden's article](https://www.theorangeduck.com/page/code-vs-data-driven-displacement).

:warning: **This repo is a work in progress!** :warning:

### Demo
The demo has now moved to a separate repository. You can find it [here!](https://github.com/GuilhermeGSousa/godot-motion-matching-demo).

### Wiki
[You can find this repo's wiki here!](https://github.com/GuilhermeGSousa/godot-motion-matching/wiki)

### Features
You'll find on this repo:
- A plugin that allow you to run motion matching queries on an animation dataset!
- A `CharacterBody3D` implementing a simple movement logic.
- Trajectory generation, including collisions and environmental checks.
- An editor to bake and visualize motion matching features.
- Blending nodes to qllow you to smoothly transition when switching animations.

### Credits
I want to thank all the contributors that made this project possible!

[Fire](https://github.com/fire)

[GeorgeS](https://github.com/GeorgeS2019)

[Remi](https://github.com/Remi123)

[Roberts Kalnins](https://github.com/rkalnins)

### Sources

- [Road to Next Gen Animation - GDC Talk](https://www.gdcvault.com/play/1023280/Motion-Matching-and-The-Road)
- [Simon Clavet's implementation video](https://www.youtube.com/watch?v=jcpIrw38E-s&ab_channel=SimonClavet)
- [Orange Duck's Blog](https://theorangeduck.com/)
- [Remi's Motion Matching implementation](https://github.com/Remi123/MotionMatching)
- Demo data taken from [O3DE Motion Matching Implementation](https://github.com/o3de/o3de/tree/development/Gems/MotionMatching)
19 changes: 19 additions & 0 deletions godot/modules/motion_matching/SCsub
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python
from glob import glob
from pathlib import Path

Import('env')

env.Append(CPPPATH=["src/"])
sources = Glob("*.cpp")
sources += Glob("src/*.cpp")
sources += Glob("src/features/*.cpp")
sources += Glob("src/math/*.cpp")
sources += Glob("src/modifiers/*.cpp")
sources += Glob("src/synchronizers/*.cpp")

module_env = env.Clone()
module_env.add_source_files(env.modules_sources, sources)

if env.editor_build:
module_env.add_source_files(env.modules_sources, "editor/*.cpp")
26 changes: 26 additions & 0 deletions godot/modules/motion_matching/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
def can_build(env, platform):
return True


def configure(env):
pass


def get_doc_classes():
return [
"DampedSkeletonModifier",
"MMAnimationLibrary",
"MMBoneDataFeature",
"MMCharacter",
"MMClampSynchronizer",
"MMFeature",
"MMRootMotionSynchronizer",
"MMSynchronizer",
"MMTrajectoryFeature",
"MMAnimationNode",
"MMQueryInput",
]


def get_doc_path():
return "doc_classes"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="DampedSkeletonModifier" inherits="SkeletonModifier3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<members>
<member name="halflife" type="float" setter="set_halflife" getter="get_halflife" default="0.1">
</member>
</members>
</class>
21 changes: 21 additions & 0 deletions godot/modules/motion_matching/doc_classes/MMAnimationLibrary.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MMAnimationLibrary" inherits="AnimationLibrary" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<members>
<member name="db_anim_index" type="PackedInt32Array" setter="set_db_anim_index" getter="get_db_anim_index" default="PackedInt32Array()">
</member>
<member name="db_time_index" type="PackedFloat32Array" setter="set_db_time_index" getter="get_db_time_index" default="PackedFloat32Array()">
</member>
<member name="features" type="MMFeature[]" setter="set_features" getter="get_features" default="[]">
</member>
<member name="motion_data" type="PackedFloat32Array" setter="set_motion_data" getter="get_motion_data" default="PackedFloat32Array()">
</member>
<member name="sampling_rate" type="float" setter="set_sampling_rate" getter="get_sampling_rate" default="1.0">
</member>
</members>
</class>
15 changes: 15 additions & 0 deletions godot/modules/motion_matching/doc_classes/MMAnimationNode.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MMAnimationNode" inherits="AnimationRootNode" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<members>
<member name="library" type="StringName" setter="set_library" getter="get_library" default="&amp;&quot;&quot;">
</member>
<member name="query_frequency" type="float" setter="set_query_frequency" getter="get_query_frequency" default="2.0">
</member>
</members>
</class>
13 changes: 13 additions & 0 deletions godot/modules/motion_matching/doc_classes/MMBoneDataFeature.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MMBoneDataFeature" inherits="MMFeature" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<members>
<member name="bone_names" type="PackedStringArray" setter="set_bone_names" getter="get_bone_names" default="PackedStringArray()">
</member>
</members>
</class>
75 changes: 75 additions & 0 deletions godot/modules/motion_matching/doc_classes/MMCharacter.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MMCharacter" inherits="CharacterBody3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A [CharacterBody3D] that provides the necessary functionality to use motion matching.
</brief_description>
<description>
[MMCharacter] that characters that use [Skeleton3D] to be animated through motion matching. Motion matching works by searching for the best animation in a database of animations that matches the current state of the character. This node is responsible for compiling the character's state, and send it to an [AnimationTree] to run motion matching searches.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_skeleton_state" qualifiers="const">
<return type="Dictionary[]" />
<description>
Returns an array of dictionaries each containing the [code]position[/code] and [code]velocity[/code] of each bone. Position and velocity are both [Vector3]s, and are relative to the skeleton's root bone.
</description>
</method>
<method name="get_trajectory" qualifiers="const">
<return type="Dictionary[]" />
<description>
Returns an array of dictionaries describing the character's trajectory. Each dictionary contains the [code]position[/code], [code]velocity[/code], [code]facing[/code] and [code]on_floor[/code] at given future point in time.
</description>
</method>
<method name="get_trajectory_history" qualifiers="const">
<return type="Dictionary[]" />
<description>
Returns an array of dictionaries describing the character's past trajectory. Each dictionary contains the [code]position[/code], [code]velocity[/code], [code]facing[/code] and [code]on_floor[/code] at given past point.
</description>
</method>
</methods>
<members>
<member name="animation_tree" type="AnimationTree" setter="set_animation_tree" getter="get_animation_tree">
</member>
<member name="check_environment" type="bool" setter="set_check_environment" getter="get_check_environment" default="true">
Used to enable or disable environmental checks along the character's trajectory. When enabled, trajectory generation will also consider collisions and gravity.
</member>
<member name="halflife" type="float" setter="set_halflife" getter="get_halflife" default="0.5">
Describes the time it takes for the character's current velocity to reach its target velocity. Higher values will make the character's movement (and trajectory) smoother, but also less responsive.
</member>
<member name="history_delta_time" type="float" setter="set_history_delta_time" getter="get_history_delta_time" default="0.5">
Time between each point in the trajectory history.
</member>
<member name="history_point_count" type="int" setter="set_history_point_count" getter="get_history_point_count" default="3">
Number of past points to store in the trajectory history.
</member>
<member name="is_strafing" type="bool" setter="set_is_strafing" getter="get_is_strafing" default="false">
When enabled, the character's facing direction on every trajectory point will be set to [member strafe_facing]. This may be useful to implement strafing movement.
When disabled, the character's facing direction will be calculated based on its velocity.
</member>
<member name="skeleton" type="Skeleton3D" setter="set_skeleton" getter="get_skeleton">
</member>
<member name="strafe_facing" type="float" setter="set_strafe_facing" getter="get_strafe_facing" default="0.0">
When [member is_strafing] is enabled, this value will be used as the facing direction on every trajectory point. When implementing strafing movement, this value is typically set to to the camera's facing direction.
</member>
<member name="synchronizer" type="MMSynchronizer" setter="set_synchronizer" getter="get_synchronizer">
The [MMSynchronizer] that will be used to synchronize the character to with its skeleton.
</member>
<member name="target_velocity" type="Vector3" setter="set_target_velocity" getter="get_target_velocity" default="Vector3(0, 0, 0)">
The character's target velocity. The character's velocity will be interpolated towards this value over time, controlled by [member halflife].
</member>
<member name="trajectory_delta_time" type="float" setter="set_trajectory_delta_time" getter="get_trajectory_delta_time" default="0.5">
Time between each point in the trajectory.
</member>
<member name="trajectory_point_count" type="int" setter="set_trajectory_point_count" getter="get_trajectory_point_count" default="10">
Number of future points to generate in the trajectory.
</member>
</members>
<signals>
<signal name="on_query_result">
<param index="0" name="data" type="Dictionary" />
<description>
</description>
</signal>
</signals>
</class>
13 changes: 13 additions & 0 deletions godot/modules/motion_matching/doc_classes/MMClampSynchronizer.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MMClampSynchronizer" inherits="MMSynchronizer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<members>
<member name="clamp_distance" type="float" setter="set_clamp_distance" getter="get_clamp_distance" default="10.0">
</member>
</members>
</class>
Loading

0 comments on commit 8fe19f2

Please sign in to comment.