Browse Source

Merge pull request #63802 from TokageItLab/curve-transition

Rémi Verschelde 3 years ago
parent
commit
9c567a0604

+ 3 - 0
doc/classes/AnimationNodeStateMachineTransition.xml

@@ -37,6 +37,9 @@
 		<member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0">
 			The transition type.
 		</member>
+		<member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
+			Ease curve for better control over cross-fade between this state and the next.
+		</member>
 		<member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0">
 			The time to cross-fade between this state and the next.
 		</member>

+ 3 - 1
doc/classes/AnimationNodeTransition.xml

@@ -46,7 +46,9 @@
 		<member name="input_count" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
 			The number of available input ports for this node.
 		</member>
-		<member name="xfade_time" type="float" setter="set_cross_fade_time" getter="get_cross_fade_time" default="0.0">
+		<member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
+		</member>
+		<member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0">
 			Cross-fading time (in seconds) between each animation connected to the inputs.
 		</member>
 	</members>

+ 25 - 10
scene/animation/animation_blend_tree.cpp

@@ -676,12 +676,20 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
 	return inputs[p_input].name;
 }
 
-void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
-	xfade = p_fade;
+void AnimationNodeTransition::set_xfade_time(float p_fade) {
+	xfade_time = p_fade;
 }
 
-float AnimationNodeTransition::get_cross_fade_time() const {
-	return xfade;
+float AnimationNodeTransition::get_xfade_time() const {
+	return xfade_time;
+}
+
+void AnimationNodeTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
+	xfade_curve = p_curve;
+}
+
+Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
+	return xfade_curve;
 }
 
 void AnimationNodeTransition::set_from_start(bool p_from_start) {
@@ -707,7 +715,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
 		set_parameter(this->prev, prev_current);
 
 		prev = prev_current;
-		prev_xfading = xfade;
+		prev_xfading = xfade_time;
 		time = 0;
 		switched = true;
 	}
@@ -734,13 +742,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
 			time += p_time;
 		}
 
-		if (inputs[current].auto_advance && rem <= xfade) {
+		if (inputs[current].auto_advance && rem <= xfade_time) {
 			set_parameter(this->current, (current + 1) % enabled_inputs);
 		}
 
 	} else { // cross-fading from prev to current
 
-		float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
+		float blend = xfade_time == 0 ? 0 : (prev_xfading / xfade_time);
+		if (xfade_curve.is_valid()) {
+			blend = xfade_curve->interpolate(blend);
+		}
 
 		if (from_start && !p_seek && switched) { //just switched, seek to start of current
 
@@ -790,14 +801,18 @@ void AnimationNodeTransition::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
 	ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
 
-	ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
-	ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
+	ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
+	ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
+
+	ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
+	ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
 
 	ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
 	ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
 
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_cross_fade_time", "get_cross_fade_time");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start");
 
 	for (int i = 0; i < MAX_INPUTS; i++) {

+ 7 - 3
scene/animation/animation_blend_tree.h

@@ -297,7 +297,8 @@ class AnimationNodeTransition : public AnimationNodeSync {
 	StringName current = PNAME("current");
 	StringName prev_current = "prev_current";
 
-	float xfade = 0.0;
+	float xfade_time = 0.0;
+	Ref<Curve> xfade_curve;
 	bool from_start = true;
 
 	void _update_inputs();
@@ -321,8 +322,11 @@ public:
 	void set_input_caption(int p_input, const String &p_name);
 	String get_input_caption(int p_input) const;
 
-	void set_cross_fade_time(float p_fade);
-	float get_cross_fade_time() const;
+	void set_xfade_time(float p_fade);
+	float get_xfade_time() const;
+
+	void set_xfade_curve(const Ref<Curve> &p_curve);
+	Ref<Curve> get_xfade_curve() const;
 
 	void set_from_start(bool p_from_start);
 	bool is_from_start() const;

+ 19 - 2
scene/animation/animation_node_state_machine.cpp

@@ -98,12 +98,20 @@ NodePath AnimationNodeStateMachineTransition::get_advance_expression_base_node()
 
 void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) {
 	ERR_FAIL_COND(p_xfade < 0);
-	xfade = p_xfade;
+	xfade_time = p_xfade;
 	emit_changed();
 }
 
 float AnimationNodeStateMachineTransition::get_xfade_time() const {
-	return xfade;
+	return xfade_time;
+}
+
+void AnimationNodeStateMachineTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
+	xfade_curve = p_curve;
+}
+
+Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const {
+	return xfade_curve;
 }
 
 void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) {
@@ -137,6 +145,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time);
 	ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time);
 
+	ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve);
+	ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve);
+
 	ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled);
 	ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled);
 
@@ -150,6 +161,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationNodeStateMachineTransition::get_advance_expression_base_node);
 
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
 	ADD_GROUP("Switch", "");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
@@ -420,6 +432,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
 		}
 	}
 
+	if (current_curve.is_valid()) {
+		fade_blend = current_curve->interpolate(fade_blend);
+	}
 	float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true);
 
 	if (fading_from != StringName()) {
@@ -450,6 +465,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
 
 			if (p_state_machine->transitions[i].local_from == current && p_state_machine->transitions[i].local_to == path[0]) {
 				next_xfade = p_state_machine->transitions[i].transition->get_xfade_time();
+				current_curve = p_state_machine->transitions[i].transition->get_xfade_curve();
 				switch_mode = p_state_machine->transitions[i].transition->get_switch_mode();
 				next = path[0];
 			}
@@ -504,6 +520,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
 			tr.to = String(p_state_machine->transitions[auto_advance_to].to).replace_first("../", "");
 			tr.next = p_state_machine->transitions[auto_advance_to].to;
 			current_transition = tr;
+			current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve();
 			next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time();
 			switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode();
 		}

+ 6 - 1
scene/animation/animation_node_state_machine.h

@@ -49,7 +49,8 @@ private:
 	bool auto_advance = false;
 	StringName advance_condition;
 	StringName advance_condition_name;
-	float xfade = 0.0;
+	float xfade_time = 0.0;
+	Ref<Curve> xfade_curve;
 	bool disabled = false;
 	int priority = 1;
 	String advance_expression;
@@ -82,6 +83,9 @@ public:
 	void set_xfade_time(float p_xfade);
 	float get_xfade_time() const;
 
+	void set_xfade_curve(const Ref<Curve> &p_curve);
+	Ref<Curve> get_xfade_curve() const;
+
 	void set_disabled(bool p_disabled);
 	bool is_disabled() const;
 
@@ -117,6 +121,7 @@ class AnimationNodeStateMachinePlayback : public Resource {
 
 	StringName current;
 	Transition current_transition;
+	Ref<Curve> current_curve;
 	bool force_auto_advance = false;
 
 	StringName fading_from;