From 3d4a55a1a3469458c9c16ebee00869b6b61e4f48 Mon Sep 17 00:00:00 2001 From: Relintai Date: Tue, 9 Aug 2022 19:19:50 +0200 Subject: [PATCH] Backported: Added feature to move physical bones with skeleton when not simulating physics. - AndreaCatania https://github.com/godotengine/godot/commit/374432d0744208751eb752226b9284f6d1e247fc --- scene/3d/physics_body.cpp | 112 ++++++++++++++------------------------ scene/3d/physics_body.h | 12 +--- scene/3d/skeleton.cpp | 67 +++++++++++++++++++---- scene/3d/skeleton.h | 5 ++ 4 files changed, 106 insertions(+), 90 deletions(-) diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 853effb02..0c1e2e42d 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1644,6 +1644,24 @@ void PhysicalBone::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); } +void PhysicalBone::reset_physics_simulation_state() { + if (simulate_physics) { + _start_physics_simulation(); + } else { + _stop_physics_simulation(); + } +} + +void PhysicalBone::reset_to_rest_position() { + if (parent_skeleton) { + if (-1 == bone_id) { + set_global_transform(parent_skeleton->get_global_transform() * body_offset); + } else { + set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset); + } + } +} + bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { if (JointData::_set(p_name, p_value, j)) { return true; @@ -2301,7 +2319,7 @@ void PhysicalBone::_notification(int p_what) { parent_skeleton = find_skeleton_parent(get_parent()); update_bone_id(); reset_to_rest_position(); - _reset_physics_simulation_state(); + reset_physics_simulation_state(); if (!joint.is_valid() && joint_data) { _reload_joint(); } @@ -2368,8 +2386,6 @@ void PhysicalBone::_bind_methods() { ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset); ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset); - ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body); - ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics); ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics); @@ -2636,25 +2652,13 @@ const Transform &PhysicalBone::get_joint_offset() const { return joint_offset; } -void PhysicalBone::set_static_body(bool p_static) { - static_body = p_static; - - set_as_toplevel(!static_body); - - _reset_physics_simulation_state(); -} - -bool PhysicalBone::is_static_body() { - return static_body; -} - void PhysicalBone::set_simulate_physics(bool p_simulate) { if (simulate_physics == p_simulate) { return; } simulate_physics = p_simulate; - _reset_physics_simulation_state(); + reset_physics_simulation_state(); } bool PhysicalBone::get_simulate_physics() { @@ -2662,7 +2666,7 @@ bool PhysicalBone::get_simulate_physics() { } bool PhysicalBone::is_simulating_physics() { - return _internal_simulate_physics && !_internal_static_body; + return _internal_simulate_physics; } void PhysicalBone::set_bone_name(const String &p_name) { @@ -2733,8 +2737,6 @@ PhysicalBone::PhysicalBone() : #endif joint_data(nullptr), parent_skeleton(nullptr), - static_body(false), - _internal_static_body(false), simulate_physics(false), _internal_simulate_physics(false), bone_id(-1), @@ -2744,8 +2746,7 @@ PhysicalBone::PhysicalBone() : friction(1), gravity_scale(1) { - set_static_body(static_body); - _reset_physics_simulation_state(); + reset_physics_simulation_state(); } PhysicalBone::~PhysicalBone() { @@ -2773,8 +2774,7 @@ void PhysicalBone::update_bone_id() { parent_skeleton->bind_physical_bone_to_bone(bone_id, this); _fix_joint_offset(); - _internal_static_body = !static_body; // Force staticness reset - _reset_staticness_state(); + reset_physics_simulation_state(); } } @@ -2796,47 +2796,6 @@ void PhysicalBone::update_offset() { #endif } -void PhysicalBone::reset_to_rest_position() { - if (parent_skeleton) { - if (-1 == bone_id) { - set_global_transform(parent_skeleton->get_global_transform() * body_offset); - } else { - set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset); - } - } -} - -void PhysicalBone::_reset_physics_simulation_state() { - if (simulate_physics && !static_body) { - _start_physics_simulation(); - } else { - _stop_physics_simulation(); - } - - _reset_staticness_state(); -} - -void PhysicalBone::_reset_staticness_state() { - if (parent_skeleton && -1 != bone_id) { - if (static_body && simulate_physics) { // With this check I'm sure the position of this body is updated only when it's necessary - - if (_internal_static_body) { - return; - } - - parent_skeleton->bind_child_node_to_bone(bone_id, this); - _internal_static_body = true; - } else { - if (!_internal_static_body) { - return; - } - - parent_skeleton->unbind_child_node_from_bone(bone_id, this); - _internal_static_body = false; - } - } -} - void PhysicalBone::_start_physics_simulation() { if (_internal_simulate_physics || !parent_skeleton) { return; @@ -2846,17 +2805,28 @@ void PhysicalBone::_start_physics_simulation() { PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); + set_as_toplevel(true); _internal_simulate_physics = true; } void PhysicalBone::_stop_physics_simulation() { - if (!_internal_simulate_physics || !parent_skeleton) { + if (!parent_skeleton) { return; } - PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC); - PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); - PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, ""); - parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); - _internal_simulate_physics = false; + + if (parent_skeleton->get_animate_physical_bones()) { + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_KINEMATIC); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + } else { + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); + } + if (_internal_simulate_physics) { + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); + parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); + set_as_toplevel(false); + _internal_simulate_physics = false; + } } diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 6a05498b8..f05fa2ee0 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -571,8 +571,6 @@ private: Skeleton *parent_skeleton; Transform body_offset; Transform body_offset_inverse; - bool static_body; - bool _internal_static_body; bool simulate_physics; bool _internal_simulate_physics; int bone_id; @@ -622,9 +620,6 @@ public: void set_body_offset(const Transform &p_offset); const Transform &get_body_offset() const; - void set_static_body(bool p_static); - bool is_static_body(); - void set_simulate_physics(bool p_simulate); bool get_simulate_physics(); bool is_simulating_physics(); @@ -650,16 +645,15 @@ public: void apply_central_impulse(const Vector3 &p_impulse); void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); + void reset_physics_simulation_state(); + void reset_to_rest_position(); + PhysicalBone(); ~PhysicalBone(); private: void update_bone_id(); void update_offset(); - void reset_to_rest_position(); - - void _reset_physics_simulation_state(); - void _reset_staticness_state(); void _start_physics_simulation(); void _stop_physics_simulation(); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 2cd4efc76..55235b9ee 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -32,6 +32,7 @@ #include "core/message_queue.h" +#include "core/engine.h" #include "core/project_settings.h" #include "scene/3d/physics_body.h" #include "scene/resources/skin.h" @@ -371,6 +372,27 @@ void Skeleton::_notification(int p_what) { dirty = false; emit_signal("skeleton_updated"); } break; + +#ifndef _3D_DISABLED + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // This is active only if the skeleton animates the physical bones + // and the state of the bone is not active. + if (animate_physical_bones) { + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + if (bones[i].physical_bone->is_simulating_physics() == false) { + bones[i].physical_bone->reset_to_rest_position(); + } + } + } + } + } break; + case NOTIFICATION_READY: { + if (Engine::get_singleton()->is_editor_hint()) { + set_physics_process_internal(true); + } + } break; +#endif } } @@ -674,6 +696,11 @@ int Skeleton::get_process_order(int p_idx) { return process_order[p_idx]; } +Vector Skeleton::get_bone_process_orders() { + _update_process_order(); + return process_order; +} + void Skeleton::localize_rests() { _update_process_order(); @@ -687,6 +714,27 @@ void Skeleton::localize_rests() { #ifndef _3D_DISABLED +void Skeleton::set_animate_physical_bones(bool p_animate) { + animate_physical_bones = p_animate; + + if (Engine::get_singleton()->is_editor_hint() == false) { + bool sim = false; + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + bones[i].physical_bone->reset_physics_simulation_state(); + if (bones[i].physical_bone->is_simulating_physics()) { + sim = true; + } + } + } + set_physics_process_internal(sim == false && p_animate); + } +} + +bool Skeleton::get_animate_physical_bones() const { + return animate_physical_bones; +} + void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) { ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_COND(bones[p_bone].physical_bone); @@ -756,7 +804,6 @@ void _pb_stop_simulation(Node *p_node) { PhysicalBone *pb = Object::cast_to(p_node); if (pb) { pb->set_simulate_physics(false); - pb->set_static_body(false); } } @@ -771,24 +818,18 @@ void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector PhysicalBone *pb = Object::cast_to(p_node); if (pb) { - bool sim = false; for (int i = p_sim_bones.size() - 1; 0 <= i; --i) { if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) { - sim = true; + pb->set_simulate_physics(true); break; } } - - pb->set_simulate_physics(true); - if (sim) { - pb->set_static_body(false); - } else { - pb->set_static_body(true); - } } } void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) { + set_physics_process_internal(false); + Vector sim_bones; if (p_bones.size() <= 0) { sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body @@ -986,6 +1027,7 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("local_pose_to_global_pose", "bone_idx", "local_pose"), &Skeleton::local_pose_to_global_pose); ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests); + ClassDB::bind_method(D_METHOD("get_bone_process_orders"), &Skeleton::get_bone_process_orders); ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest); ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton::is_bone_rest_disabled); @@ -1016,6 +1058,10 @@ void Skeleton::_bind_methods() { #ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton::get_animate_physical_bones); + ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton::set_animate_physical_bones); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones"); + ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception); @@ -1031,6 +1077,7 @@ void Skeleton::_bind_methods() { } Skeleton::Skeleton() { + animate_physical_bones = true; dirty = false; version = 1; process_order_dirty = true; diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index 228df2c57..a67b20edf 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -134,6 +134,7 @@ private: } }; + bool animate_physical_bones; Vector bones; Vector process_order; bool process_order_dirty; @@ -221,6 +222,7 @@ public: void localize_rests(); // used for loaders and tools int get_process_order(int p_idx); + Vector get_bone_process_orders(); Ref create_skin_from_rest_transforms(); @@ -235,6 +237,9 @@ public: #ifndef _3D_DISABLED // Physical bone API + void set_animate_physical_bones(bool p_animate); + bool get_animate_physical_bones() const; + void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone); void unbind_physical_bone_from_bone(int p_bone);