Skip to content

Commit

Permalink
Cyclic Animation BlendSpaces (1D/2D)
Browse files Browse the repository at this point in the history
  • Loading branch information
marstaik committed Dec 8, 2019
1 parent b5fb7ce commit c30eb28
Show file tree
Hide file tree
Showing 12 changed files with 595 additions and 132 deletions.
10 changes: 9 additions & 1 deletion editor/plugins/animation_blend_space_1d_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "animation_blend_space_1d_editor.h"

#include "core/os/keyboard.h"
#include "scene/animation/animation_blend_space_cyclic_1d.h"
#include "scene/animation/animation_blend_tree.h"

StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
Expand All @@ -56,7 +57,14 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
animations_to_add.clear();

List<StringName> classes;
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);

// BlendSpaceCyclic1d can only use pure animation nodes (for now)
if (Object::cast_to<AnimationNodeBlendSpaceCyclic1D>(blend_space.ptr())) {
ClassDB::get_inheriters_from_class("AnimationNodeAnimation", &classes);
} else {
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
}

classes.sort_custom<StringName::AlphCompare>();

menu->add_submenu_item(TTR("Add Animation"), "animations");
Expand Down
10 changes: 9 additions & 1 deletion editor/plugins/animation_blend_space_2d_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "scene/animation/animation_blend_space_cyclic_2d.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
Expand Down Expand Up @@ -86,9 +87,16 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
animations_menu->clear();
animations_to_add.clear();
List<StringName> classes;

// BlendSpaceCyclic2d can only use pure animation nodes (for now)
if (Object::cast_to<AnimationNodeBlendSpaceCyclic2D>(blend_space.ptr())) {
ClassDB::get_inheriters_from_class("AnimationNodeAnimation", &classes);
} else {
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
}

classes.sort_custom<StringName::AlphCompare>();

ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "animations");

AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
Expand Down
2 changes: 2 additions & 0 deletions editor/plugins/animation_blend_tree_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
add_options.push_back(AddOption("BlendTree", "AnimationNodeBlendTree"));
add_options.push_back(AddOption("BlendSpace1D", "AnimationNodeBlendSpace1D"));
add_options.push_back(AddOption("BlendSpace2D", "AnimationNodeBlendSpace2D"));
add_options.push_back(AddOption("BlendSpaceCyclic1D", "AnimationNodeBlendSpaceCyclic1D"));
add_options.push_back(AddOption("BlendSpaceCyclic2D", "AnimationNodeBlendSpaceCyclic2D"));
add_options.push_back(AddOption("StateMachine", "AnimationNodeStateMachine"));
_update_options_menu();

Expand Down
101 changes: 47 additions & 54 deletions scene/animation/animation_blend_space_1d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,88 +221,81 @@ void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<Animatio
}
}

float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {
AnimationNodeBlendSpace1D::BlendWeights AnimationNodeBlendSpace1D::get_blend_values(const float p_blend_pos) const {

if (blend_points_used == 0) {
return 0.0;
}
BlendWeights values;

if (blend_points_used == 1) {
// only one point available, just play that animation
return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
}
float pos_lower = 1e20;
float pos_higher = 1e20;

float blend_pos = get_parameter(blend_position);

float weights[MAX_BLEND_POINTS] = {};

int point_lower = -1;
float pos_lower = 0.0;
int point_higher = -1;
float pos_higher = 0.0;

// find the closest two points to blend between
// Find the closest two points to blend between
for (int i = 0; i < blend_points_used; i++) {

float pos = blend_points[i].position;

if (pos <= blend_pos) {
if (point_lower == -1) {
point_lower = i;
pos_lower = pos;
} else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
point_lower = i;
if (pos <= p_blend_pos) {
if (values.points[0] == -1 || p_blend_pos - pos < p_blend_pos - pos_lower) {
values.points[0] = i;
pos_lower = pos;
}
} else {
if (point_higher == -1) {
point_higher = i;
pos_higher = pos;
} else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
point_higher = i;
if (values.points[1] == -1 || pos - p_blend_pos < pos_higher - p_blend_pos) {
values.points[1] = i;
pos_higher = pos;
}
}
}

// fill in weights

if (point_lower == -1 && point_higher != -1) {
// we are on the left side, no other point to the left
// we just play the next point.

weights[point_higher] = 1.0;
} else if (point_higher == -1) {
// we are on the right side, no other point to the right
// we just play the previous point
// We are on the left side, and there are no other point to the left,
// so we just max the blend of the higher point.
if (values.points[0] == -1 && values.points[1] != -1) {
values.weights[0] = 0.0;
values.weights[1] = 1.0;
return values;
}

weights[point_lower] = 1.0;
} else {
// There is no higher node, max the blend on the lowest point.
if (values.points[1] == -1) {
values.weights[0] = 1.0;
values.weights[1] = 0.0;
return values;
}

// we are between two points.
// figure out weights, then blend the animations
// We are in a state between two points.
// Figure out the linear blend percentage

float distance_between_points = pos_higher - pos_lower;
const float distance_between_points = pos_higher - pos_lower;
const float current_pos_inbetween = p_blend_pos - pos_lower;

float current_pos_inbetween = blend_pos - pos_lower;
values.weights[1] = current_pos_inbetween / distance_between_points;
values.weights[0] = 1 - values.weights[1];
return values;
}

float blend_percentage = current_pos_inbetween / distance_between_points;
float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {

float blend_lower = 1.0 - blend_percentage;
float blend_higher = blend_percentage;
if (blend_points_used == 0) {
return 0.0;
}

weights[point_lower] = blend_lower;
weights[point_higher] = blend_higher;
if (blend_points_used == 1) {
// only one point available, just play that animation
return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
}

// actually blend the animations now
const float blend_pos = get_parameter(blend_position);

const BlendWeights b_values = get_blend_values(blend_pos);

float max_time_remaining = 0.0;

for (int i = 0; i < blend_points_used; i++) {
float remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false);
for (int i = 0; i < 2; i++) {
if (b_values.weights[i] > 0.0) {
const BlendPoint &blend_point = blend_points[b_values.points[i]];
float remaining = blend_node(blend_point.name, blend_point.node, p_time, p_seek, b_values.weights[i], FILTER_IGNORE, false);

max_time_remaining = MAX(max_time_remaining, remaining);
max_time_remaining = MAX(max_time_remaining, remaining);
}
}

return max_time_remaining;
Expand Down
17 changes: 13 additions & 4 deletions scene/animation/animation_blend_space_1d.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
class AnimationNodeBlendSpace1D : public AnimationRootNode {
GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode);

protected:
enum {
MAX_BLEND_POINTS = 64
};
Expand All @@ -62,6 +63,13 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {

StringName blend_position;

struct BlendWeights {
int points[2] = { -1, -1 };
float weights[2] = { 0 };
};

BlendWeights get_blend_values(const float p_blend_pos) const;

protected:
virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
Expand All @@ -72,9 +80,10 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {

virtual void get_child_nodes(List<ChildNode> *r_child_nodes);

void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1);
virtual void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1);
virtual void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node);

void set_blend_point_position(int p_point, float p_position);
void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node);

float get_blend_point_position(int p_point) const;
Ref<AnimationRootNode> get_blend_point_node(int p_point) const;
Expand All @@ -93,8 +102,8 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
void set_value_label(const String &p_label);
String get_value_label() const;

float process(float p_time, bool p_seek);
String get_caption() const;
virtual float process(float p_time, bool p_seek);
virtual String get_caption() const;

Ref<AnimationNode> get_child_by_name(const StringName &p_name);

Expand Down
Loading

0 comments on commit c30eb28

Please sign in to comment.