Browse Source

Optimize animation blend tree process

Silc Renew 2 years ago
parent
commit
17ce879a15

+ 2 - 2
scene/animation/animation_blend_space_1d.cpp

@@ -309,8 +309,8 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_see
 		if (i == point_lower || i == point_higher) {
 			double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, weights[i], FILTER_IGNORE, true);
 			max_time_remaining = MAX(max_time_remaining, remaining);
-		} else {
-			blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+		} else if (sync) {
+			blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true);
 		}
 	}
 

+ 7 - 5
scene/animation/animation_blend_space_2d.cpp

@@ -512,8 +512,8 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
 				}
 			}
 
-			if (!found) {
-				blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+			if (sync && !found) {
+				blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true);
 			}
 		}
 	} else {
@@ -550,9 +550,11 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
 			mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
 		}
 
-		for (int i = 0; i < blend_points_used; i++) {
-			if (i != cur_closest) {
-				blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+		if (sync) {
+			for (int i = 0; i < blend_points_used; i++) {
+				if (i != cur_closest) {
+					blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true);
+				}
 			}
 		}
 	}

+ 5 - 3
scene/animation/animation_blend_tree.cpp

@@ -726,9 +726,11 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
 
 	double rem = 0.0;
 
-	for (int i = 0; i < enabled_inputs; i++) {
-		if (i != cur_current && i != cur_prev) {
-			blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
+	if (sync) {
+		for (int i = 0; i < enabled_inputs; i++) {
+			if (i != cur_current && i != cur_prev) {
+				blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, true);
+			}
 		}
 	}
 

+ 55 - 88
scene/animation/animation_tree.cpp

@@ -289,11 +289,8 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
 		new_path = String(parent->base_path) + String(p_subpath) + "/";
 	}
 
-	// If tracks for blending don't exist for one of the animations, Rest or RESET animation is blended as init animation instead.
-	// Then blend weight is 0 means that the init animation blend weight is 1.
-	// In that case, processing only the animation with the lacking track will not process the lacking track, and will not properly apply the Reset value.
-	// This means that all tracks which the animations in the branch that may be blended have must be processed.
-	// Therefore, the blending process must be executed even if the blend weight is 0.
+	// This process, which depends on p_sync is needed to process sync correctly in the case of
+	// that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.
 	if (!p_seek && !p_sync && !any_valid) {
 		return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_seek_root, p_connections);
 	}
@@ -596,6 +593,13 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
 
 						track = track_value;
 
