summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Linietsky <juan@godotengine.org>2020-02-21 07:27:48 -0300
committerJuan Linietsky <juan@godotengine.org>2020-02-21 09:40:29 -0300
commit9a34f39d320132f4a8fef4c231a4678a0159c3d3 (patch)
tree10e21954675c639bf87b49d22718223abd6f5d3a
parent851cb429631168369d2a51812de763b658795fbf (diff)
Add support for named binds in Skin.
Helps better reutilization of skeletons from Maya exported files.
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp15
-rw-r--r--editor/import/editor_scene_importer_gltf.h3
-rw-r--r--editor/import/resource_importer_scene.cpp4
-rw-r--r--editor/import/resource_importer_scene.h3
-rw-r--r--scene/3d/skeleton.cpp46
-rw-r--r--scene/3d/skeleton.h5
-rw-r--r--scene/resources/skin.cpp30
-rw-r--r--scene/resources/skin.h12
8 files changed, 110 insertions, 8 deletions
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index f9e8977924..731d094745 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -2183,6 +2183,8 @@ Error EditorSceneImporterGLTF::_map_skin_joints_indices_to_skeleton_bone_indices
const GLTFNodeIndex node_i = skin.joints_original[joint_index];
const GLTFNode *node = state.nodes[node_i];
+ skin.joint_i_to_name.insert(joint_index, node->name);
+
const int bone_index = skeleton.godot_skeleton->find_bone(node->name);
ERR_FAIL_COND_V(bone_index < 0, FAILED);
@@ -2204,12 +2206,18 @@ Error EditorSceneImporterGLTF::_create_skins(GLTFState &state) {
const bool has_ibms = !gltf_skin.inverse_binds.empty();
for (int joint_i = 0; joint_i < gltf_skin.joints_original.size(); ++joint_i) {
- int bone_i = gltf_skin.joint_i_to_bone_i[joint_i];
+ Transform xform;
if (has_ibms) {
- skin->add_bind(bone_i, gltf_skin.inverse_binds[joint_i]);
+ xform = gltf_skin.inverse_binds[joint_i];
+ }
+
+ if (state.use_named_skin_binds) {
+ StringName name = gltf_skin.joint_i_to_name[joint_i];
+ skin->add_named_bind(name, xform);
} else {
- skin->add_bind(bone_i, Transform());
+ int bone_i = gltf_skin.joint_i_to_bone_i[joint_i];
+ skin->add_bind(bone_i, xform);
}
}
@@ -2995,6 +3003,7 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_fla
state.major_version = version.get_slice(".", 0).to_int();
state.minor_version = version.get_slice(".", 1).to_int();
+ state.use_named_skin_binds = p_flags & IMPORT_USE_NAMED_SKIN_BINDS;
/* STEP 0 PARSE SCENE */
Error err = _parse_scenes(state);
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index 72d5b04e67..5d2711483b 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -231,6 +231,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
// A mapping from the joint indices (in the order of joints_original) to the
// Godot Skeleton's bone_indices
Map<int, int> joint_i_to_bone_i;
+ Map<int, StringName> joint_i_to_name;
// The Actual Skin that will be created as a mapping between the IBM's of this skin
// to the generated skeleton for the mesh instances.
@@ -298,6 +299,8 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
int minor_version;
Vector<uint8_t> glb_data;
+ bool use_named_skin_binds;
+
Vector<GLTFNode *> nodes;
Vector<Vector<uint8_t> > buffers;
Vector<GLTFBufferView> buffer_views;
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 4b0bfa7222..22c2a71286 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1171,6 +1171,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files (.mesh),Files (.tres)"), meshes_out ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
@@ -1313,6 +1314,9 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (int(p_options["materials/location"]) == 0)
import_flags |= EditorSceneImporter::IMPORT_MATERIALS_IN_INSTANCES;
+ if (bool(p_options["skins/use_named_skins"]))
+ import_flags |= EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
+
Error err = OK;
List<String> missing_deps; // for now, not much will be done with this
Node *scene = importer->import_scene(src_path, import_flags, fps, &missing_deps, &err);
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 2691b224eb..20e7af15b5 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -59,7 +59,8 @@ public:
IMPORT_GENERATE_TANGENT_ARRAYS = 256,
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 512,
IMPORT_MATERIALS_IN_INSTANCES = 1024,
- IMPORT_USE_COMPRESSION = 2048
+ IMPORT_USE_COMPRESSION = 2048,
+ IMPORT_USE_NAMED_SKIN_BINDS = 4096,
};
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index a1d1856001..660b5bc7da 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -41,6 +41,7 @@ void SkinReference::_skin_changed() {
if (skeleton_node) {
skeleton_node->_make_dirty();
}
+ skeleton_version = 0;
}
void SkinReference::_bind_methods() {
@@ -322,10 +323,49 @@ void Skeleton::_notification(int p_what) {
if (E->get()->bind_count != bind_count) {
VS::get_singleton()->skeleton_allocate(skeleton, bind_count);
E->get()->bind_count = bind_count;
+ E->get()->skin_bone_indices.resize(bind_count);
+ E->get()->skin_bone_indices_ptrs = E->get()->skin_bone_indices.ptrw();
+ }
+
+ if (E->get()->skeleton_version != version) {
+
+ for (uint32_t i = 0; i < bind_count; i++) {
+ StringName bind_name = skin->get_bind_name(i);
+
+ if (bind_name != StringName()) {
+ //bind name used, use this
+ bool found = false;
+ for (int j = 0; j < len; j++) {
+ if (bonesptr[j].name == bind_name) {
+ E->get()->skin_bone_indices_ptrs[i] = j;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ ERR_PRINT("Skin bind #" + itos(i) + " contains named bind '" + String(bind_name) + "' but Skeleton has no bone by that name.");
+ E->get()->skin_bone_indices_ptrs[i] = 0;
+ }
+ } else if (skin->get_bind_bone(i) >= 0) {
+ int bind_index = skin->get_bind_bone(i);
+ if (bind_index >= len) {
+ ERR_PRINT("Skin bind #" + itos(i) + " contains bone index bind: " + itos(bind_index) + " , which is greater than the skeleton bone count: " + itos(len) + ".");
+ E->get()->skin_bone_indices_ptrs[i] = 0;
+ } else {
+ E->get()->skin_bone_indices_ptrs[i] = bind_index;
+ }
+ } else {
+ ERR_PRINT("Skin bind #" + itos(i) + " does not contain a name nor a bone index.");
+ E->get()->skin_bone_indices_ptrs[i] = 0;
+ }
+ }
+
+ E->get()->skeleton_version = version;
}
for (uint32_t i = 0; i < bind_count; i++) {
- uint32_t bone_index = skin->get_bind_bone(i);
+ uint32_t bone_index = E->get()->skin_bone_indices_ptrs[i];
ERR_CONTINUE(bone_index >= (uint32_t)len);
vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
}
@@ -388,6 +428,7 @@ void Skeleton::add_bone(const String &p_name) {
b.name = p_name;
bones.push_back(b);
process_order_dirty = true;
+ version++;
_make_dirty();
update_gizmo();
}
@@ -539,7 +580,7 @@ void Skeleton::clear_bones() {
bones.clear();
process_order_dirty = true;
-
+ version++;
_make_dirty();
}
@@ -894,6 +935,7 @@ Skeleton::Skeleton() {
animate_physical_bones = true;
dirty = false;
+ version = 1;
process_order_dirty = true;
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index b42c2112e3..76fd96f30a 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -51,6 +51,9 @@ class SkinReference : public Reference {
RID skeleton;
Ref<Skin> skin;
uint32_t bind_count = 0;
+ uint64_t skeleton_version = 0;
+ Vector<uint32_t> skin_bone_indices;
+ uint32_t *skin_bone_indices_ptrs;
void _skin_changed();
protected:
@@ -123,6 +126,8 @@ private:
void _make_dirty();
bool dirty;
+ uint64_t version;
+
// bind helpers
Array _get_bound_child_nodes_to_bone(int p_bone) const {
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
index 9c8710a59c..28258c0b60 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -45,6 +45,24 @@ void Skin::add_bind(int p_bone, const Transform &p_pose) {
set_bind_pose(index, p_pose);
}
+void Skin::add_named_bind(const String &p_name, const Transform &p_pose) {
+
+ uint32_t index = bind_count;
+ set_bind_count(bind_count + 1);
+ set_bind_name(index, p_name);
+ set_bind_pose(index, p_pose);
+}
+
+void Skin::set_bind_name(int p_index, const StringName &p_name) {
+ ERR_FAIL_INDEX(p_index, bind_count);
+ bool notify_change = (binds_ptr[p_index].name != StringName()) != (p_name != StringName());
+ binds_ptr[p_index].name = p_name;
+ emit_changed();
+ if (notify_change) {
+ _change_notify();
+ }
+}
+
void Skin::set_bind_bone(int p_index, int p_bone) {
ERR_FAIL_INDEX(p_index, bind_count);
binds_ptr[p_index].bone = p_bone;
@@ -75,6 +93,9 @@ bool Skin::_set(const StringName &p_name, const Variant &p_value) {
if (what == "bone") {
set_bind_bone(index, p_value);
return true;
+ } else if (what == "name") {
+ set_bind_name(index, p_value);
+ return true;
} else if (what == "pose") {
set_bind_pose(index, p_value);
return true;
@@ -95,6 +116,9 @@ bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
if (what == "bone") {
r_ret = get_bind_bone(index);
return true;
+ } else if (what == "name") {
+ r_ret = get_bind_name(index);
+ return true;
} else if (what == "pose") {
r_ret = get_bind_pose(index);
return true;
@@ -105,7 +129,8 @@ bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
void Skin::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT, "bind_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
for (int i = 0; i < get_bind_count(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::STRING, "bind/" + itos(i) + "/name", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NOEDITOR : PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, "bind/" + itos(i) + "/pose"));
}
}
@@ -120,6 +145,9 @@ void Skin::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bind_pose", "bind_index", "pose"), &Skin::set_bind_pose);
ClassDB::bind_method(D_METHOD("get_bind_pose", "bind_index"), &Skin::get_bind_pose);
+ ClassDB::bind_method(D_METHOD("set_bind_name", "bind_index", "name"), &Skin::set_bind_name);
+ ClassDB::bind_method(D_METHOD("get_bind_name", "bind_index"), &Skin::get_bind_name);
+
ClassDB::bind_method(D_METHOD("set_bind_bone", "bind_index", "bone"), &Skin::set_bind_bone);
ClassDB::bind_method(D_METHOD("get_bind_bone", "bind_index"), &Skin::get_bind_bone);
diff --git a/scene/resources/skin.h b/scene/resources/skin.h
index ddc7c655f5..57aaf1afd4 100644
--- a/scene/resources/skin.h
+++ b/scene/resources/skin.h
@@ -37,7 +37,8 @@ class Skin : public Resource {
GDCLASS(Skin, Resource)
struct Bind {
- int bone;
+ int bone = -1;
+ StringName name;
Transform pose;
};
@@ -58,9 +59,11 @@ public:
inline int get_bind_count() const { return bind_count; }
void add_bind(int p_bone, const Transform &p_pose);
+ void add_named_bind(const String &p_name, const Transform &p_pose);
void set_bind_bone(int p_index, int p_bone);
void set_bind_pose(int p_index, const Transform &p_pose);
+ void set_bind_name(int p_index, const StringName &p_name);
inline int get_bind_bone(int p_index) const {
#ifdef DEBUG_ENABLED
@@ -69,6 +72,13 @@ public:
return binds_ptr[p_index].bone;
}
+ inline StringName get_bind_name(int p_index) const {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(p_index, bind_count, StringName());
+#endif
+ return binds_ptr[p_index].name;
+ }
+
inline Transform get_bind_pose(int p_index) const {
#ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(p_index, bind_count, Transform());