Add support for named binds in Skin.
Helps better reutilization of skeletons from Maya exported files.
(cherry picked from commit 9a34f39d32
)
This commit is contained in:
parent
ffea9fc39f
commit
03c8e12d54
|
@ -2179,6 +2179,8 @@ Error EditorSceneImporterGLTF::_map_skin_joints_indices_to_skeleton_bone_indices
|
||||||
const GLTFNodeIndex node_i = skin.joints_original[joint_index];
|
const GLTFNodeIndex node_i = skin.joints_original[joint_index];
|
||||||
const GLTFNode *node = state.nodes[node_i];
|
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);
|
const int bone_index = skeleton.godot_skeleton->find_bone(node->name);
|
||||||
ERR_FAIL_COND_V(bone_index < 0, FAILED);
|
ERR_FAIL_COND_V(bone_index < 0, FAILED);
|
||||||
|
|
||||||
|
@ -2200,12 +2202,18 @@ Error EditorSceneImporterGLTF::_create_skins(GLTFState &state) {
|
||||||
const bool has_ibms = !gltf_skin.inverse_binds.empty();
|
const bool has_ibms = !gltf_skin.inverse_binds.empty();
|
||||||
|
|
||||||
for (int joint_i = 0; joint_i < gltf_skin.joints_original.size(); ++joint_i) {
|
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) {
|
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 {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2991,6 +2999,7 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_fla
|
||||||
|
|
||||||
state.major_version = version.get_slice(".", 0).to_int();
|
state.major_version = version.get_slice(".", 0).to_int();
|
||||||
state.minor_version = version.get_slice(".", 1).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 */
|
/* STEP 0 PARSE SCENE */
|
||||||
Error err = _parse_scenes(state);
|
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
|
// A mapping from the joint indices (in the order of joints_original) to the
|
||||||
// Godot Skeleton's bone_indices
|
// Godot Skeleton's bone_indices
|
||||||
Map<int, int> joint_i_to_bone_i;
|
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
|
// 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.
|
// to the generated skeleton for the mesh instances.
|
||||||
|
@ -298,6 +299,8 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
|
||||||
int minor_version;
|
int minor_version;
|
||||||
Vector<uint8_t> glb_data;
|
Vector<uint8_t> glb_data;
|
||||||
|
|
||||||
|
bool use_named_skin_binds;
|
||||||
|
|
||||||
Vector<GLTFNode *> nodes;
|
Vector<GLTFNode *> nodes;
|
||||||
Vector<Vector<uint8_t> > buffers;
|
Vector<Vector<uint8_t> > buffers;
|
||||||
Vector<GLTFBufferView> buffer_views;
|
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/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::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::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, "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::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));
|
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)
|
if (int(p_options["materials/location"]) == 0)
|
||||||
import_flags |= EditorSceneImporter::IMPORT_MATERIALS_IN_INSTANCES;
|
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;
|
Error err = OK;
|
||||||
List<String> missing_deps; // for now, not much will be done with this
|
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);
|
Node *scene = importer->import_scene(src_path, import_flags, fps, &missing_deps, &err);
|
||||||
|
|
|
@ -59,7 +59,8 @@ public:
|
||||||
IMPORT_GENERATE_TANGENT_ARRAYS = 256,
|
IMPORT_GENERATE_TANGENT_ARRAYS = 256,
|
||||||
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 512,
|
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 512,
|
||||||
IMPORT_MATERIALS_IN_INSTANCES = 1024,
|
IMPORT_MATERIALS_IN_INSTANCES = 1024,
|
||||||
IMPORT_USE_COMPRESSION = 2048
|
IMPORT_USE_COMPRESSION = 2048,
|
||||||
|
IMPORT_USE_NAMED_SKIN_BINDS = 4096,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ void SkinReference::_skin_changed() {
|
||||||
if (skeleton_node) {
|
if (skeleton_node) {
|
||||||
skeleton_node->_make_dirty();
|
skeleton_node->_make_dirty();
|
||||||
}
|
}
|
||||||
|
skeleton_version = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkinReference::_bind_methods() {
|
void SkinReference::_bind_methods() {
|
||||||
|
@ -321,10 +322,49 @@ void Skeleton::_notification(int p_what) {
|
||||||
if (E->get()->bind_count != bind_count) {
|
if (E->get()->bind_count != bind_count) {
|
||||||
VS::get_singleton()->skeleton_allocate(skeleton, bind_count);
|
VS::get_singleton()->skeleton_allocate(skeleton, bind_count);
|
||||||
E->get()->bind_count = 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++) {
|
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);
|
ERR_CONTINUE(bone_index >= (uint32_t)len);
|
||||||
vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
|
vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
|
||||||
}
|
}
|
||||||
|
@ -366,6 +406,7 @@ void Skeleton::add_bone(const String &p_name) {
|
||||||
b.name = p_name;
|
b.name = p_name;
|
||||||
bones.push_back(b);
|
bones.push_back(b);
|
||||||
process_order_dirty = true;
|
process_order_dirty = true;
|
||||||
|
version++;
|
||||||
_make_dirty();
|
_make_dirty();
|
||||||
update_gizmo();
|
update_gizmo();
|
||||||
}
|
}
|
||||||
|
@ -517,7 +558,7 @@ void Skeleton::clear_bones() {
|
||||||
|
|
||||||
bones.clear();
|
bones.clear();
|
||||||
process_order_dirty = true;
|
process_order_dirty = true;
|
||||||
|
version++;
|
||||||
_make_dirty();
|
_make_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,6 +890,7 @@ void Skeleton::_bind_methods() {
|
||||||
Skeleton::Skeleton() {
|
Skeleton::Skeleton() {
|
||||||
|
|
||||||
dirty = false;
|
dirty = false;
|
||||||
|
version = 1;
|
||||||
process_order_dirty = true;
|
process_order_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,9 @@ class SkinReference : public Reference {
|
||||||
RID skeleton;
|
RID skeleton;
|
||||||
Ref<Skin> skin;
|
Ref<Skin> skin;
|
||||||
uint32_t bind_count = 0;
|
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();
|
void _skin_changed();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -122,6 +125,8 @@ private:
|
||||||
void _make_dirty();
|
void _make_dirty();
|
||||||
bool dirty;
|
bool dirty;
|
||||||
|
|
||||||
|
uint64_t version;
|
||||||
|
|
||||||
// bind helpers
|
// bind helpers
|
||||||
Array _get_bound_child_nodes_to_bone(int p_bone) const {
|
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);
|
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) {
|
void Skin::set_bind_bone(int p_index, int p_bone) {
|
||||||
ERR_FAIL_INDEX(p_index, bind_count);
|
ERR_FAIL_INDEX(p_index, bind_count);
|
||||||
binds_ptr[p_index].bone = p_bone;
|
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") {
|
if (what == "bone") {
|
||||||
set_bind_bone(index, p_value);
|
set_bind_bone(index, p_value);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (what == "name") {
|
||||||
|
set_bind_name(index, p_value);
|
||||||
|
return true;
|
||||||
} else if (what == "pose") {
|
} else if (what == "pose") {
|
||||||
set_bind_pose(index, p_value);
|
set_bind_pose(index, p_value);
|
||||||
return true;
|
return true;
|
||||||
|
@ -95,6 +116,9 @@ bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
|
||||||
if (what == "bone") {
|
if (what == "bone") {
|
||||||
r_ret = get_bind_bone(index);
|
r_ret = get_bind_bone(index);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (what == "name") {
|
||||||
|
r_ret = get_bind_name(index);
|
||||||
|
return true;
|
||||||
} else if (what == "pose") {
|
} else if (what == "pose") {
|
||||||
r_ret = get_bind_pose(index);
|
r_ret = get_bind_pose(index);
|
||||||
return true;
|
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 {
|
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"));
|
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++) {
|
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"));
|
||||||
|
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"));
|
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("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("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("set_bind_bone", "bind_index", "bone"), &Skin::set_bind_bone);
|
||||||
ClassDB::bind_method(D_METHOD("get_bind_bone", "bind_index"), &Skin::get_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)
|
GDCLASS(Skin, Resource)
|
||||||
|
|
||||||
struct Bind {
|
struct Bind {
|
||||||
int bone;
|
int bone = -1;
|
||||||
|
StringName name;
|
||||||
Transform pose;
|
Transform pose;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,9 +59,11 @@ public:
|
||||||
inline int get_bind_count() const { return bind_count; }
|
inline int get_bind_count() const { return bind_count; }
|
||||||
|
|
||||||
void add_bind(int p_bone, const Transform &p_pose);
|
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_bone(int p_index, int p_bone);
|
||||||
void set_bind_pose(int p_index, const Transform &p_pose);
|
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 {
|
inline int get_bind_bone(int p_index) const {
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -69,6 +72,13 @@ public:
|
||||||
return binds_ptr[p_index].bone;
|
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 {
|
inline Transform get_bind_pose(int p_index) const {
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
ERR_FAIL_INDEX_V(p_index, bind_count, Transform());
|
ERR_FAIL_INDEX_V(p_index, bind_count, Transform());
|
||||||
|
|
Loading…
Reference in New Issue