summaryrefslogtreecommitdiff
path: root/scene/animation
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation')
-rw-r--r--scene/animation/animation_player.cpp52
-rw-r--r--scene/animation/animation_player.h11
-rw-r--r--scene/animation/animation_tree.cpp62
-rw-r--r--scene/animation/animation_tree.h7
4 files changed, 131 insertions, 1 deletions
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 8407e0dd99..1f000d5f39 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -257,6 +257,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
ERR_CONTINUE_MSG(!child, "On Animation: '" + p_anim->name + "', couldn't resolve track: '" + String(a->track_get_path(i)) + "'."); // couldn't find the child node
ObjectID id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id();
int bone_idx = -1;
+ int blend_shape_idx = -1;
#ifndef _3D_DISABLED
if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton3D>(child)) {
@@ -266,6 +267,22 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
continue;
}
}
+
+ if (a->track_get_type(i) == Animation::TYPE_BLEND_SHAPE) {
+ MeshInstance3D *mi_3d = Object::cast_to<MeshInstance3D>(child);
+ if (!mi_3d) {
+ continue;
+ }
+ if (a->track_get_path(i).get_subname_count() != 1) {
+ continue;
+ }
+
+ blend_shape_idx = mi_3d->find_blend_shape_by_name(a->track_get_path(i).get_subname(0));
+ if (blend_shape_idx == -1) {
+ continue;
+ }
+ }
+
#endif // _3D_DISABLED
{
@@ -277,6 +294,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
TrackNodeCacheKey key;
key.id = id;
key.bone_idx = bone_idx;
+ key.blend_shape_idx = blend_shape_idx;
if (!node_cache_map.has(key)) {
node_cache_map[key] = TrackNodeCache();
@@ -334,6 +352,13 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
}
}
}
+
+ if (a->track_get_type(i) == Animation::TYPE_BLEND_SHAPE) {
+ // special cases and caches for transform tracks
+ node_cache->node_blend_shape = Object::cast_to<MeshInstance3D>(child);
+ node_cache->blend_shape_idx = blend_shape_idx;
+ }
+
#endif // _3D_DISABLED
if (a->track_get_type(i) == Animation::TYPE_VALUE) {
@@ -481,6 +506,31 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
#endif // _3D_DISABLED
} break;
+ case Animation::TYPE_BLEND_SHAPE: {
+#ifndef _3D_DISABLED
+ if (!nc->node_blend_shape) {
+ continue;
+ }
+
+ float blend;
+
+ Error err = a->blend_shape_track_interpolate(i, p_time, &blend);
+ //ERR_CONTINUE(err!=OK); //used for testing, should be removed
+
+ if (err != OK) {
+ continue;
+ }
+
+ if (nc->accum_pass != accum_pass) {
+ ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
+ nc->accum_pass = accum_pass;
+ cache_update[cache_update_size++] = nc;
+ nc->blend_shape_accum = blend;
+ } else {
+ nc->blend_shape_accum = Math::lerp(nc->blend_shape_accum, blend, p_interp);
+ }
+#endif // _3D_DISABLED
+ } break;
case Animation::TYPE_VALUE: {
if (!nc->node) {
continue;
@@ -947,6 +997,8 @@ void AnimationPlayer::_animation_update_transforms() {
nc->skeleton->set_bone_pose_scale(nc->bone_idx, nc->scale_accum);
}
+ } else if (nc->node_blend_shape) {
+ nc->node_blend_shape->set_blend_shape_value(nc->blend_shape_idx, nc->blend_shape_accum);
} else if (nc->node_3d) {
if (nc->loc_used) {
nc->node_3d->set_position(nc->loc_accum);
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index f8e72a67b6..21e309efe0 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -32,6 +32,7 @@
#define ANIMATION_PLAYER_H
#include "scene/2d/node_2d.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/animation.h"
@@ -99,6 +100,8 @@ private:
#ifndef _3D_DISABLED
Node3D *node_3d = nullptr;
Skeleton3D *skeleton = nullptr;
+ MeshInstance3D *node_blend_shape = nullptr;
+ int blend_shape_idx = -1;
#endif // _3D_DISABLED
int bone_idx = -1;
// accumulated transforms
@@ -110,6 +113,7 @@ private:
Vector3 loc_accum;
Quaternion rot_accum;
Vector3 scale_accum;
+ float blend_shape_accum = 0;
uint64_t accum_pass = 0;
bool audio_playing = false;
@@ -147,10 +151,15 @@ private:
struct TrackNodeCacheKey {
ObjectID id;
int bone_idx = -1;
+ int blend_shape_idx = -1;
inline bool operator<(const TrackNodeCacheKey &p_right) const {
if (id == p_right.id) {
- return bone_idx < p_right.bone_idx;
+ if (blend_shape_idx == p_right.blend_shape_idx) {
+ return bone_idx < p_right.bone_idx;
+ } else {
+ return blend_shape_idx < p_right.blend_shape_idx;
+ }
} else {
return id < p_right.id;
}
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index dd5fe46223..ccb5fa9472 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -640,6 +640,37 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
#endif // _3D_DISABLED
} break;
+ case Animation::TYPE_BLEND_SHAPE: {
+#ifndef _3D_DISABLED
+
+ if (path.get_subname_count() != 1) {
+ ERR_PRINT("AnimationTree: '" + String(E) + "', blend shape track does not contain a blend shape subname: '" + String(path) + "'");
+ continue;
+ }
+ MeshInstance3D *mesh_3d = Object::cast_to<MeshInstance3D>(child);
+
+ if (!mesh_3d) {
+ ERR_PRINT("AnimationTree: '" + String(E) + "', blend shape track does not point to MeshInstance3D: '" + String(path) + "'");
+ continue;
+ }
+
+ StringName blend_shape_name = path.get_subname(0);
+ int blend_shape_idx = mesh_3d->find_blend_shape_by_name(blend_shape_name);
+ if (blend_shape_idx == -1) {
+ ERR_PRINT("AnimationTree: '" + String(E) + "', blend shape track points to a non-existing name: '" + String(blend_shape_name) + "'");
+ continue;
+ }
+
+ TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape);
+
+ track_bshape->mesh_3d = mesh_3d;
+ track_bshape->shape_index = blend_shape_idx;
+
+ track_bshape->object = mesh_3d;
+ track_bshape->object_id = mesh_3d->get_instance_id();
+ track = track_bshape;
+#endif
+ } break;
case Animation::TYPE_METHOD: {
TrackCacheMethod *track_method = memnew(TrackCacheMethod);
@@ -1089,6 +1120,28 @@ void AnimationTree::_process_graph(real_t p_delta) {
}
#endif // _3D_DISABLED
} break;
+ case Animation::TYPE_BLEND_SHAPE: {
+#ifndef _3D_DISABLED
+ TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
+
+ if (t->process_pass != process_pass) {
+ t->process_pass = process_pass;
+ t->value = 0;
+ }
+
+ float value;
+
+ Error err = a->blend_shape_track_interpolate(i, time, &value);
+ //ERR_CONTINUE(err!=OK); //used for testing, should be removed
+
+ if (err != OK) {
+ continue;
+ }
+
+ t->value = Math::lerp(t->value, value, blend);
+
+#endif // _3D_DISABLED
+ } break;
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
@@ -1384,6 +1437,15 @@ void AnimationTree::_process_graph(real_t p_delta) {
}
#endif // _3D_DISABLED
} break;
+ case Animation::TYPE_BLEND_SHAPE: {
+#ifndef _3D_DISABLED
+ TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
+
+ if (t->mesh_3d) {
+ t->mesh_3d->set_blend_shape_value(t->shape_index, t->value);
+ }
+#endif // _3D_DISABLED
+ } break;
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index ed207dfe0c..21b49937a7 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -210,6 +210,13 @@ private:
}
};
+ struct TrackCacheBlendShape : public TrackCache {
+ MeshInstance3D *mesh_3d = nullptr;
+ float value = 0;
+ int shape_index = -1;
+ TrackCacheBlendShape() { type = Animation::TYPE_BLEND_SHAPE; }
+ };
+
struct TrackCacheValue : public TrackCache {
Variant value;
Vector<StringName> subpath;