Skip to content

Commit 4a38b10

Browse files
committed
Convert 3.x transform animation tracks
1 parent fb51292 commit 4a38b10

5 files changed

Lines changed: 387 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
@@ -3528,11 +3528,43 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c
35283528
r_extensions->push_back("escn");
35293529
}
35303530

3531+
int get_text_format_version(String p_path) {
3532+
Error error;
3533+
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &error);
3534+
ERR_FAIL_COND_V_MSG(error != OK || f.is_null(), -1, "Cannot open file '" + p_path + "'.");
3535+
String line = f->get_line().strip_edges();
3536+
// skip empty lines and comments
3537+
while (line.is_empty() || line.begins_with(";")) {
3538+
line = f->get_line().strip_edges();
3539+
if (f->eof_reached()) {
3540+
break;
3541+
}
3542+
}
3543+
int format_index = line.find("format");
3544+
ERR_FAIL_COND_V_MSG(format_index == -1, -1, "No format specifier in file '" + p_path + "'.");
3545+
String format_str = line.substr(format_index).get_slicec('=', 1).strip_edges();
3546+
ERR_FAIL_COND_V_MSG(!format_str.substr(0, 1).is_numeric(), -1, "Invalid format in file '" + p_path + "'.");
3547+
int format = format_str.to_int();
3548+
return format;
3549+
}
3550+
35313551
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) {
35323552
Error error;
3553+
int format = get_text_format_version(p_path);
3554+
ERR_FAIL_COND_V(format == -1, nullptr);
35333555
Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error);
35343556
ERR_FAIL_COND_V_MSG(ps.is_null(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'.");
35353557
Node *scene = ps->instantiate();
3558+
ERR_FAIL_COND_V(!scene, nullptr);
3559+
if (format == 2) {
3560+
TypedArray<Node> skel_nodes = scene->find_children("*", "AnimationPlayer");
3561+
for (int32_t node_i = 0; node_i < skel_nodes.size(); node_i++) {
3562+
// Force re-compute animation tracks.
3563+
AnimationPlayer *player = cast_to<AnimationPlayer>(skel_nodes[node_i]);
3564+
ERR_CONTINUE(!player);
3565+
player->advance(0);
3566+
}
3567+
}
35363568
TypedArray<Node> nodes = scene->find_children("*", "MeshInstance3D");
35373569
for (int32_t node_i = 0; node_i < nodes.size(); node_i++) {
35383570
MeshInstance3D *mesh_3d = cast_to<MeshInstance3D>(nodes[node_i]);
@@ -3541,9 +3573,22 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
35413573
// Ignore the aabb, it will be recomputed.
35423574
ImporterMeshInstance3D *importer_mesh_3d = memnew(ImporterMeshInstance3D);
35433575
importer_mesh_3d->set_name(mesh_3d->get_name());
3544-
importer_mesh_3d->set_transform(mesh_3d->get_relative_transform(mesh_3d->get_parent()));
3545-
importer_mesh_3d->set_skin(mesh_3d->get_skin());
3576+
Node *parent = mesh_3d->get_parent();
3577+
Transform3D rel_transform = mesh_3d->get_relative_transform(parent);
3578+
if (rel_transform == Transform3D() && parent && parent != mesh_3d) {
3579+
// If we're here, we probably got a "data.parent is null" error
3580+
// Node3D.data.parent hasn't been set yet but Node.data.parent has, so we need to get the transform manually
3581+
Node3D *parent_3d = mesh_3d->get_parent_node_3d();
3582+
if (parent == parent_3d) {
3583+
rel_transform = mesh_3d->get_transform();
3584+
} else if (parent_3d) {
3585+
rel_transform = parent_3d->get_relative_transform(parent) * mesh_3d->get_transform();
3586+
} // Otherwise, parent isn't a Node3D.
3587+
}
3588+
importer_mesh_3d->set_transform(rel_transform);
3589+
Ref<Skin> skin = mesh_3d->get_skin();
35463590
importer_mesh_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
3591+
importer_mesh_3d->set_skin(skin);
35473592
Ref<ArrayMesh> array_mesh_3d_mesh = mesh_3d->get_mesh();
35483593
if (array_mesh_3d_mesh.is_valid()) {
35493594
// For the MeshInstance3D nodes, we need to convert the ArrayMesh to an ImporterMesh specially.
@@ -3584,7 +3629,5 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
35843629
}
35853630
}
35863631

3587-
ERR_FAIL_NULL_V(scene, nullptr);
3588-
35893632
return scene;
35903633
}

scene/animation/animation_mixer.cpp

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

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

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

0 commit comments

Comments
 (0)