Add mutable_bone_axes to IKs

This commit is contained in:
Silc Lizard (Tokage) Renew
2025-11-15 06:17:24 +09:00
parent ef34c3d534
commit 031fd66fed
18 changed files with 760 additions and 155 deletions

View File

@@ -258,7 +258,7 @@ void ChainIK3D::set_extend_end_bone(int p_index, bool p_enabled) {
}
notify_property_list_changed();
#ifdef TOOLS_ENABLED
update_gizmos();
_make_gizmo_dirty();
#endif // TOOLS_ENABLED
}
@@ -270,14 +270,17 @@ bool ChainIK3D::is_end_bone_extended(int p_index) const {
void ChainIK3D::set_end_bone_direction(int p_index, BoneDirection p_bone_direction) {
ERR_FAIL_INDEX(p_index, (int)settings.size());
chain_settings[p_index]->end_bone_direction = p_bone_direction;
_make_simulation_dirty(p_index);
Skeleton3D *sk = get_skeleton();
if (sk && !chain_settings[p_index]->joints.is_empty()) {
_validate_axis(sk, p_index, chain_settings[p_index]->joints.size() - 1);
}
#ifdef TOOLS_ENABLED
update_gizmos();
_make_gizmo_dirty();
#endif // TOOLS_ENABLED
if (mutable_bone_axes) {
return; // Chain dir will be recaluclated in _update_bone_axis().
}
_make_simulation_dirty(p_index);
}
SkeletonModifier3D::BoneDirection ChainIK3D::get_end_bone_direction(int p_index) const {
@@ -287,11 +290,15 @@ SkeletonModifier3D::BoneDirection ChainIK3D::get_end_bone_direction(int p_index)
void ChainIK3D::set_end_bone_length(int p_index, float p_length) {
ERR_FAIL_INDEX(p_index, (int)settings.size());
float old = chain_settings[p_index]->end_bone_length;
chain_settings[p_index]->end_bone_length = p_length;
_make_simulation_dirty(p_index);
#ifdef TOOLS_ENABLED
update_gizmos();
_make_gizmo_dirty();
#endif // TOOLS_ENABLED
if (mutable_bone_axes && Math::is_zero_approx(old) == Math::is_zero_approx(p_length)) {
return; // If chain size is not changed, length will be recaluclated in _update_bone_axis().
}
_make_simulation_dirty(p_index);
}
float ChainIK3D::get_end_bone_length(int p_index) const {
@@ -472,7 +479,7 @@ void ChainIK3D::_update_joints(int p_index) {
}
#ifdef TOOLS_ENABLED
update_gizmos();
_make_gizmo_dirty();
#endif // TOOLS_ENABLED
}
@@ -480,6 +487,59 @@ void ChainIK3D::_process_ik(Skeleton3D *p_skeleton, double p_delta) {
//
}
#ifdef TOOLS_ENABLED
void ChainIK3D::_update_mutable_info() {
if (!is_inside_tree()) {
return;
}
Skeleton3D *skeleton = get_skeleton();
if (!skeleton) {
for (uint32_t i = 0; i < settings.size(); i++) {
chain_settings[i]->root_global_rest = Transform3D();
}
}
bool changed = false;
for (uint32_t i = 0; i < settings.size(); i++) {
int root_bone = chain_settings[i]->root_bone.bone;
if (root_bone < 0) {
continue;
}
Transform3D new_tr = get_bone_global_rest_mutable(skeleton, root_bone);
changed = changed || !chain_settings[i]->root_global_rest.is_equal_approx(new_tr);
chain_settings[i]->root_global_rest = new_tr;
}
if (changed) {
_make_gizmo_dirty();
}
}
Transform3D ChainIK3D::get_bone_global_rest_mutable(Skeleton3D *p_skeleton, int p_bone) {
int current = p_bone;
Transform3D accum;
int parent = p_skeleton->get_bone_parent(current);
if (parent >= 0) {
accum = p_skeleton->get_bone_global_rest(parent);
}
Transform3D tr = p_skeleton->get_bone_rest(current);
// Note:
// Chain IK gizmo might not be able to retrieve this pose in SkeletonModifier update process.
// So the gizmo uses bone_vector insteads but parent of root bone doesn't have bone_vector.
// Then, we needs to cache this pose in IK node.
tr.origin = p_skeleton->get_bone_pose_position(current);
accum *= tr;
return accum;
}
Transform3D ChainIK3D::get_chain_root_global_rest(int p_index) {
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), Transform3D());
return chain_settings[p_index]->root_global_rest;
}
Vector3 ChainIK3D::get_bone_vector(int p_index, int p_joint) const {
return Vector3();
}
#endif // TOOLS_ENABLED
ChainIK3D::~ChainIK3D() {
clear_settings();
}