Skip to content

Commit

Permalink
Convert 3.x transform animation tracks
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitalita committed Oct 3, 2024
1 parent 386b525 commit 6f36e92
Show file tree
Hide file tree
Showing 5 changed files with 400 additions and 5 deletions.
51 changes: 47 additions & 4 deletions editor/import/3d/resource_importer_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3270,11 +3270,43 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c
r_extensions->push_back("escn");
}

int get_text_format_version(String p_path) {
Error error;
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &error);
ERR_FAIL_COND_V_MSG(error != OK || f.is_null(), -1, "Cannot open file '" + p_path + "'.");
String line = f->get_line().strip_edges();
// skip empty lines and comments
while (line.is_empty() || line.begins_with(";")) {
line = f->get_line().strip_edges();
if (f->eof_reached()) {
break;
}
}
int format_index = line.find("format");
ERR_FAIL_COND_V_MSG(format_index == -1, -1, "No format specifier in file '" + p_path + "'.");
String format_str = line.substr(format_index).get_slicec('=', 1).strip_edges();
ERR_FAIL_COND_V_MSG(!format_str.substr(0, 1).is_numeric(), -1, "Invalid format in file '" + p_path + "'.");
int format = format_str.to_int();
return format;
}

Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
Error error;
int format = get_text_format_version(p_path);
ERR_FAIL_COND_V(format == -1, nullptr);
Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error);
ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
Node *scene = ps->instantiate();
ERR_FAIL_COND_V(!scene, nullptr);
if (format == 2) {
TypedArray<Node> skel_nodes = scene->find_children("*", "AnimationPlayer");
for (int32_t node_i = 0; node_i < skel_nodes.size(); node_i++) {
// Force re-compute animation tracks.
AnimationPlayer *player = cast_to<AnimationPlayer>(skel_nodes[node_i]);
ERR_CONTINUE(!player);
player->advance(0);
}
}
TypedArray<Node> nodes = scene->find_children("*", "MeshInstance3D");
for (int32_t node_i = 0; node_i < nodes.size(); node_i++) {
MeshInstance3D *mesh_3d = cast_to<MeshInstance3D>(nodes[node_i]);
Expand All @@ -3283,9 +3315,22 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
// Ignore the aabb, it will be recomputed.
ImporterMeshInstance3D *importer_mesh_3d = memnew(ImporterMeshInstance3D);
importer_mesh_3d->set_name(mesh_3d->get_name());
importer_mesh_3d->set_transform(mesh_3d->get_relative_transform(mesh_3d->get_parent()));
importer_mesh_3d->set_skin(mesh_3d->get_skin());
Node *parent = mesh_3d->get_parent();
Transform3D rel_transform = mesh_3d->get_relative_transform(parent);
if (rel_transform == Transform3D() && parent && parent != mesh_3d) {
// If we're here, we probably got a "data.parent is null" error
// Node3D.data.parent hasn't been set yet but Node.data.parent has, so we need to get the transform manually
Node3D *parent_3d = mesh_3d->get_parent_node_3d();
if (parent == parent_3d) {
rel_transform = mesh_3d->get_transform();
} else if (parent_3d) {
rel_transform = parent_3d->get_relative_transform(parent) * mesh_3d->get_transform();
} // Otherwise, parent isn't a Node3D.
}
importer_mesh_3d->set_transform(rel_transform);
Ref<Skin> skin = mesh_3d->get_skin();
importer_mesh_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
importer_mesh_3d->set_skin(skin);
Ref<ArrayMesh> array_mesh_3d_mesh = mesh_3d->get_mesh();
if (array_mesh_3d_mesh.is_valid()) {
// For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially.
Expand Down Expand Up @@ -3326,7 +3371,5 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
}
}

ERR_FAIL_NULL_V(scene, nullptr);

return scene;
}
103 changes: 103 additions & 0 deletions scene/animation/animation_mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,97 @@ TypedArray<StringName> AnimationMixer::_get_animation_library_list() const {
return ret;
}

