Added demo, otherwise WIP.
Also needs AnimationMixer to be modified such that SyncedAnimationGraph is a friend class of AnimationMixer.
This commit is contained in:
parent
9a9adfbfb4
commit
c642fa2a04
29
.gitignore
vendored
29
.gitignore
vendored
@ -1,2 +1,31 @@
|
|||||||
.*swp
|
.*swp
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
||||||
|
# Godot 4+ specific ignores
|
||||||
|
demo/.godot/
|
||||||
|
demo/android/
|
||||||
|
|
||||||
|
demo/.nomedia
|
||||||
|
|
||||||
|
# Godot-specific ignores
|
||||||
|
demo/.import/
|
||||||
|
demo/export.cfg
|
||||||
|
demo/export_credentials.cfg
|
||||||
|
demo/*.tmp
|
||||||
|
|
||||||
|
# Imported translations (automatically generated from CSV files)
|
||||||
|
demo/*.translation
|
||||||
|
|
||||||
|
# Mono-specific ignores
|
||||||
|
demo/.mono/
|
||||||
|
demo/data_*/
|
||||||
|
demo/mono_crash.*.json
|
||||||
|
|
||||||
|
/demo/assets/MixamoAmy_Ch46_1001_Diffuse.png
|
||||||
|
/demo/assets/MixamoAmy_Ch46_1001_Diffuse.png.import
|
||||||
|
/demo/assets/MixamoAmy_Ch46_1001_Glossiness.png
|
||||||
|
/demo/assets/MixamoAmy_Ch46_1001_Glossiness.png.import
|
||||||
|
/demo/assets/MixamoAmy_Ch46_1001_Normal.png
|
||||||
|
/demo/assets/MixamoAmy_Ch46_1001_Normal.png.import
|
||||||
|
/demo/assets/MixamoAmy_Image.png
|
||||||
|
/demo/assets/MixamoAmy_Image.png.import
|
||||||
|
|||||||
17
README.md
Normal file
17
README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Synced Animation Graphs for Godot
|
||||||
|
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
1. Given an animation "Walk" with a call-method track and given that it is used as an input to a Blend2 node: will the
|
||||||
|
method be called twice?
|
||||||
|
1. a)
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
|
||||||
|
1. Dynamic Track Caches
|
||||||
|
|
||||||
|
When AnimationMixer performs blends it c
|
||||||
|
|
||||||
|
AnimationMixer still has all sampled Animations and therefore their Tracks individually. However for the SAG
|
||||||
|
evaluation all operations are
|
||||||
4
demo/.editorconfig
Normal file
4
demo/.editorconfig
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
20
demo/.gitignore
vendored
Normal file
20
demo/.gitignore
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
/android/
|
||||||
|
|
||||||
|
.nomedia
|
||||||
|
|
||||||
|
# Godot-specific ignores
|
||||||
|
.import/
|
||||||
|
export.cfg
|
||||||
|
export_credentials.cfg
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# Imported translations (automatically generated from CSV files)
|
||||||
|
*.translation
|
||||||
|
|
||||||
|
# Mono-specific ignores
|
||||||
|
.mono/
|
||||||
|
data_*/
|
||||||
|
mono_crash.*.json
|
||||||
|
|
||||||
BIN
demo/animation_library.res
Normal file
BIN
demo/animation_library.res
Normal file
Binary file not shown.
BIN
demo/assets/MixamoAmy.glb
Normal file
BIN
demo/assets/MixamoAmy.glb
Normal file
Binary file not shown.
42
demo/assets/MixamoAmy.glb.import
Normal file
42
demo/assets/MixamoAmy.glb.import
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://d1xcqdqr1qeu6"
|
||||||
|
path="res://.godot/imported/MixamoAmy.glb-5f8a7101bbea7c3cd32f3ebd9335cd1a.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/MixamoAmy.glb"
|
||||||
|
dest_files=["res://.godot/imported/MixamoAmy.glb-5f8a7101bbea7c3cd32f3ebd9335cd1a.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=true
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
gltf/naming_version=2
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
1
demo/icon.svg
Normal file
1
demo/icon.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 995 B |
43
demo/icon.svg.import
Normal file
43
demo/icon.svg.import
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://4q335xxs2p"
|
||||||
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
29
demo/main.tscn
Normal file
29
demo/main.tscn
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://svj53e2xoio"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://d1xcqdqr1qeu6" path="res://assets/MixamoAmy.glb" id="1_0xm2m"]
|
||||||
|
[ext_resource type="AnimationNodeBlendTree" uid="uid://c7o0gt3li5p4g" path="res://walk_limp_blend_tree.tres" id="2_h2yge"]
|
||||||
|
[ext_resource type="AnimationLibrary" uid="uid://dwubn740aqx51" path="res://animation_library.res" id="3_h2yge"]
|
||||||
|
|
||||||
|
[node name="Node3D" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="MixamoAmy" parent="." instance=ExtResource("1_0xm2m")]
|
||||||
|
|
||||||
|
[node name="AnimationTree" type="AnimationTree" parent="."]
|
||||||
|
active = false
|
||||||
|
root_node = NodePath("../MixamoAmy")
|
||||||
|
tree_root = ExtResource("2_h2yge")
|
||||||
|
anim_player = NodePath("../MixamoAmy/AnimationPlayer")
|
||||||
|
parameters/Blend2/blend_amount = 0.44
|
||||||
|
|
||||||
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||||
|
active = false
|
||||||
|
root_node = NodePath("../MixamoAmy")
|
||||||
|
libraries = {
|
||||||
|
&"animation_library": ExtResource("3_h2yge")
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="SyncedAnimationGraph" type="SyncedAnimationGraph" parent="."]
|
||||||
|
animation_tree = NodePath("../AnimationTree")
|
||||||
|
skeleton = NodePath("../MixamoAmy/Armature/Skeleton3D")
|
||||||
|
|
||||||
|
[editable path="MixamoAmy"]
|
||||||
19
demo/project.godot
Normal file
19
demo/project.godot
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=5
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Synced Blend Tree Test"
|
||||||
|
config/features=PackedStringArray("4.5", "Forward Plus")
|
||||||
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[dotnet]
|
||||||
|
|
||||||
|
project/assembly_name="Synced Blend Tree Test"
|
||||||
19
demo/walk_limp_blend_tree.tres
Normal file
19
demo/walk_limp_blend_tree.tres
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_resource type="AnimationNodeBlendTree" load_steps=4 format=3 uid="uid://c7o0gt3li5p4g"]
|
||||||
|
|
||||||
|
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_fpiwu"]
|
||||||
|
animation = &"Limping-InPlace"
|
||||||
|
|
||||||
|
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_4sffn"]
|
||||||
|
animation = &"Walk-InPlace"
|
||||||
|
|
||||||
|
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_w6plo"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
nodes/output/position = Vector2(860, 160)
|
||||||
|
nodes/Animation/node = SubResource("AnimationNodeAnimation_4sffn")
|
||||||
|
nodes/Animation/position = Vector2(280, 100)
|
||||||
|
"nodes/Animation 2/node" = SubResource("AnimationNodeAnimation_fpiwu")
|
||||||
|
"nodes/Animation 2/position" = Vector2(280, 300)
|
||||||
|
nodes/Blend2/node = SubResource("AnimationNodeBlend2_w6plo")
|
||||||
|
nodes/Blend2/position = Vector2(640, 160)
|
||||||
|
node_connections = [&"output", 0, &"Blend2", &"Blend2", 0, &"Animation", &"Blend2", 1, &"Animation 2"]
|
||||||
@ -1,35 +1,108 @@
|
|||||||
#include "synced_animation_graph.h"
|
#include "synced_animation_graph.h"
|
||||||
|
|
||||||
|
#include "core/os/time.h"
|
||||||
|
#include "scene/3d/skeleton_3d.h"
|
||||||
#include "scene/animation/animation_player.h"
|
#include "scene/animation/animation_player.h"
|
||||||
|
|
||||||
|
|
||||||
void SyncedAnimationGraph::_bind_methods() {
|
void SyncedAnimationGraph::_bind_methods() {
|
||||||
print_line(vformat("binding methods"));
|
print_line(vformat("binding methods"));
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_active", "active"), &SyncedAnimationGraph::set_active);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_active"), &SyncedAnimationGraph::is_active);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_callback_mode_process", "mode"), &SyncedAnimationGraph::set_callback_mode_process);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_callback_mode_process"), &SyncedAnimationGraph::get_callback_mode_process);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_callback_mode_method", "mode"), &SyncedAnimationGraph::set_callback_mode_method);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_callback_mode_method"), &SyncedAnimationGraph::get_callback_mode_method);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_animation_tree", "animation_tree"), &SyncedAnimationGraph::set_animation_tree);
|
ClassDB::bind_method(D_METHOD("set_animation_tree", "animation_tree"), &SyncedAnimationGraph::set_animation_tree);
|
||||||
ClassDB::bind_method(D_METHOD("get_animation_tree"), &SyncedAnimationGraph::get_animation_tree);
|
ClassDB::bind_method(D_METHOD("get_animation_tree"), &SyncedAnimationGraph::get_animation_tree);
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "animation_tree", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationTree"), "set_animation_tree", "get_animation_tree");
|
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "animation_tree", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationTree"), "set_animation_tree", "get_animation_tree");
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &SyncedAnimationGraph::set_skeleton);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_skeleton"), &SyncedAnimationGraph::get_skeleton);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_skeleton", "get_skeleton");
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo(SNAME("animation_tree_changed")));
|
ADD_SIGNAL(MethodInfo(SNAME("animation_tree_changed")));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncedAnimationGraph::_notification(int p_what) {
|
void SyncedAnimationGraph::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_READY: {
|
case Node::NOTIFICATION_READY: {
|
||||||
_set_process(true);
|
_set_process(true);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
case Node::NOTIFICATION_INTERNAL_PROCESS: {
|
||||||
_process_animation(get_process_delta_time());
|
if (active) {
|
||||||
|
_process_graph(get_process_delta_time());
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
case Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||||
_process_animation(get_physics_process_delta_time());
|
if (active) {
|
||||||
|
_process_graph(get_physics_process_delta_time());
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyncedAnimationGraph::set_active(bool p_active) {
|
||||||
|
if (active == p_active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
active = p_active;
|
||||||
|
_set_process(processing, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SyncedAnimationGraph::is_active() const {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncedAnimationGraph::set_callback_mode_process(AnimationMixer::AnimationCallbackModeProcess p_mode) {
|
||||||
|
if (callback_mode_process == p_mode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool was_active = is_active();
|
||||||
|
if (was_active) {
|
||||||
|
set_active(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback_mode_process = p_mode;
|
||||||
|
|
||||||
|
if (was_active) {
|
||||||
|
set_active(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationMixer::AnimationCallbackModeProcess SyncedAnimationGraph::get_callback_mode_process() const {
|
||||||
|
return callback_mode_process;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncedAnimationGraph::set_callback_mode_method(AnimationMixer::AnimationCallbackModeMethod p_mode) {
|
||||||
|
callback_mode_method = p_mode;
|
||||||
|
emit_signal(SNAME("mixer_updated"));
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationMixer::AnimationCallbackModeMethod SyncedAnimationGraph::get_callback_mode_method() const {
|
||||||
|
return callback_mode_method;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncedAnimationGraph::set_callback_mode_discrete(AnimationMixer::AnimationCallbackModeDiscrete p_mode) {
|
||||||
|
callback_mode_discrete = p_mode;
|
||||||
|
emit_signal(SNAME("mixer_updated"));
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationMixer::AnimationCallbackModeDiscrete SyncedAnimationGraph::get_callback_mode_discrete() const {
|
||||||
|
return callback_mode_discrete;
|
||||||
|
}
|
||||||
|
|
||||||
void SyncedAnimationGraph::set_animation_tree(const NodePath &p_path) {
|
void SyncedAnimationGraph::set_animation_tree(const NodePath &p_path) {
|
||||||
animation_tree = p_path;
|
animation_tree_path = p_path;
|
||||||
if (p_path.is_empty()) {
|
if (p_path.is_empty()) {
|
||||||
// set_root_node(SceneStringName(path_pp));
|
// set_root_node(SceneStringName(path_pp));
|
||||||
// while (animation_libraries.size()) {
|
// while (animation_libraries.size()) {
|
||||||
@ -40,31 +113,134 @@ void SyncedAnimationGraph::set_animation_tree(const NodePath &p_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NodePath SyncedAnimationGraph::get_animation_tree() const {
|
NodePath SyncedAnimationGraph::get_animation_tree() const {
|
||||||
return animation_tree;
|
return animation_tree_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyncedAnimationGraph::set_skeleton(const NodePath &p_path) {
|
||||||
|
skeleton_path = p_path;
|
||||||
|
if (p_path.is_empty()) {
|
||||||
|
// set_root_node(SceneStringName(path_pp));
|
||||||
|
// while (animation_libraries.size()) {
|
||||||
|
// remove_animation_library(animation_libraries[0].name);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
emit_signal(SNAME("skeleton_changed")); // Needs to unpin AnimationPlayerEditor.
|
||||||
|
}
|
||||||
|
|
||||||
|
NodePath SyncedAnimationGraph::get_skeleton() const {
|
||||||
|
return skeleton_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncedAnimationGraph::_ready(const NodePath &p_path) {
|
void SyncedAnimationGraph::_ready(const NodePath &p_path) {
|
||||||
print_line(vformat("synced animation graph ready!"));
|
print_line(vformat("synced animation graph ready!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncedAnimationGraph::_process_animation(double p_delta, bool p_update_only) {
|
void SyncedAnimationGraph::_process_graph(double p_delta, bool p_update_only) {
|
||||||
print_line(vformat("updating blend tree! %f", p_delta));
|
if (skeleton_path.is_empty()) {
|
||||||
// if (!root_animation_node.is_valid()) {
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
//
|
float current_time = Time::get_singleton()->get_unix_time_from_system();
|
||||||
// Ref<AnimationNodeBlendTree> blend_tree = root_animation_node;
|
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(get_node_or_null(skeleton_path));
|
||||||
// if (!blend_tree.is_valid()) {
|
if (!skeleton) {
|
||||||
// print_line("Cannot process animation graph: root not AnimationNodeBlendTree");
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
//
|
AnimationTree *animation_tree = Object::cast_to<AnimationTree>(get_node_or_null(animation_tree_path));
|
||||||
// LocalVector<StringName> node_names = blend_tree->get_node_list();
|
if (!animation_tree) {
|
||||||
// for (StringName node_name : node_names) {
|
return;
|
||||||
// print_line(vformat(" %s", node_name));
|
}
|
||||||
// }
|
|
||||||
|
Ref<Animation> animation = animation_tree->get_animation("Walk-InPlace");
|
||||||
|
if (!animation.is_valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LocalVector<AnimationMixer::TrackCache *> &track_num_to_track_cache = animation_track_num_to_track_cache[a];
|
||||||
|
const Vector<Animation::Track *> tracks = animation->get_tracks();
|
||||||
|
Animation::Track *const *tracks_ptr = tracks.ptr();
|
||||||
|
// real_t a_length = animation->get_length();
|
||||||
|
int count = tracks.size();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
const Animation::Track *animation_track = tracks_ptr[i];
|
||||||
|
if (!animation_track->enabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Animation::TrackType ttype = animation_track->type;
|
||||||
|
switch (ttype) {
|
||||||
|
case Animation::TYPE_POSITION_3D: {
|
||||||
|
AnimationMixer::TrackCacheTransform *track_xform = memnew(AnimationMixer::TrackCacheTransform);
|
||||||
|
track_xform->type = Animation::TYPE_POSITION_3D;
|
||||||
|
track_xform->bone_idx = -1;
|
||||||
|
track_xform->skeleton_id = skeleton->get_instance_id();
|
||||||
|
NodePath path = animation->track_get_path(i);
|
||||||
|
|
||||||
|
double animation_time = Math::fposmod(current_time, animation->get_length());
|
||||||
|
if (path.get_subname_count() == 1) {
|
||||||
|
int bone_idx = skeleton->find_bone(path.get_subname(0));
|
||||||
|
if (bone_idx != -1) {
|
||||||
|
track_xform->bone_idx = bone_idx;
|
||||||
|
Vector3 pos;
|
||||||
|
animation->try_position_track_interpolate(i, animation_time, &pos);
|
||||||
|
skeleton->set_bone_pose_position(bone_idx, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Animation::TYPE_ROTATION_3D: {
|
||||||
|
AnimationMixer::TrackCacheTransform *track_xform = memnew(AnimationMixer::TrackCacheTransform);
|
||||||
|
track_xform->type = Animation::TYPE_POSITION_3D;
|
||||||
|
track_xform->bone_idx = -1;
|
||||||
|
track_xform->skeleton_id = skeleton->get_instance_id();
|
||||||
|
NodePath path = animation->track_get_path(i);
|
||||||
|
|
||||||
|
double animation_time = Math::fposmod(current_time, animation->get_length());
|
||||||
|
if (path.get_subname_count() == 1) {
|
||||||
|
int bone_idx = skeleton->find_bone(path.get_subname(0));
|
||||||
|
if (bone_idx != -1) {
|
||||||
|
track_xform->bone_idx = bone_idx;
|
||||||
|
Quaternion rot;
|
||||||
|
animation->try_rotation_track_interpolate(i, animation_time, &rot);
|
||||||
|
skeleton->set_bone_pose_rotation(bone_idx, rot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skeleton->set_bone_pose_position(3, Vector3(sin(current_time) * 10., 0., 0.));
|
||||||
|
skeleton->force_update_all_bone_transforms();
|
||||||
|
|
||||||
|
|
||||||
|
// TrackCache *track = track_num_to_track_cache[i];
|
||||||
|
// if (track == nullptr) {
|
||||||
|
// continue; // No path, but avoid error spamming.
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (!root_animation_node.is_valid()) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Ref<AnimationNodeBlendTree> blend_tree = root_animation_node;
|
||||||
|
// if (!blend_tree.is_valid()) {
|
||||||
|
// print_line("Cannot process animation graph: root not AnimationNodeBlendTree");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// LocalVector<StringName> node_names = blend_tree->get_node_list();
|
||||||
|
// for (StringName node_name : node_names) {
|
||||||
|
// print_line(vformat(" %s", node_name));
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
void SyncedAnimationGraph::_set_process(bool p_process, bool p_force) {
|
void SyncedAnimationGraph::_set_process(bool p_process, bool p_force) {
|
||||||
if (processing == p_process && !p_force) {
|
if (processing == p_process && !p_force) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -7,19 +7,44 @@ class SyncedAnimationGraph : public Node {
|
|||||||
GDCLASS(SyncedAnimationGraph, Node);
|
GDCLASS(SyncedAnimationGraph, Node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodePath animation_tree;
|
NodePath animation_tree_path;
|
||||||
bool processing = false;
|
NodePath skeleton_path;
|
||||||
|
|
||||||
void set_animation_tree(const NodePath &p_path);
|
void set_animation_tree(const NodePath &p_path);
|
||||||
NodePath get_animation_tree() const;
|
NodePath get_animation_tree() const;
|
||||||
|
|
||||||
|
void set_skeleton(const NodePath &p_path);
|
||||||
|
NodePath get_skeleton() const;
|
||||||
|
|
||||||
|
// AnimationMixer::TrackCache
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
/* ---- General settings for animation ---- */
|
||||||
|
AnimationMixer::AnimationCallbackModeProcess callback_mode_process = AnimationMixer::ANIMATION_CALLBACK_MODE_PROCESS_IDLE;
|
||||||
|
AnimationMixer::AnimationCallbackModeMethod callback_mode_method = AnimationMixer::ANIMATION_CALLBACK_MODE_METHOD_DEFERRED;
|
||||||
|
AnimationMixer::AnimationCallbackModeDiscrete callback_mode_discrete = AnimationMixer::ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE;
|
||||||
|
|
||||||
|
bool processing = false;
|
||||||
|
bool active = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void _ready(const NodePath &p_path);
|
void _ready(const NodePath &p_path);
|
||||||
void _process_animation(double p_delta, bool p_update_only = false);
|
void _process_graph(double p_delta, bool p_update_only = false);
|
||||||
|
|
||||||
|
void set_active(bool p_active);
|
||||||
|
bool is_active() const;
|
||||||
|
|
||||||
|
void set_callback_mode_process(AnimationMixer::AnimationCallbackModeProcess p_mode);
|
||||||
|
AnimationMixer::AnimationCallbackModeProcess get_callback_mode_process() const;
|
||||||
|
|
||||||
|
void set_callback_mode_method(AnimationMixer::AnimationCallbackModeMethod p_mode);
|
||||||
|
AnimationMixer::AnimationCallbackModeMethod get_callback_mode_method() const;
|
||||||
|
|
||||||
|
void set_callback_mode_discrete(AnimationMixer::AnimationCallbackModeDiscrete p_mode);
|
||||||
|
AnimationMixer::AnimationCallbackModeDiscrete get_callback_mode_discrete() const;
|
||||||
|
|
||||||
SyncedAnimationGraph();
|
SyncedAnimationGraph();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user