summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gltf/gltf_document.cpp4
-rw-r--r--modules/gltf/skin_tool.cpp5
-rw-r--r--modules/gltf/tests/test_gltf_extras.h57
3 files changed, 66 insertions, 0 deletions
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 56dae65831..bd034cbdc5 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -5534,6 +5534,10 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS
joint_node->set_name(_gen_unique_name(p_state, skeleton->get_bone_name(bone_i)));
joint_node->transform = skeleton->get_bone_pose(bone_i);
joint_node->joint = true;
+
+ if (p_skeleton3d->has_bone_meta(bone_i, "extras")) {
+ joint_node->set_meta("extras", p_skeleton3d->get_bone_meta(bone_i, "extras"));
+ }
GLTFNodeIndex current_node_i = p_state->nodes.size();
p_state->scene_nodes.insert(current_node_i, skeleton);
p_state->nodes.push_back(joint_node);
diff --git a/modules/gltf/skin_tool.cpp b/modules/gltf/skin_tool.cpp
index a344334d93..1522c0e324 100644
--- a/modules/gltf/skin_tool.cpp
+++ b/modules/gltf/skin_tool.cpp
@@ -602,6 +602,11 @@ Error SkinTool::_create_skeletons(
skeleton->set_bone_pose_rotation(bone_index, node->transform.basis.get_rotation_quaternion());
skeleton->set_bone_pose_scale(bone_index, node->transform.basis.get_scale());
+ // Store bone-level GLTF extras in skeleton per bone meta.
+ if (node->has_meta("extras")) {
+ skeleton->set_bone_meta(bone_index, "extras", node->get_meta("extras"));
+ }
+
if (node->parent >= 0 && nodes[node->parent]->skeleton == skel_i) {
const int bone_parent = skeleton->find_bone(nodes[node->parent]->get_name());
ERR_FAIL_COND_V(bone_parent < 0, FAILED);
diff --git a/modules/gltf/tests/test_gltf_extras.h b/modules/gltf/tests/test_gltf_extras.h
index 96aadf3023..37c8f6925c 100644
--- a/modules/gltf/tests/test_gltf_extras.h
+++ b/modules/gltf/tests/test_gltf_extras.h
@@ -41,6 +41,7 @@
#include "modules/gltf/gltf_document.h"
#include "modules/gltf/gltf_state.h"
#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/main/window.h"
#include "scene/resources/3d/primitive_meshes.h"
#include "scene/resources/material.h"
@@ -158,6 +159,62 @@ TEST_CASE("[SceneTree][Node] GLTF test mesh and material meta export and import"
memdelete(original);
memdelete(loaded);
}
+
+TEST_CASE("[SceneTree][Node] GLTF test skeleton and bone export and import") {
+ // Setup scene.
+ Skeleton3D *skeleton = memnew(Skeleton3D);
+ skeleton->set_name("skeleton");
+ Dictionary skeleton_extras;
+ skeleton_extras["node_type"] = "skeleton";
+ skeleton->set_meta("extras", skeleton_extras);
+
+ skeleton->add_bone("parent");
+ skeleton->set_bone_rest(0, Transform3D());
+ Dictionary parent_bone_extras;
+ parent_bone_extras["bone"] = "i_am_parent_bone";
+ skeleton->set_bone_meta(0, "extras", parent_bone_extras);
+
+ skeleton->add_bone("child");
+ skeleton->set_bone_rest(1, Transform3D());
+ skeleton->set_bone_parent(1, 0);
+ Dictionary child_bone_extras;
+ child_bone_extras["bone"] = "i_am_child_bone";
+ skeleton->set_bone_meta(1, "extras", child_bone_extras);
+
+ // We have to have a mesh to link with skeleton or it will not get imported.
+ Ref<PlaneMesh> meshdata = memnew(PlaneMesh);
+ meshdata->set_name("planemesh");
+
+ MeshInstance3D *mesh = memnew(MeshInstance3D);
+ mesh->set_mesh(meshdata);
+ mesh->set_name("mesh_instance_3d");
+
+ Node3D *scene = memnew(Node3D);
+ SceneTree::get_singleton()->get_root()->add_child(scene);
+ scene->add_child(skeleton);
+ scene->add_child(mesh);
+ scene->set_name("node3d");
+
+ // Now that both skeleton and mesh are part of scene, link them.
+ mesh->set_skeleton_path(mesh->get_path_to(skeleton));
+
+ // Convert to GLFT and back.
+ String tempfile = OS::get_singleton()->get_cache_path().path_join("gltf_bone_extras");
+ Node *loaded = _gltf_export_then_import(scene, tempfile);
+
+ // Compare the results.
+ CHECK(loaded->get_name() == "node3d");
+ Skeleton3D *result = Object::cast_to<Skeleton3D>(loaded->find_child("Skeleton3D", false, true));
+ CHECK(result->get_bone_name(0) == "parent");
+ CHECK(Dictionary(result->get_bone_meta(0, "extras"))["bone"] == "i_am_parent_bone");
+ CHECK(result->get_bone_name(1) == "child");
+ CHECK(Dictionary(result->get_bone_meta(1, "extras"))["bone"] == "i_am_child_bone");
+
+ memdelete(skeleton);
+ memdelete(mesh);
+ memdelete(scene);
+ memdelete(loaded);
+}
} // namespace TestGltfExtras
#endif // TOOLS_ENABLED