diff options
Diffstat (limited to 'scene/animation/skeleton_ik.cpp')
| -rw-r--r-- | scene/animation/skeleton_ik.cpp | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index cda70c97c9..3119e29586 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -34,6 +34,8 @@ #include "skeleton_ik.h" +#ifndef _3D_DISABLED + FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) { for (int i = childs.size() - 1; 0 <= i; --i) { if (p_bone_id == childs[i].bone) { @@ -52,9 +54,9 @@ FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child( } /// Build a chain that starts from the root to tip -void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) { +bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) { - ERR_FAIL_COND(-1 == p_task->root_bone); + ERR_FAIL_COND_V(-1 == p_task->root_bone, false); Chain &chain(p_task->chain); @@ -75,8 +77,8 @@ void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain for (int x = p_task->end_effectors.size() - 1; 0 <= x; --x) { const EndEffector *ee(&p_task->end_effectors[x]); - ERR_FAIL_COND(p_task->root_bone >= ee->tip_bone); - ERR_FAIL_INDEX(ee->tip_bone, p_task->skeleton->get_bone_count()); + ERR_FAIL_COND_V(p_task->root_bone >= ee->tip_bone, false); + ERR_FAIL_INDEX_V(ee->tip_bone, p_task->skeleton->get_bone_count(), false); sub_chain_size = 0; // Picks all IDs that composing a single chain in reverse order (except the root) @@ -131,6 +133,7 @@ void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain break; } } + return true; } void FabrikInverseKinematic::update_chain(const Skeleton *p_sk, ChainItem *p_chain_item) { @@ -245,7 +248,10 @@ FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleto task->end_effectors.push_back(ee); task->goal_global_transform = goal_transform; - build_chain(task); + if (!build_chain(task)) { + free_task(task); + return NULL; + } return task; } @@ -274,7 +280,7 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_ } } -void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool p_use_magnet, const Vector3 &p_magnet_position) { +void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position) { if (blending_delta <= 0.01f) { return; // Skip solving @@ -308,7 +314,10 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool p_u } } else { // Set target orientation to tip - new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis; + if (override_tip_basis) + new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis; + else + new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis; } p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose); @@ -360,6 +369,9 @@ void SkeletonIK::_bind_methods() { ClassDB::bind_method(D_METHOD("set_target_node", "node"), &SkeletonIK::set_target_node); ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonIK::get_target_node); + ClassDB::bind_method(D_METHOD("set_override_tip_basis", "override"), &SkeletonIK::set_override_tip_basis); + ClassDB::bind_method(D_METHOD("is_override_tip_basis"), &SkeletonIK::is_override_tip_basis); + ClassDB::bind_method(D_METHOD("set_use_magnet", "use"), &SkeletonIK::set_use_magnet); ClassDB::bind_method(D_METHOD("is_using_magnet"), &SkeletonIK::is_using_magnet); @@ -381,7 +393,8 @@ void SkeletonIK::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_bone"), "set_root_bone", "get_root_bone"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "tip_bone"), "set_tip_bone", "get_tip_bone"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target", "get_target"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_tip_basis"), "set_override_tip_basis", "is_override_tip_basis"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node"), "set_target_node", "get_target_node"); @@ -412,11 +425,12 @@ void SkeletonIK::_notification(int p_what) { SkeletonIK::SkeletonIK() : Node(), interpolation(1), - skeleton(NULL), - target_node_override(NULL), + override_tip_basis(true), use_magnet(false), min_distance(0.01), max_iterations(10), + skeleton(NULL), + target_node_override(NULL), task(NULL) { set_process_priority(1); @@ -472,6 +486,14 @@ NodePath SkeletonIK::get_target_node() { return target_node_path_override; } +void SkeletonIK::set_override_tip_basis(bool p_override) { + override_tip_basis = p_override; +} + +bool SkeletonIK::is_override_tip_basis() const { + return override_tip_basis; +} + void SkeletonIK::set_use_magnet(bool p_use) { use_magnet = p_use; } @@ -533,8 +555,10 @@ void SkeletonIK::reload_chain() { return; task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform()); - task->max_iterations = max_iterations; - task->min_distance = min_distance; + if (task) { + task->max_iterations = max_iterations; + task->min_distance = min_distance; + } } void SkeletonIK::reload_goal() { @@ -547,5 +571,7 @@ void SkeletonIK::reload_goal() { void SkeletonIK::_solve_chain() { if (!task) return; - FabrikInverseKinematic::solve(task, interpolation, use_magnet, magnet_position); + FabrikInverseKinematic::solve(task, interpolation, override_tip_basis, use_magnet, magnet_position); } + +#endif // _3D_DISABLED |
