Backported: Added feature to move physical bones with skeleton when not simulating physics. - AndreaCatania

374432d074
This commit is contained in:
Relintai 2022-08-09 19:19:50 +02:00
parent 3b0c27d89c
commit 3d4a55a1a3
4 changed files with 106 additions and 90 deletions

View File

@ -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); 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) { bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
if (JointData::_set(p_name, p_value, j)) { if (JointData::_set(p_name, p_value, j)) {
return true; return true;
@ -2301,7 +2319,7 @@ void PhysicalBone::_notification(int p_what) {
parent_skeleton = find_skeleton_parent(get_parent()); parent_skeleton = find_skeleton_parent(get_parent());
update_bone_id(); update_bone_id();
reset_to_rest_position(); reset_to_rest_position();
_reset_physics_simulation_state(); reset_physics_simulation_state();
if (!joint.is_valid() && joint_data) { if (!joint.is_valid() && joint_data) {
_reload_joint(); _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("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("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("get_simulate_physics"), &PhysicalBone::get_simulate_physics);
ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_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; 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) { void PhysicalBone::set_simulate_physics(bool p_simulate) {
if (simulate_physics == p_simulate) { if (simulate_physics == p_simulate) {
return; return;
} }
simulate_physics = p_simulate; simulate_physics = p_simulate;
_reset_physics_simulation_state(); reset_physics_simulation_state();
} }
bool PhysicalBone::get_simulate_physics() { bool PhysicalBone::get_simulate_physics() {
@ -2662,7 +2666,7 @@ bool PhysicalBone::get_simulate_physics() {
} }
bool PhysicalBone::is_simulating_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) { void PhysicalBone::set_bone_name(const String &p_name) {
@ -2733,8 +2737,6 @@ PhysicalBone::PhysicalBone() :
#endif #endif
joint_data(nullptr), joint_data(nullptr),
parent_skeleton(nullptr), parent_skeleton(nullptr),
static_body(false),
_internal_static_body(false),
simulate_physics(false), simulate_physics(false),
_internal_simulate_physics(false), _internal_simulate_physics(false),
bone_id(-1), bone_id(-1),
@ -2744,8 +2746,7 @@ PhysicalBone::PhysicalBone() :
friction(1), friction(1),
gravity_scale(1) { gravity_scale(1) {
set_static_body(static_body); reset_physics_simulation_state();
_reset_physics_simulation_state();
} }
PhysicalBone::~PhysicalBone() { PhysicalBone::~PhysicalBone() {
@ -2773,8 +2774,7 @@ void PhysicalBone::update_bone_id() {
parent_skeleton->bind_physical_bone_to_bone(bone_id, this); parent_skeleton->bind_physical_bone_to_bone(bone_id, this);
_fix_joint_offset(); _fix_joint_offset();
_internal_static_body = !static_body; // Force staticness reset reset_physics_simulation_state();
_reset_staticness_state();
} }
} }
@ -2796,47 +2796,6 @@ void PhysicalBone::update_offset() {
#endif #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() { void PhysicalBone::_start_physics_simulation() {
if (_internal_simulate_physics || !parent_skeleton) { if (_internal_simulate_physics || !parent_skeleton) {
return; 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_layer(get_rid(), get_collision_layer());
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); 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"); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
set_as_toplevel(true);
_internal_simulate_physics = true; _internal_simulate_physics = true;
} }
void PhysicalBone::_stop_physics_simulation() { void PhysicalBone::_stop_physics_simulation() {
if (!_internal_simulate_physics || !parent_skeleton) { if (!parent_skeleton) {
return; return;
} }
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_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC);
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); 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_collision_mask(get_rid(), 0);
PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, ""); }
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); parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
set_as_toplevel(false);
_internal_simulate_physics = false; _internal_simulate_physics = false;
} }
}

View File

