Browse Source

Merge pull request #36008 from AndreaCatania/physical_bone_impr

Skeleton animates physical bones
Rémi Verschelde 5 years ago
parent
commit
23531207a5

+ 6 - 3
editor/plugins/skeleton_editor_plugin.cpp

@@ -103,8 +103,10 @@ void SkeletonEditor::create_physical_skeleton() {
 
 PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) {
 
-	real_t half_height(skeleton->get_bone_rest(bone_child_id).origin.length() * 0.5);
-	real_t radius(half_height * 0.2);
+	const Transform child_rest = skeleton->get_bone_rest(bone_child_id);
+
+	const real_t half_height(child_rest.origin.length() * 0.5);
+	const real_t radius(half_height * 0.2);
 
 	CapsuleShape *bone_shape_capsule = memnew(CapsuleShape);
 	bone_shape_capsule->set_height((half_height - radius) * 2);
@@ -114,7 +116,8 @@ PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_i
 	bone_shape->set_shape(bone_shape_capsule);
 
 	Transform body_transform;
-	body_transform.origin = Vector3(0, 0, -half_height);
+	body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin, Vector3(0, 1, 0));
+	body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height));
 
 	Transform joint_transform;
 	joint_transform.origin = Vector3(0, 0, half_height);

+ 40 - 74
scene/3d/physics_body.cpp

@@ -1562,6 +1562,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;
@@ -2167,7 +2185,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();
 			}
@@ -2238,8 +2256,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);
@@ -2508,26 +2524,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() {
@@ -2535,7 +2538,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) {
@@ -2618,8 +2621,6 @@ PhysicalBone::PhysicalBone() :
 #endif
 		joint_data(NULL),
 		parent_skeleton(NULL),
-		static_body(false),
-		_internal_static_body(false),
 		simulate_physics(false),
 		_internal_simulate_physics(false),
 		bone_id(-1),
@@ -2629,8 +2630,7 @@ PhysicalBone::PhysicalBone() :
 		friction(1),
 		gravity_scale(1) {
 
-	set_static_body(static_body);
-	_reset_physics_simulation_state();
+	reset_physics_simulation_state();
 }
 
 PhysicalBone::~PhysicalBone() {
@@ -2657,8 +2657,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();
 	}
 }
 
@@ -2680,49 +2679,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;
@@ -2732,17 +2688,27 @@ 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(), NULL, "");
-	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;
+	}
 }

+ 3 - 9
scene/3d/physics_body.h

@@ -562,8 +562,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;
@@ -613,9 +611,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();
@@ -641,16 +636,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();

+ 53 - 10
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/surface_tool.h"
@@ -332,6 +333,27 @@ void Skeleton::_notification(int p_what) {
 
 			dirty = false;
 		} 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
 	}
 }
 
@@ -584,6 +606,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);
@@ -653,12 +696,14 @@ void _pb_stop_simulation(Node *p_node) {
 	PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
 	if (pb) {
 		pb->set_simulate_physics(false);
-		pb->set_static_body(false);
 	}
 }
 
 void Skeleton::physical_bones_stop_simulation() {
 	_pb_stop_simulation(this);
+	if (Engine::get_singleton()->is_editor_hint() == false && animate_physical_bones) {
+		set_physics_process_internal(true);
+	}
 }
 
 void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
@@ -669,24 +714,17 @@ void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector
 
 	PhysicalBone *pb = Object::cast_to<PhysicalBone>(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<int> sim_bones;
 	if (p_bones.size() <= 0) {
@@ -836,11 +874,15 @@ void Skeleton::_bind_methods() {
 
 #ifndef _3D_DISABLED
 
+	ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton::set_animate_physical_bones);
+	ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton::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);
 	ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception);
 
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
 #endif // _3D_DISABLED
 
 	BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
@@ -848,6 +890,7 @@ void Skeleton::_bind_methods() {
 
 Skeleton::Skeleton() {
 
+	animate_physical_bones = true;
 	dirty = false;
 	process_order_dirty = true;
 }

+ 4 - 0
scene/3d/skeleton.h

@@ -115,6 +115,7 @@ private:
 		}
 	};
 
+	bool animate_physical_bones;
 	Vector<Bone> bones;
 	Vector<int> process_order;
 	bool process_order_dirty;
@@ -199,6 +200,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);