Initial version with working synced blending.
This commit is contained in:
parent
f1641f3ac3
commit
69bb2d7980
@ -57,11 +57,11 @@ struct SyncTrack {
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
float calc_ratio_from_sync_time(float sync_time) const {
|
||||
float interval_ratio = fmodf(sync_time, 1.0f);
|
||||
double calc_ratio_from_sync_time(double sync_time) const {
|
||||
float interval_ratio = fmod(sync_time, 1.0f);
|
||||
int interval = int(sync_time - interval_ratio);
|
||||
|
||||
return fmodf(
|
||||
return fmod(
|
||||
interval_start_ratio[interval] + interval_duration_ratio[interval] * interval_ratio,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
@ -202,6 +202,20 @@ bool AnimationSamplerNode::initialize(GraphEvaluationContext &context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (animation_name == "animation_library/TestAnimationA") {
|
||||
// Corresponds to the walking animation
|
||||
node_time_info.sync_track = SyncTrack::create_from_markers(animation->get_length(), { 0.8117, 0.314 });
|
||||
print_line(vformat("Using hardcoded sync track for animation %s.", animation_name));
|
||||
} else if (animation_name == "animation_library/TestAnimationB") {
|
||||
// Corresponds to the running animation
|
||||
node_time_info.sync_track = SyncTrack::create_from_markers(animation->get_length(), { 0.6256, 0.2721 });
|
||||
print_line(vformat("Using hardcoded sync track for animation %s.", animation_name));
|
||||
} else if (animation_name == "animation_library/TestAnimationC") {
|
||||
// Corresponds to the limping animation
|
||||
node_time_info.sync_track = SyncTrack::create_from_markers(animation->get_length(), { 0.0674, 1.1047 });
|
||||
print_line(vformat("Using hardcoded sync track for animation %s.", animation_name));
|
||||
}
|
||||
|
||||
node_time_info.length = animation->get_length();
|
||||
node_time_info.loop_mode = Animation::LOOP_LINEAR;
|
||||
|
||||
@ -211,8 +225,14 @@ bool AnimationSamplerNode::initialize(GraphEvaluationContext &context) {
|
||||
void AnimationSamplerNode::evaluate(GraphEvaluationContext &context, const LocalVector<AnimationData *> &inputs, AnimationData &output) {
|
||||
assert(inputs.size() == 0);
|
||||
|
||||
double sample_time = node_time_info.position;
|
||||
|
||||
if (node_time_info.is_synced) {
|
||||
sample_time = node_time_info.sync_track.calc_ratio_from_sync_time(node_time_info.sync_position) * animation->get_length();
|
||||
}
|
||||
|
||||
output.clear();
|
||||
output.sample_from_animation(animation, context.skeleton_3d, node_time_info.position);
|
||||
output.sample_from_animation(animation, context.skeleton_3d, sample_time);
|
||||
}
|
||||
|
||||
void AnimationSamplerNode::set_animation(const StringName &p_name) {
|
||||
|
||||
@ -230,7 +230,7 @@ public:
|
||||
double sync_delta = 0.0;
|
||||
bool is_synced = false;
|
||||
|
||||
Animation::LoopMode loop_mode = Animation::LOOP_NONE;
|
||||
Animation::LoopMode loop_mode = Animation::LOOP_LINEAR;
|
||||
SyncTrack sync_track;
|
||||
};
|
||||
NodeTimeInfo node_time_info;
|
||||
@ -246,6 +246,7 @@ public:
|
||||
// By default, all inputs nodes are activated.
|
||||
for (const Ref<SyncedAnimationNode> &node : input_nodes) {
|
||||
node->active = true;
|
||||
node->node_time_info.is_synced = node_time_info.is_synced;
|
||||
}
|
||||
}
|
||||
virtual void calculate_sync_track(Vector<Ref<SyncedAnimationNode>> input_nodes) {
|
||||
@ -254,25 +255,29 @@ public:
|
||||
node_time_info.sync_track = input_nodes[0]->node_time_info.sync_track;
|
||||
}
|
||||
}
|
||||
virtual void update_time(double p_delta) {
|
||||
node_time_info.delta = p_delta;
|
||||
node_time_info.position += p_delta;
|
||||
if (node_time_info.position > node_time_info.length) {
|
||||
switch (node_time_info.loop_mode) {
|
||||
case Animation::LOOP_NONE: {
|
||||
node_time_info.position = node_time_info.length;
|
||||
break;
|
||||
}
|
||||
case Animation::LOOP_LINEAR: {
|
||||
assert(node_time_info.length > 0.0);
|
||||
while (node_time_info.position > node_time_info.length) {
|
||||
node_time_info.position -= node_time_info.length;
|
||||
virtual void update_time(double p_time) {
|
||||
if (node_time_info.is_synced) {
|
||||
node_time_info.sync_position = p_time;
|
||||
} else {
|
||||
node_time_info.delta = p_time;
|
||||
node_time_info.position += p_time;
|
||||
if (node_time_info.position > node_time_info.length) {
|
||||
switch (node_time_info.loop_mode) {
|
||||
case Animation::LOOP_NONE: {
|
||||
node_time_info.position = node_time_info.length;
|
||||
break;
|
||||
}
|
||||
case Animation::LOOP_LINEAR: {
|
||||
assert(node_time_info.length > 0.0);
|
||||
while (node_time_info.position > node_time_info.length) {
|
||||
node_time_info.position -= node_time_info.length;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Animation::LOOP_PINGPONG: {
|
||||
assert(false && !"Not yet implemented.");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Animation::LOOP_PINGPONG: {
|
||||
assert(false && !"Not yet implemented.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,13 +341,33 @@ class AnimationBlend2Node : public SyncedAnimationNode {
|
||||
public:
|
||||
StringName blend_amount = PNAME("blend_amount");
|
||||
float blend_weight = 0.0f;
|
||||
bool sync = false;
|
||||
bool sync = true;
|
||||
|
||||
void get_input_names(Vector<StringName> &inputs) const override {
|
||||
inputs.push_back("Input0");
|
||||
inputs.push_back("Input1");
|
||||
}
|
||||
void activate_inputs(Vector<Ref<SyncedAnimationNode>> input_nodes) override {
|
||||
for (const Ref<SyncedAnimationNode> &node : input_nodes) {
|
||||
node->active = true;
|
||||
|
||||
// If this Blend2 node is already synced then inputs are also synced. Otherwise, inputs are only set to synced if synced blending is active in this node.
|
||||
node->node_time_info.is_synced = node_time_info.is_synced || sync;
|
||||
}
|
||||
}
|
||||
void calculate_sync_track(Vector<Ref<SyncedAnimationNode>> input_nodes) override {
|
||||
if (node_time_info.is_synced || sync) {
|
||||
node_time_info.sync_track = SyncTrack::blend(blend_weight, input_nodes[0]->node_time_info.sync_track, input_nodes[1]->node_time_info.sync_track);
|
||||
node_time_info.length = node_time_info.sync_track.duration;
|
||||
}
|
||||
}
|
||||
void update_time(double p_delta) override {
|
||||
SyncedAnimationNode::update_time(p_delta);
|
||||
|
||||
if (sync && !node_time_info.is_synced) {
|
||||
node_time_info.sync_position = node_time_info.sync_track.calc_sync_from_abs_time(node_time_info.position);
|
||||
}
|
||||
}
|
||||
void evaluate(GraphEvaluationContext &context, const LocalVector<AnimationData *> &inputs, AnimationData &output) override;
|
||||
|
||||
void set_use_sync(bool p_sync);
|
||||
@ -717,7 +742,7 @@ public:
|
||||
const Ref<SyncedAnimationNode> &node_parent = tree_graph.nodes[tree_graph.node_connection_info[i].parent_node_index];
|
||||
|
||||
if (node->node_time_info.is_synced) {
|
||||
node->update_time(node_parent->node_time_info.position);
|
||||
node->update_time(node_parent->node_time_info.sync_position);
|
||||
} else {
|
||||
node->update_time(node_parent->node_time_info.delta);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user