@ -571,8 +571,6 @@ private:
Skeleton *parent_skeleton; Skeleton *parent_skeleton;
Transform body_offset; Transform body_offset;
Transform body_offset_inverse; Transform body_offset_inverse;
bool static_body;
bool _internal_static_body;
bool simulate_physics; bool simulate_physics;
bool _internal_simulate_physics; bool _internal_simulate_physics;
int bone_id; int bone_id;
@ -622,9 +620,6 @@ public:
void set_body_offset(const Transform &p_offset); void set_body_offset(const Transform &p_offset);
const Transform &get_body_offset() const; const Transform &get_body_offset() const;
void set_static_body(bool p_static);
bool is_static_body();
void set_simulate_physics(bool p_simulate); void set_simulate_physics(bool p_simulate);
bool get_simulate_physics(); bool get_simulate_physics();
bool is_simulating_physics(); bool is_simulating_physics();
@ -650,16 +645,15 @@ public:
void apply_central_impulse(const Vector3 &p_impulse); void apply_central_impulse(const Vector3 &p_impulse);
void apply_impulse(const Vector3 &p_pos, 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();
~PhysicalBone(); ~PhysicalBone();
private: private:
void update_bone_id(); void update_bone_id();
void update_offset(); void update_offset();
void reset_to_rest_position();
void _reset_physics_simulation_state();
void _reset_staticness_state();
void _start_physics_simulation(); void _start_physics_simulation();
void _stop_physics_simulation(); void _stop_physics_simulation();

View File

@ -32,6 +32,7 @@
#include "core/message_queue.h" #include "core/message_queue.h"
#include "core/engine.h"
#include "core/project_settings.h" #include "core/project_settings.h"
#include "scene/3d/physics_body.h" #include "scene/3d/physics_body.h"
#include "scene/resources/skin.h" #include "scene/resources/skin.h"
@ -371,6 +372,27 @@ void Skeleton::_notification(int p_what) {
dirty = false; dirty = false;
emit_signal("skeleton_updated"); emit_signal("skeleton_updated");
} break; } 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]; return process_order[p_idx];
} }
Vector<int> Skeleton::get_bone_process_orders() {
_update_process_order();
return process_order;
}
void Skeleton::localize_rests() { void Skeleton::localize_rests() {
_update_process_order(); _update_process_order();
@ -687,6 +714,27 @@ void Skeleton::localize_rests() {
#ifndef _3D_DISABLED #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) { void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) {
ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_INDEX(p_bone, bones.size());
ERR_FAIL_COND(bones[p_bone].physical_bone); ERR_FAIL_COND(bones[p_bone].physical_bone);
@ -756,7 +804,6 @@ void _pb_stop_simulation(Node *p_node) {
PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node); PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
if (pb) { if (pb) {
pb->set_simulate_physics(false); 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<PhysicalBone>(p_node); PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
if (pb) { if (pb) {
bool sim = false;
for (int i = p_sim_bones.size() - 1; 0 <= i; --i) { 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])) { 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; 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) { void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
set_physics_process_internal(false);
Vector<int> sim_bones; Vector<int> sim_bones;
if (p_bones.size() <= 0) { if (p_bones.size() <= 0) {
sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body 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("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("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("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); 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 #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_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_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); 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() { Skeleton::Skeleton() {
animate_physical_bones = true;
dirty = false; dirty = false;
version = 1; version = 1;
process_order_dirty = true; process_order_dirty = true;

View File

@ -134,6 +134,7 @@ private:
} }
}; };
bool animate_physical_bones;
Vector<Bone> bones; Vector<Bone> bones;
Vector<int> process_order; Vector<int> process_order;
bool process_order_dirty; bool process_order_dirty;
@ -221,6 +222,7 @@ public:
void localize_rests(); // used for loaders and tools void localize_rests(); // used for loaders and tools
int get_process_order(int p_idx); int get_process_order(int p_idx);
Vector<int> get_bone_process_orders();
Ref<Skin> create_skin_from_rest_transforms(); Ref<Skin> create_skin_from_rest_transforms();
@ -235,6 +237,9 @@ public:
#ifndef _3D_DISABLED #ifndef _3D_DISABLED
// Physical bone API // 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 bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone);
void unbind_physical_bone_from_bone(int p_bone); void unbind_physical_bone_from_bone(int p_bone);