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

@ -189,6 +189,9 @@ void SplineIK3D::_init_joints(Skeleton3D *p_skeleton, int p_index) {
SplineIK3DSetting *setting = sp_settings[p_index];
cached_space = p_skeleton->get_global_transform_interpolated();
if (!setting->simulation_dirty) {
if (mutable_bone_axes) {
_update_bone_axis(p_skeleton, p_index);
}
return;
}
for (uint32_t i = 0; i < setting->solver_info_list.size(); i++) {
@ -205,7 +208,7 @@ void SplineIK3D::_init_joints(Skeleton3D *p_skeleton, int p_index) {
setting->chain.push_back(p_skeleton->get_bone_global_pose(setting->joints[i].bone).origin);
bool last = i == setting->joints.size() - 1;
if (last && extend_end_bone && setting->end_bone_length > 0) {
Vector3 axis = get_bone_axis(setting->end_bone.bone, setting->end_bone_direction);
Vector3 axis = IKModifier3D::get_bone_axis(p_skeleton, setting->end_bone.bone, setting->end_bone_direction, mutable_bone_axes);
if (axis.is_zero_approx()) {
setting->chain_length_accum[i] = accum;
continue;
@ -230,6 +233,14 @@ void SplineIK3D::_init_joints(Skeleton3D *p_skeleton, int p_index) {
setting->chain_length_accum[i] = accum;
}
if (mutable_bone_axes) {
_update_bone_axis(p_skeleton, p_index);
#ifdef TOOLS_ENABLED
} else {
_make_gizmo_dirty();
#endif // TOOLS_ENABLED
}
setting->init_current_joint_rotations(p_skeleton);
setting->simulation_dirty = false;
@ -243,6 +254,56 @@ void SplineIK3D::_make_simulation_dirty(int p_index) {
setting->simulation_dirty = true;
}
void SplineIK3D::_update_bone_axis(Skeleton3D *p_skeleton, int p_index) {
#ifdef TOOLS_ENABLED
bool changed = false;
#endif // TOOLS_ENABLED
SplineIK3DSetting *setting = sp_settings[p_index];
const LocalVector<BoneJoint> &joints = setting->joints;
const LocalVector<IKModifier3DSolverInfo *> &solver_info_list = setting->solver_info_list;
int len = (int)solver_info_list.size() - 1;
for (int j = 0; j < len; j++) {
if (!solver_info_list[j]) {
continue;
}
Vector3 axis = p_skeleton->get_bone_pose(joints[j + 1].bone).origin;
if (axis.is_zero_approx()) {
continue;
}
// Less computing.
#ifdef TOOLS_ENABLED
if (!changed) {
Vector3 old_v = solver_info_list[j]->forward_vector;
solver_info_list[j]->forward_vector = axis.normalized();
changed = changed || !old_v.is_equal_approx(solver_info_list[j]->forward_vector);
float old_l = solver_info_list[j]->length;
solver_info_list[j]->length = axis.length();
changed = changed || !Math::is_equal_approx(old_l, solver_info_list[j]->length);
} else {
solver_info_list[j]->forward_vector = axis.normalized();
solver_info_list[j]->length = axis.length();
}
#else
solver_info_list[j]->forward_vector = axis.normalized();
solver_info_list[j]->length = axis.length();
#endif // TOOLS_ENABLED
}
if (setting->extend_end_bone && len >= 0) {
if (solver_info_list[len]) {
Vector3 axis = IKModifier3D::get_bone_axis(p_skeleton, setting->end_bone.bone, setting->end_bone_direction, mutable_bone_axes);
if (!axis.is_zero_approx()) {
solver_info_list[len]->forward_vector = axis.normalized();
solver_info_list[len]->length = setting->end_bone_length;
}
}
}
#ifdef TOOLS_ENABLED
if (changed) {
_make_gizmo_dirty();
}
#endif // TOOLS_ENABLED
}
void SplineIK3D::_process_ik(Skeleton3D *p_skeleton, double p_delta) {
for (uint32_t i = 0; i < settings.size(); i++) {
_init_joints(p_skeleton, i);
@ -430,6 +491,30 @@ void SplineIK3D::_process_joints(double p_delta, Skeleton3D *p_skeleton, SplineI
}
}
#ifdef TOOLS_ENABLED
Vector3 SplineIK3D::get_bone_vector(int p_index, int p_joint) const {
Skeleton3D *skeleton = get_skeleton();
if (!skeleton) {
return Vector3();
}
ERR_FAIL_INDEX_V(p_index, (int)settings.size(), Vector3());
SplineIK3DSetting *setting = sp_settings[p_index];
if (!setting) {
return Vector3();
}
const LocalVector<BoneJoint> &joints = setting->joints;
ERR_FAIL_INDEX_V(p_joint, (int)joints.size(), Vector3());
const LocalVector<IKModifier3DSolverInfo *> &solver_info_list = setting->solver_info_list;
if (p_joint >= (int)solver_info_list.size() || !solver_info_list[p_joint]) {
if (p_joint == (int)joints.size() - 1) {
return IKModifier3D::get_bone_axis(skeleton, setting->end_bone.bone, setting->end_bone_direction, mutable_bone_axes) * setting->end_bone_length;
}
return mutable_bone_axes ? skeleton->get_bone_pose(joints[p_joint + 1].bone).origin : skeleton->get_bone_rest(joints[p_joint + 1].bone).origin;
}
return solver_info_list[p_joint]->forward_vector * solver_info_list[p_joint]->length;
}
#endif // TOOLS_ENABLED
SplineIK3D::~SplineIK3D() {
clear_settings();
}