Skip to content

Commit 6ae46be

Browse files
committed
Convert 3.x transform animation tracks
1 parent 91f1530 commit 6ae46be

5 files changed

Lines changed: 385 additions & 5 deletions

File tree

editor/import/3d/resource_importer_scene.cpp

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3426,11 +3426,43 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c
34263426
r_extensions->push_back("escn");
34273427
}
34283428

3429+
int get_text_format_version(String p_path) {
3430+
Error error;
3431+
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &error);
3432+
ERR_FAIL_COND_V_MSG(error != OK || f.is_null(), -1, "Cannot open file '" + p_path + "'.");
3433+
String line = f->get_line().strip_edges();
3434+
// skip empty lines and comments
3435+
while (line.is_empty() || line.begins_with(";")) {
3436+
line = f->get_line().strip_edges();
3437+
if (f->eof_reached()) {
3438+
break;
3439+
}
3440+
}
3441+
int format_index = line.find("format");
3442+
ERR_FAIL_COND_V_MSG(format_index == -1, -1, "No format specifier in file '" + p_path + "'.");
3443+
String format_str = line.substr(format_index).get_slicec('=', 1).strip_edges();
3444+
ERR_FAIL_COND_V_MSG(!format_str.substr(0, 1).is_numeric(), -1, "Invalid format in file '" + p_path + "'.");
3445+
int format = format_str.to_int();
3446+
return format;
3447+
}
3448+
34293449
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) {
34303450
Error error;
3451+
int format = get_text_format_version(p_path);
3452+
ERR_FAIL_COND_V(format == -1, nullptr);
34313453
Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error);
34323454
ERR_FAIL_COND_V_MSG(ps.is_null(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
34333455
Node *scene = ps->instantiate();
3456+
ERR_FAIL_COND_V(!scene, nullptr);
3457+
if (format == 2) {
3458+
TypedArray<Node> skel_nodes = scene->find_children("*", "AnimationPlayer");
3459+
for (int32_t node_i = 0; node_i < skel_nodes.size(); node_i++) {
3460+
// Force re-compute animation tracks.
3461+
AnimationPlayer *player = cast_to<AnimationPlayer>(skel_nodes[node_i]);
3462+
ERR_CONTINUE(!player);
3463+
player->advance(0);
3464+
}
3465+
}
34343466
TypedArray<Node> nodes = scene->find_children("*", "MeshInstance3D");
34353467
for (int32_t node_i = 0; node_i < nodes.size(); node_i++) {
34363468
MeshInstance3D *mesh_3d = cast_to<MeshInstance3D>(nodes[node_i]);
@@ -3439,9 +3471,22 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
34393471
// Ignore the aabb, it will be recomputed.
34403472
ImporterMeshInstance3D *importer_mesh_3d = memnew(ImporterMeshInstance3D);
34413473
importer_mesh_3d->set_name(mesh_3d->get_name());
3442-
importer_mesh_3d->set_transform(mesh_3d->get_relative_transform(mesh_3d->get_parent()));
3443-
importer_mesh_3d->set_skin(mesh_3d->get_skin());
3474+
Node *parent = mesh_3d->get_parent();
3475+
Transform3D rel_transform = mesh_3d->get_relative_transform(parent);
3476+
if (rel_transform == Transform3D() && parent && parent != mesh_3d) {
3477+
// If we're here, we probably got a "data.parent is null" error
3478+
// Node3D.data.parent hasn't been set yet but Node.data.parent has, so we need to get the transform manually
3479+
Node3D *parent_3d = mesh_3d->get_parent_node_3d();
3480+
if (parent == parent_3d) {
3481+
rel_transform = mesh_3d->get_transform();
3482+
} else if (parent_3d) {
3483+
rel_transform = parent_3d->get_relative_transform(parent) * mesh_3d->get_transform();
3484+
} // Otherwise, parent isn't a Node3D.
3485+
}
3486+
importer_mesh_3d->set_transform(rel_transform);
3487+
Ref<Skin> skin = mesh_3d->get_skin();
34443488
importer_mesh_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
3489+
importer_mesh_3d->set_skin(skin);
34453490
Ref<ArrayMesh> array_mesh_3d_mesh = mesh_3d->get_mesh();
34463491
if (array_mesh_3d_mesh.is_valid()) {
34473492
// For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially.
@@ -3482,7 +3527,5 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
34823527
}
34833528
}
34843529

3485-
ERR_FAIL_NULL_V(scene, nullptr);
3486-
34873530
return scene;
34883531
}

scene/animation/animation_mixer.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,101 @@ TypedArray<StringName> AnimationMixer::_get_animation_library_list() const {
260260
return ret;
261261
}
262262

263+
#if !defined(_3D_DISABLED) && !defined(DISABLE_DEPRECATED)
264+
bool AnimationMixer::_recalc_animation(Ref<Animation> &p_anim) {
265+
HashMap<int, Vector<real_t>> new_track_values_map;
266+
Node *parent = get_node_or_null(root_node);
267+
if (!parent) {
268+
return false;
269+
}
270+
271+
for (int i = 0; i < p_anim->get_track_count(); i++) {
272+
int track_type = p_anim->track_get_type(i);
273+
if (!p_anim->track_is_relative_to_rest(i)) {
274+
continue;
275+
}
276+
if (track_type == Animation::TYPE_POSITION_3D || track_type == Animation::TYPE_ROTATION_3D || track_type == Animation::TYPE_SCALE_3D) {
277+
NodePath path = p_anim->track_get_path(i);
278+
Node *node = parent->get_node(path);
279+
ERR_FAIL_NULL_V(node, false);
280+
Skeleton3D *skel = Object::cast_to<Skeleton3D>(node);
281+
if (!skel) { // transforming non-skeleton node, not relative to rest
282+
continue;
283+
}
284+
StringName bone = path.get_subname(0);
285+
int bone_idx = skel->find_bone(bone);
286+
if (bone_idx == -1) {
287+
continue;
288+
}
289+
Transform3D rest = skel->get_bone_rest(bone_idx);
290+
new_track_values_map[i] = Vector<real_t>();
291+
const int32_t POSITION_TRACK_SIZE = 5;
292+
const int32_t ROTATION_TRACK_SIZE = 6;
293+
const int32_t SCALE_TRACK_SIZE = 5;
294+
int32_t track_size = POSITION_TRACK_SIZE;
295+
if (track_type == Animation::TYPE_ROTATION_3D) {
296+
track_size = ROTATION_TRACK_SIZE;
297+
}
298+
new_track_values_map[i].resize(track_size * p_anim->track_get_key_count(i));
299+
real_t *r = new_track_values_map[i].ptrw();
300+
for (int j = 0; j < p_anim->track_get_key_count(i); j++) {
301+
real_t time = p_anim->track_get_key_time(i, j);
302+
real_t transition = p_anim->track_get_key_transition(i, j);
303+
if (track_type == Animation::TYPE_POSITION_3D) {
304+
Vector3 a_pos = p_anim->track_get_key_value(i, j);
305+
Transform3D t;
306+
t.set_origin(a_pos);
307+
Vector3 new_a_pos = (rest * t).origin;
308+
309+
real_t *ofs = &r[j * POSITION_TRACK_SIZE];
310+
ofs[0] = time;
311+
ofs[1] = transition;
312+
ofs[2] = new_a_pos.x;
313+
ofs[3] = new_a_pos.y;
314+
ofs[4] = new_a_pos.z;
315+
} else if (track_type == Animation::TYPE_ROTATION_3D) {
316+
Quaternion q = p_anim->track_get_key_value(i, j);
317+
Transform3D t;
318+
t.basis.rotate(q);
319+
Quaternion new_q = (rest * t).basis.get_rotation_quaternion();
320+
real_t *ofs = &r[j * ROTATION_TRACK_SIZE];
321+
ofs[0] = time;
322+
ofs[1] = transition;
323+
ofs[2] = new_q.x;
324+
ofs[3] = new_q.y;
325+
ofs[4] = new_q.z;
326+
ofs[5] = new_q.w;
327+
} else if (track_type == Animation::TYPE_SCALE_3D) {
328+
Vector3 v = p_anim->track_get_key_value(i, j);
329+
Transform3D t;
330+
t.scale(v);
331+
Vector3 new_v = (rest * t).basis.get_scale();
332+
333+
real_t *ofs = &r[j * SCALE_TRACK_SIZE];
334+
ofs[0] = time;
335+
ofs[1] = transition;
336+
ofs[2] = new_v.x;
337+
ofs[3] = new_v.y;
338+
ofs[4] = new_v.z;
339+
}
340+
}
341+
}
342+
}
343+
if (new_track_values_map.is_empty()) {
344+
return false;
345+
}
346+
for (int i = 0; i < p_anim->get_track_count(); i++) {
347+
if (!new_track_values_map.has(i)) {
348+
continue;
349+
}
350+
p_anim->set("tracks/" + itos(i) + "/keys", new_track_values_map[i]);
351+
p_anim->set("tracks/" + itos(i) + "/relative_to_rest", false);
352+
}
353+
p_anim->emit_changed();
354+
return true;
355+
}
356+
#endif // !defined(_3D_DISABLED) || !defined(DISABLE_DEPRECATED)
357+
263358
void AnimationMixer::get_animation_library_list(List<StringName> *p_libraries) const {
264359
for (const AnimationLibraryData &lib : animation_libraries) {
265360
p_libraries->push_back(lib.name);
@@ -678,6 +773,11 @@ bool AnimationMixer::_update_caches() {
678773
}
679774
for (const StringName &E : sname_list) {
680775
Ref<Animation> anim = get_animation(E);
776+
#if !defined(_3D_DISABLED) && !defined(DISABLE_DEPRECATED)
777+
if (anim->has_tracks_relative_to_rest()) {
778+
_recalc_animation(anim);
779+
}
780+
#endif
681781
for (int i = 0; i < anim->get_track_count(); i++) {
682782
if (!anim->track_is_enabled(i)) {
683783
continue;

scene/animation/animation_mixer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ class AnimationMixer : public Node {
317317
bool _update_caches();
318318
void _create_track_num_to_track_cache_for_animation(Ref<Animation> &p_animation);
319319

320+
#if !defined(_3D_DISABLED) && !defined(DISABLE_DEPRECATED)
321+
bool _recalc_animation(Ref<Animation> &p_anim);
322+
#endif
323+
320324
/* ---- Audio ---- */
321325
AudioServer::PlaybackType playback_type;
322326

0 commit comments

Comments
 (0)