+						// If a value track without a key is cached first, the initial value cannot be determined.
+						// It is a corner case, but which may cause problems with blending.
+						ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, "AnimationTree: '" + String(E) + "', value track:  '" + String(path) + "' must have at least one key to cache for blending.");
+						track_value->init_value = anim->track_get_key_value(i, 0);
+						track_value->init_value.zero();
+
+						// If there is a Reset Animation, it takes precedence by overwriting.
 						if (has_reset_anim) {
 							int rt = reset_anim->find_track(path, track_type);
 							if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
@@ -955,8 +959,44 @@ void AnimationTree::_process_graph(double p_delta) {
 	if (!state.valid) {
 		return; //state is not valid. do nothing.
 	}
-	//apply value/transform/bezier blends to track caches and execute method/audio/animation tracks
 
+	// Init all value/transform/blend/bezier tracks that track_cache has.
+	{
+		for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
+			TrackCache *track = K.value;
+
+			switch (track->type) {
+				case Animation::TYPE_POSITION_3D: {
+					TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
+					if (track->root_motion) {
+						t->loc = Vector3(0, 0, 0);
+						t->rot = Quaternion(0, 0, 0, 1);
+						t->scale = Vector3(0, 0, 0);
+					} else {
+						t->loc = t->init_loc;
+						t->rot = t->init_rot;
+						t->scale = t->init_scale;
+					}
+				} break;
+				case Animation::TYPE_BLEND_SHAPE: {
+					TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
+					t->value = t->init_value;
+				} break;
+				case Animation::TYPE_VALUE: {
+					TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
+					t->value = t->init_value;
+				} break;
+				case Animation::TYPE_BEZIER: {
+					TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
+					t->value = t->init_value;
+				} break;
+				default: {
+				} break;
+			}
+		}
+	}
+
+	// Apply value/transform/blend/bezier blends to track caches and execute method/audio/animation tracks.
 	{
 		bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();
 
@@ -968,7 +1008,7 @@ void AnimationTree::_process_graph(double p_delta) {
 			bool seeked = as.seeked;
 			int pingponged = as.pingponged;
 #ifndef _3D_DISABLED
-			bool backward = signbit(delta);
+			bool backward = signbit(delta); // This flag is required only for the root motion since it calculates the difference between the previous and current frames.
 			bool calc_root = !seeked || as.seek_root;
 #endif // _3D_DISABLED
 
@@ -978,37 +1018,29 @@ void AnimationTree::_process_graph(double p_delta) {
 				}
 
 				NodePath path = a->track_get_path(i);
-
 				ERR_CONTINUE(!track_cache.has(path));
-
 				TrackCache *track = track_cache[path];
 
+				ERR_CONTINUE(!state.track_map.has(path));
+				int blend_idx = state.track_map[path];
+				ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count);
+				real_t blend = (*as.track_blends)[blend_idx] * weight;
+				if (blend < CMP_EPSILON) {
+					continue; // Nothing to blend.
+				}
+
 				Animation::TrackType ttype = a->track_get_type(i);
 				if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) {
 					//broken animation, but avoid error spamming
 					continue;
 				}
-
 				track->root_motion = root_motion_track == path;
 
-				ERR_CONTINUE(!state.track_map.has(path));
-				int blend_idx = state.track_map[path];
-
-				ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count);
-
-				real_t blend = (*as.track_blends)[blend_idx] * weight;
-
 				switch (ttype) {
 					case Animation::TYPE_POSITION_3D: {
 #ifndef _3D_DISABLED
 						TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
 						if (track->root_motion && calc_root) {
-							if (t->process_pass != process_pass) {
-								t->process_pass = process_pass;
-								t->loc = Vector3(0, 0, 0);
-								t->rot = Quaternion(0, 0, 0, 1);
-								t->scale = Vector3(0, 0, 0);
-							}
 							double prev_time = time - delta;
 							if (!backward) {
 								if (prev_time < 0) {
@@ -1084,12 +1116,6 @@ void AnimationTree::_process_graph(double p_delta) {
 							prev_time = !backward ? 0 : (double)a->get_length();
 
 						} else {
-							if (t->process_pass != process_pass) {
-								t->process_pass = process_pass;
-								t->loc = t->init_loc;
-								t->rot = t->init_rot;
-								t->scale = t->init_scale;
-							}
 							Vector3 loc;
 
 							Error err = a->position_track_interpolate(i, time, &loc);
@@ -1106,12 +1132,6 @@ void AnimationTree::_process_graph(double p_delta) {
 #ifndef _3D_DISABLED
 						TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
 						if (track->root_motion && calc_root) {
-							if (t->process_pass != process_pass) {
-								t->process_pass = process_pass;
-								t->loc = Vector3(0, 0, 0);
-								t->rot = Quaternion(0, 0, 0, 1);
-								t->scale = Vector3(0, 0, 0);
-							}
 							double prev_time = time - delta;
 							if (!backward) {
 								if (prev_time < 0) {
@@ -1186,12 +1206,6 @@ void AnimationTree::_process_graph(double p_delta) {
 							prev_time = !backward ? 0 : (double)a->get_length();
 
 						} else {
-							if (t->process_pass != process_pass) {
-								t->process_pass = process_pass;
-								t->loc = t->init_loc;
-								t->rot = t->init_rot;
-								t->scale = t->init_scale;
-							}
 							Quaternion rot;
 
 							Error err = a->rotation_track_interpolate(i, time, &rot);
@@ -1208,12 +1222,6 @@ void AnimationTree::_process_graph(double p_delta) {
 #ifndef _3D_DISABLED
 						TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
 						if (track->root_motion && calc_root) {
-							if (t->process_pass != process_pass) {
-								t->process_pass = process_pass;
-								t->loc = Vector3(0, 0, 0);
-								t->rot = Quaternion(0, 0, 0, 1);
-								t->scale = Vector3(0, 0, 0);
-							}
 							double prev_time = time - delta;
 							if (!backward) {
 								if (prev_time < 0) {
@@ -1289,12 +1297,6 @@ void AnimationTree::_process_graph(double p_delta) {
 							prev_time = !backward ? 0 : (double)a->get_length();
 
 						} else {
-							if (t->process_pass != process_pass) {
-								t->process_pass = process_pass;
-								t->loc = t->init_loc;
-								t->rot = t->init_rot;
-								t->scale = t->init_scale;
-							}
 							Vector3 scale;
 
 							Error err = a->scale_track_interpolate(i, time, &scale);
@@ -1311,11 +1313,6 @@ void AnimationTree::_process_graph(double p_delta) {
 #ifndef _3D_DISABLED
 						TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
 
-						if (t->process_pass != process_pass) {
-							t->process_pass = process_pass;
-							t->value = t->init_value;
-						}
-
 						float value;
 
 						Error err = a->blend_shape_track_interpolate(i, time, &value);
@@ -1342,15 +1339,6 @@ void AnimationTree::_process_graph(double p_delta) {
 								continue;
 							}
 
-							if (t->process_pass != process_pass) {
-								t->process_pass = process_pass;
-								if (!t->init_value) {
-									t->init_value = value;
-									t->init_value.zero();
-								}
-								t->value = t->init_value;
-							}
-
 							// Special case for angle interpolation.
 							if (t->is_using_angle) {
 								// For blending consistency, it prevents rotation of more than 180 degrees from init_value.
@@ -1379,10 +1367,6 @@ void AnimationTree::_process_graph(double p_delta) {
 								}
 							}
 						} else {
-							if (blend < CMP_EPSILON) {
-								continue; //nothing to blend
-							}
-
 							if (seeked) {
 								int idx = a->track_find_key(i, time);
 								if (idx < 0) {
@@ -1404,9 +1388,6 @@ void AnimationTree::_process_graph(double p_delta) {
 
 					} break;
 					case Animation::TYPE_METHOD: {
-						if (blend < CMP_EPSILON) {
-							continue; //nothing to blend
-						}
 						TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);
 
 						if (seeked) {
@@ -1437,17 +1418,9 @@ void AnimationTree::_process_graph(double p_delta) {
 						real_t bezier = a->bezier_track_interpolate(i, time);
 						bezier = _post_process_key_value(a, i, bezier, t->object);
 
-						if (t->process_pass != process_pass) {
-							t->process_pass = process_pass;
-							t->value = t->init_value;
-						}
-
 						t->value += (bezier - t->init_value) * blend;
 					} break;
 					case Animation::TYPE_AUDIO: {
-						if (blend < CMP_EPSILON) {
-							continue; //nothing to blend
-						}
 						TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
 
 						if (seeked) {
@@ -1555,9 +1528,6 @@ void AnimationTree::_process_graph(double p_delta) {
 						t->object->call(SNAME("set_volume_db"), db);
 					} break;
 					case Animation::TYPE_ANIMATION: {
-						if (blend < CMP_EPSILON) {
-							continue; //nothing to blend
-						}
 						TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);
 
 						AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object);
@@ -1639,9 +1609,6 @@ void AnimationTree::_process_graph(double p_delta) {
 		// finally, set the tracks
 		for (const KeyValue<NodePath, TrackCache *> &K : track_cache) {
 			TrackCache *track = K.value;
-			if (track->process_pass != process_pass) {
-				continue; //not processed, ignore
-			}
 
 			switch (track->type) {
 				case Animation::TYPE_POSITION_3D: {

+ 0 - 1
scene/animation/animation_tree.h

@@ -190,7 +190,6 @@ private:
 	struct TrackCache {
 		bool root_motion = false;
 		uint64_t setup_pass = 0;
-		uint64_t process_pass = 0;
 		Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION;
 		Object *object = nullptr;
 		ObjectID object_id;