#if !defined(_3D_DISABLED) || !defined(DISABLE_DEPRECATED)
bool AnimationMixer::_recalc_animation(Ref<Animation> &anim) {
HashMap<int, Vector<real_t>> new_track_values_map;
Node *parent = get_node_or_null(root_node);
if (!parent) {
return false;
}

for (int i = 0; i < anim->get_track_count(); i++) {
int track_type = anim->track_get_type(i);
if (track_type == Animation::TYPE_POSITION_3D || track_type == Animation::TYPE_ROTATION_3D || track_type == Animation::TYPE_SCALE_3D) {
NodePath path = anim->track_get_path(i);
Node *node = parent->get_node(path);
ERR_FAIL_COND_V(!node, false);
Skeleton3D *skel = Object::cast_to<Skeleton3D>(node);
ERR_FAIL_COND_V(!skel, false);

StringName bone = path.get_subname(0);
int bone_idx = skel->find_bone(bone);
if (bone_idx == -1) {
continue;
}
Transform3D rest = skel->get_bone_rest(bone_idx);
new_track_values_map[i] = Vector<real_t>();
const int32_t POSITION_TRACK_SIZE = 5;
const int32_t ROTATION_TRACK_SIZE = 6;
const int32_t SCALE_TRACK_SIZE = 5;
int32_t track_size = POSITION_TRACK_SIZE;
if (track_type == Animation::TYPE_ROTATION_3D) {
track_size = ROTATION_TRACK_SIZE;
}
new_track_values_map[i].resize(track_size * anim->track_get_key_count(i));
real_t *r = new_track_values_map[i].ptrw();
for (int j = 0; j < anim->track_get_key_count(i); j++) {
real_t time = anim->track_get_key_time(i, j);
real_t transition = anim->track_get_key_transition(i, j);
if (track_type == Animation::TYPE_POSITION_3D) {
Vector3 a_pos = anim->track_get_key_value(i, j);
Transform3D t = Transform3D();
t.set_origin(a_pos);
Vector3 new_a_pos = (rest * t).origin;

real_t *ofs = &r[j * POSITION_TRACK_SIZE];
ofs[0] = time;
ofs[1] = transition;
ofs[2] = new_a_pos.x;
ofs[3] = new_a_pos.y;
ofs[4] = new_a_pos.z;
} else if (track_type == Animation::TYPE_ROTATION_3D) {
Quaternion q = anim->track_get_key_value(i, j);
Transform3D t = Transform3D();
t.basis.rotate(q);
Quaternion new_q = (rest * t).basis.get_rotation_quaternion();
real_t *ofs = &r[j * ROTATION_TRACK_SIZE];
ofs[0] = time;
ofs[1] = transition;
ofs[2] = new_q.x;
ofs[3] = new_q.y;
ofs[4] = new_q.z;
ofs[5] = new_q.w;
} else if (track_type == Animation::TYPE_SCALE_3D) {
Vector3 v = anim->track_get_key_value(i, j);
Transform3D t = Transform3D();
t.scale(v);
Vector3 new_v = (rest * t).basis.get_scale();

real_t *ofs = &r[j * SCALE_TRACK_SIZE];
ofs[0] = time;
ofs[1] = transition;
ofs[2] = new_v.x;
ofs[3] = new_v.y;
ofs[4] = new_v.z;
}
}
}
}
if (new_track_values_map.is_empty()) {
return false;
}
for (int i = 0; i < anim->get_track_count(); i++) {
if (!new_track_values_map.has(i)) {
continue;
}
anim->set("tracks/" + itos(i) + "/keys", new_track_values_map[i]);
anim->set("tracks/" + itos(i) + "/relative_to_rest", false);
}
anim->emit_changed();
return true;
}
#endif // !defined(_3D_DISABLED) || !defined(DISABLE_DEPRECATED)

void AnimationMixer::get_animation_library_list(List<StringName> *p_libraries) const {
for (const AnimationLibraryData &lib : animation_libraries) {
p_libraries->push_back(lib.name);
Expand Down Expand Up @@ -986,6 +1077,18 @@ void AnimationMixer::_blend_init() {
root_motion_scale_accumulator = Vector3(1, 1, 1);

if (!cache_valid) {
#if !defined(_3D_DISABLED) || !defined(DISABLE_DEPRECATED)
List<StringName> sname;
get_animation_list(&sname);

for (const StringName &E : sname) {
Ref<Animation> anim = get_animation(E);

if (anim->has_tracks_relative_to_rest()) {
_recalc_animation(anim);
}
}
#endif
if (!_update_caches()) {
return;
}
Expand Down
4 changes: 4 additions & 0 deletions scene/animation/animation_mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ class AnimationMixer : public Node {
void _init_root_motion_cache();
bool _update_caches();

#if !defined(_3D_DISABLED) || !defined(DISABLE_DEPRECATED)
bool _recalc_animation(Ref<Animation> &p_anim);
#endif

/* ---- Audio ---- */
AudioServer::PlaybackType playback_type;

Expand Down
Loading

0 comments on commit 6f36e92

Please sign in to comment.