Add support for named binds in Skin.
Helps better reutilization of skeletons from Maya exported files.
This commit is contained in:
parent
851cb42963
commit
9a34f39d32
8 changed files with 110 additions and 8 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue