diff options
Diffstat (limited to 'scene')
26 files changed, 1357 insertions, 627 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index e9bab274c6..4b866fc6de 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -627,7 +627,7 @@ void Camera2D::align() { } void Camera2D::set_position_smoothing_speed(real_t p_speed) { - position_smoothing_speed = p_speed; + position_smoothing_speed = MAX(0, p_speed); _update_process_internal_for_smoothing(); } @@ -636,7 +636,7 @@ real_t Camera2D::get_position_smoothing_speed() const { } void Camera2D::set_rotation_smoothing_speed(real_t p_speed) { - rotation_smoothing_speed = p_speed; + rotation_smoothing_speed = MAX(0, p_speed); _update_process_internal_for_smoothing(); } diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index 76e89f24d8..221200284d 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -187,7 +187,7 @@ void BoneAttachment3D::_transform_changed() { return; } - if (override_pose) { + if (override_pose && !overriding) { Skeleton3D *sk = _get_skeleton3d(); ERR_FAIL_NULL_MSG(sk, "Cannot override pose: Skeleton not found!"); @@ -198,8 +198,11 @@ void BoneAttachment3D::_transform_changed() { our_trans = sk->get_global_transform().affine_inverse() * get_global_transform(); } - sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true); + overriding = true; + sk->set_bone_global_pose(bone_idx, our_trans); + sk->force_update_all_dirty_bones(); } + overriding = false; } void BoneAttachment3D::set_bone_name(const String &p_name) { @@ -246,14 +249,6 @@ void BoneAttachment3D::set_override_pose(bool p_override) { override_pose = p_override; set_notify_transform(override_pose); set_process_internal(override_pose); - - if (!override_pose) { - Skeleton3D *sk = _get_skeleton3d(); - if (sk) { - sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); - } - _transform_changed(); - } notify_property_list_changed(); } @@ -314,6 +309,10 @@ void BoneAttachment3D::_notification(int p_what) { } void BoneAttachment3D::on_bone_pose_update(int p_bone_index) { + if (updating) { + return; + } + updating = true; if (bone_idx == p_bone_index) { Skeleton3D *sk = _get_skeleton3d(); if (sk) { @@ -331,6 +330,7 @@ void BoneAttachment3D::on_bone_pose_update(int p_bone_index) { } } } + updating = false; } #ifdef TOOLS_ENABLED void BoneAttachment3D::notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Dictionary p_rename_map) { diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index 1bf44c2756..ec0f7344d7 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -45,6 +45,7 @@ class BoneAttachment3D : public Node3D { bool override_pose = false; bool _override_dirty = false; + bool overriding = false; bool use_external_skeleton = false; NodePath external_skeleton_node; @@ -53,6 +54,7 @@ class BoneAttachment3D : public Node3D { void _check_bind(); void _check_unbind(); + bool updating = false; void _transform_changed(); void _update_external_skeleton_cache(); Skeleton3D *_get_skeleton3d(); diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index caabb4225f..8415fb38cb 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -231,7 +231,7 @@ void Decal::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_emission", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION); ADD_GROUP("Parameters", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_emission_energy", "get_emission_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "albedo_mix", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_albedo_mix", "get_albedo_mix"); // A Normal Fade of 1.0 causes the decal to be invisible even if fully perpendicular to a surface. diff --git a/scene/3d/physical_bone_simulator_3d.cpp b/scene/3d/physical_bone_simulator_3d.cpp new file mode 100644 index 0000000000..aba052165c --- /dev/null +++ b/scene/3d/physical_bone_simulator_3d.cpp @@ -0,0 +1,396 @@ +/**************************************************************************/ +/* physical_bone_simulator_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "physical_bone_simulator_3d.h" + +void PhysicalBoneSimulator3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) { + if (p_old) { + if (p_old->is_connected(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed))) { + p_old->disconnect(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed)); + } + if (p_old->is_connected(SNAME("pose_updated"), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated))) { + p_old->disconnect(SNAME("pose_updated"), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated)); + } + } + if (p_new) { + if (!p_new->is_connected(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed))) { + p_new->connect(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed)); + } + if (!p_new->is_connected(SNAME("pose_updated"), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated))) { + p_new->connect(SNAME("pose_updated"), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated)); + } + } + _bone_list_changed(); +} + +void PhysicalBoneSimulator3D::_bone_list_changed() { + bones.clear(); + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + for (int i = 0; i < skeleton->get_bone_count(); i++) { + SimulatedBone sb; + sb.parent = skeleton->get_bone_parent(i); + sb.child_bones = skeleton->get_bone_children(i); + bones.push_back(sb); + } + _rebuild_physical_bones_cache(); + _pose_updated(); +} + +void PhysicalBoneSimulator3D::_pose_updated() { + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton || simulating) { + return; + } + ERR_FAIL_COND(skeleton->get_bone_count() != bones.size()); + for (int i = 0; i < skeleton->get_bone_count(); i++) { + bones.write[i].global_pose = skeleton->get_bone_global_pose(i); + } +} + +void PhysicalBoneSimulator3D::_set_active(bool p_active) { + if (!Engine::get_singleton()->is_editor_hint()) { + _reset_physical_bones_state(); + } +} + +void PhysicalBoneSimulator3D::_reset_physical_bones_state() { + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + bones[i].physical_bone->reset_physics_simulation_state(); + } + } +} + +bool PhysicalBoneSimulator3D::is_simulating_physics() const { + return simulating; +} + +int PhysicalBoneSimulator3D::find_bone(const String &p_name) const { + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return -1; + } + return skeleton->find_bone(p_name); +} + +String PhysicalBoneSimulator3D::get_bone_name(int p_bone) const { + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return String(); + } + return skeleton->get_bone_name(p_bone); +} + +int PhysicalBoneSimulator3D::get_bone_count() const { + return bones.size(); +} + +bool PhysicalBoneSimulator3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const { + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return false; + } + return skeleton->is_bone_parent_of(p_bone, p_parent_bone_id); +} + +void PhysicalBoneSimulator3D::bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + ERR_FAIL_COND(bones[p_bone].physical_bone); + ERR_FAIL_NULL(p_physical_bone); + bones.write[p_bone].physical_bone = p_physical_bone; + + _rebuild_physical_bones_cache(); +} + +void PhysicalBoneSimulator3D::unbind_physical_bone_from_bone(int p_bone) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + bones.write[p_bone].physical_bone = nullptr; + + _rebuild_physical_bones_cache(); +} + +PhysicalBone3D *PhysicalBoneSimulator3D::get_physical_bone(int p_bone) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); + + return bones[p_bone].physical_bone; +} + +PhysicalBone3D *PhysicalBoneSimulator3D::get_physical_bone_parent(int p_bone) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); + + if (bones[p_bone].cache_parent_physical_bone) { + return bones[p_bone].cache_parent_physical_bone; + } + + return _get_physical_bone_parent(p_bone); +} + +PhysicalBone3D *PhysicalBoneSimulator3D::_get_physical_bone_parent(int p_bone) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); + + const int parent_bone = bones[p_bone].parent; + if (parent_bone < 0) { + return nullptr; + } + + PhysicalBone3D *pb = bones[parent_bone].physical_bone; + if (pb) { + return pb; + } else { + return get_physical_bone_parent(parent_bone); + } +} + +void PhysicalBoneSimulator3D::_rebuild_physical_bones_cache() { + const int b_size = bones.size(); + for (int i = 0; i < b_size; ++i) { + PhysicalBone3D *parent_pb = _get_physical_bone_parent(i); + if (parent_pb != bones[i].cache_parent_physical_bone) { + bones.write[i].cache_parent_physical_bone = parent_pb; + if (bones[i].physical_bone) { + bones[i].physical_bone->_on_bone_parent_changed(); + } + } + } +} + +#ifndef DISABLE_DEPRECATED +void _pb_stop_simulation_compat(Node *p_node) { + PhysicalBoneSimulator3D *ps = Object::cast_to<PhysicalBoneSimulator3D>(p_node); + if (ps) { + return; // Prevent conflict. + } + for (int i = p_node->get_child_count() - 1; i >= 0; --i) { + _pb_stop_simulation_compat(p_node->get_child(i)); + } + PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); + if (pb) { + pb->set_simulate_physics(false); + } +} +#endif // _DISABLE_DEPRECATED + +void _pb_stop_simulation(Node *p_node) { + for (int i = p_node->get_child_count() - 1; i >= 0; --i) { + PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node->get_child(i)); + if (!pb) { + continue; + } + _pb_stop_simulation(pb); + } + PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); + if (pb) { + pb->set_simulate_physics(false); + } +} + +void PhysicalBoneSimulator3D::physical_bones_stop_simulation() { + simulating = false; + _reset_physical_bones_state(); +#ifndef DISABLE_DEPRECATED + if (is_compat) { + Skeleton3D *sk = get_skeleton(); + if (sk) { + _pb_stop_simulation_compat(sk); + } + } else { + _pb_stop_simulation(this); + } +#else + _pb_stop_simulation(this); +#endif // _DISABLE_DEPRECATED +} + +#ifndef DISABLE_DEPRECATED +void _pb_start_simulation_compat(const PhysicalBoneSimulator3D *p_simulator, Node *p_node, const Vector<int> &p_sim_bones) { + PhysicalBoneSimulator3D *ps = Object::cast_to<PhysicalBoneSimulator3D>(p_node); + if (ps) { + return; // Prevent conflict. + } + for (int i = p_node->get_child_count() - 1; i >= 0; --i) { + _pb_start_simulation_compat(p_simulator, p_node->get_child(i), p_sim_bones); + } + PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); + if (pb) { + if (p_sim_bones.is_empty()) { // If no bones are specified, activate ragdoll on full body. + pb->set_simulate_physics(true); + } else { + for (int i = p_sim_bones.size() - 1; i >= 0; --i) { + if (p_sim_bones[i] == pb->get_bone_id() || p_simulator->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) { + pb->set_simulate_physics(true); + break; + } + } + } + } +} +#endif // _DISABLE_DEPRECATED + +void _pb_start_simulation(const PhysicalBoneSimulator3D *p_simulator, Node *p_node, const Vector<int> &p_sim_bones) { + for (int i = p_node->get_child_count() - 1; i >= 0; --i) { + PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node->get_child(i)); + if (!pb) { + continue; + } + _pb_start_simulation(p_simulator, pb, p_sim_bones); + } + PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); + if (pb) { + if (p_sim_bones.is_empty()) { // If no bones are specified, activate ragdoll on full body. + pb->set_simulate_physics(true); + } else { + for (int i = p_sim_bones.size() - 1; i >= 0; --i) { + if (p_sim_bones[i] == pb->get_bone_id() || p_simulator->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) { + pb->set_simulate_physics(true); + break; + } + } + } + } +} + +void PhysicalBoneSimulator3D::physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones) { + simulating = true; + _reset_physical_bones_state(); + + _pose_updated(); + + Vector<int> sim_bones; + if (p_bones.size() > 0) { + sim_bones.resize(p_bones.size()); + int c = 0; + for (int i = sim_bones.size() - 1; i >= 0; --i) { + int bone_id = find_bone(p_bones[i]); + if (bone_id != -1) { + sim_bones.write[c++] = bone_id; + } + } + sim_bones.resize(c); + } + +#ifndef DISABLE_DEPRECATED + if (is_compat) { + Skeleton3D *sk = get_skeleton(); + if (sk) { + _pb_start_simulation_compat(this, sk, sim_bones); + } + } else { + _pb_start_simulation(this, this, sim_bones); + } +#else + _pb_start_simulation(this, this, sim_bones); +#endif // _DISABLE_DEPRECATED +} + +void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) { + for (int i = p_node->get_child_count() - 1; i >= 0; --i) { + _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception); + } + + CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_node); + if (co) { + if (p_add) { + PhysicsServer3D::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception); + } else { + PhysicsServer3D::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception); + } + } +} + +void PhysicalBoneSimulator3D::physical_bones_add_collision_exception(RID p_exception) { + _physical_bones_add_remove_collision_exception(true, this, p_exception); +} + +void PhysicalBoneSimulator3D::physical_bones_remove_collision_exception(RID p_exception) { + _physical_bones_add_remove_collision_exception(false, this, p_exception); +} + +Transform3D PhysicalBoneSimulator3D::get_bone_global_pose(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); + return bones[p_bone].global_pose; +} + +void PhysicalBoneSimulator3D::set_bone_global_pose(int p_bone, const Transform3D &p_pose) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + bones.write[p_bone].global_pose = p_pose; +} + +void PhysicalBoneSimulator3D::_process_modification() { + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + if (!enabled) { + for (int i = 0; i < bones.size(); i++) { + if (bones[i].physical_bone) { + if (bones[i].physical_bone->is_simulating_physics() == false) { + bones[i].physical_bone->reset_to_rest_position(); + } + } + } + } else { + ERR_FAIL_COND(skeleton->get_bone_count() != bones.size()); + LocalVector<Transform3D> local_poses; + for (int i = 0; i < skeleton->get_bone_count(); i++) { + Transform3D pt; + if (skeleton->get_bone_parent(i) >= 0) { + pt = get_bone_global_pose(skeleton->get_bone_parent(i)); + } + local_poses.push_back(pt.affine_inverse() * bones[i].global_pose); + } + for (int i = 0; i < skeleton->get_bone_count(); i++) { + skeleton->set_bone_pose_position(i, local_poses[i].origin); + skeleton->set_bone_pose_rotation(i, local_poses[i].basis.get_rotation_quaternion()); + skeleton->set_bone_pose_scale(i, local_poses[i].basis.get_scale()); + } + } +} + +void PhysicalBoneSimulator3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBoneSimulator3D::is_simulating_physics); + + ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &PhysicalBoneSimulator3D::physical_bones_stop_simulation); + ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &PhysicalBoneSimulator3D::physical_bones_start_simulation_on, DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &PhysicalBoneSimulator3D::physical_bones_add_collision_exception); + ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &PhysicalBoneSimulator3D::physical_bones_remove_collision_exception); +} + +PhysicalBoneSimulator3D::PhysicalBoneSimulator3D() { +} diff --git a/scene/3d/physical_bone_simulator_3d.h b/scene/3d/physical_bone_simulator_3d.h new file mode 100644 index 0000000000..ee900e0e77 --- /dev/null +++ b/scene/3d/physical_bone_simulator_3d.h @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* physical_bone_simulator_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef PHYSICAL_BONE_SIMULATOR_3D_H +#define PHYSICAL_BONE_SIMULATOR_3D_H + +#include "scene/3d/skeleton_modifier_3d.h" + +#include "scene/3d/physics/physical_bone_3d.h" + +class PhysicalBone3D; + +class PhysicalBoneSimulator3D : public SkeletonModifier3D { + GDCLASS(PhysicalBoneSimulator3D, SkeletonModifier3D); + + bool simulating = false; + bool enabled = true; + + struct SimulatedBone { + int parent; + Vector<int> child_bones; + + Transform3D global_pose; + + PhysicalBone3D *physical_bone = nullptr; + PhysicalBone3D *cache_parent_physical_bone = nullptr; + + SimulatedBone() { + parent = -1; + global_pose = Transform3D(); + physical_bone = nullptr; + cache_parent_physical_bone = nullptr; + } + }; + + Vector<SimulatedBone> bones; + + /// This is a slow API, so it's cached + PhysicalBone3D *_get_physical_bone_parent(int p_bone); + void _rebuild_physical_bones_cache(); + void _reset_physical_bones_state(); + +protected: + static void _bind_methods(); + + virtual void _set_active(bool p_active) override; + + void _bone_list_changed(); + void _pose_updated(); + + virtual void _process_modification() override; + + virtual void _skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) override; + +public: +#ifndef DISABLE_DEPRECATED + bool is_compat = false; +#endif // _DISABLE_DEPRECATED + bool is_simulating_physics() const; + + int find_bone(const String &p_name) const; + String get_bone_name(int p_bone) const; + int get_bone_count() const; + bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const; + + Transform3D get_bone_global_pose(int p_bone) const; + void set_bone_global_pose(int p_bone, const Transform3D &p_pose); + + void bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone); + void unbind_physical_bone_from_bone(int p_bone); + + PhysicalBone3D *get_physical_bone(int p_bone); + PhysicalBone3D *get_physical_bone_parent(int p_bone); + + void physical_bones_stop_simulation(); + void physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones); + void physical_bones_add_collision_exception(RID p_exception); + void physical_bones_remove_collision_exception(RID p_exception); + + PhysicalBoneSimulator3D(); +}; + +#endif // PHYSICAL_BONE_SIMULATOR_3D_H diff --git a/scene/3d/physics/physical_bone_3d.cpp b/scene/3d/physics/physical_bone_3d.cpp index 10c1fceb94..c6be2a9da8 100644 --- a/scene/3d/physics/physical_bone_3d.cpp +++ b/scene/3d/physics/physical_bone_3d.cpp @@ -29,6 +29,9 @@ /**************************************************************************/ #include "physical_bone_3d.h" +#ifndef DISABLE_DEPRECATED +#include "scene/3d/skeleton_3d.h" +#endif //_DISABLE_DEPRECATED bool PhysicalBone3D::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) { return false; @@ -89,15 +92,14 @@ void PhysicalBone3D::reset_physics_simulation_state() { } void PhysicalBone3D::reset_to_rest_position() { - if (parent_skeleton) { - Transform3D new_transform = parent_skeleton->get_global_transform(); + PhysicalBoneSimulator3D *simulator = get_simulator(); + Skeleton3D *skeleton = get_skeleton(); + if (simulator && skeleton) { if (bone_id == -1) { - new_transform *= body_offset; + set_global_transform((skeleton->get_global_transform() * body_offset).orthonormalized()); } else { - new_transform *= parent_skeleton->get_bone_global_pose(bone_id) * body_offset; + set_global_transform((skeleton->get_global_transform() * simulator->get_bone_global_pose(bone_id) * body_offset).orthonormalized()); } - new_transform.orthonormalize(); - set_global_transform(new_transform); } } @@ -734,15 +736,14 @@ bool PhysicalBone3D::_get(const StringName &p_name, Variant &r_ret) const { } void PhysicalBone3D::_get_property_list(List<PropertyInfo> *p_list) const { - Skeleton3D *parent = find_skeleton_parent(get_parent()); - - if (parent) { + Skeleton3D *skeleton = get_skeleton(); + if (skeleton) { String names; - for (int i = 0; i < parent->get_bone_count(); i++) { + for (int i = 0; i < skeleton->get_bone_count(); i++) { if (i > 0) { names += ","; } - names += parent->get_bone_name(i); + names += skeleton->get_bone_name(i); } p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("bone_name"), PROPERTY_HINT_ENUM, names)); @@ -758,7 +759,8 @@ void PhysicalBone3D::_get_property_list(List<PropertyInfo> *p_list) const { void PhysicalBone3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: - parent_skeleton = find_skeleton_parent(get_parent()); + case NOTIFICATION_PARENTED: + _update_simulator_path(); update_bone_id(); reset_to_rest_position(); reset_physics_simulation_state(); @@ -768,13 +770,13 @@ void PhysicalBone3D::_notification(int p_what) { break; case NOTIFICATION_EXIT_TREE: { - if (parent_skeleton) { + PhysicalBoneSimulator3D *simulator = get_simulator(); + if (simulator) { if (-1 != bone_id) { - parent_skeleton->unbind_physical_bone_from_bone(bone_id); + simulator->unbind_physical_bone_from_bone(bone_id); bone_id = -1; } } - parent_skeleton = nullptr; PhysicsServer3D::get_singleton()->joint_clear(joint); } break; @@ -818,10 +820,12 @@ void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { Transform3D global_transform(p_state->get_transform()); - // Update skeleton - if (parent_skeleton) { + // Update simulator + PhysicalBoneSimulator3D *simulator = get_simulator(); + Skeleton3D *skeleton = get_skeleton(); + if (simulator && skeleton) { if (-1 != bone_id) { - parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true); + simulator->set_bone_global_pose(bone_id, skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse)); } } } @@ -916,14 +920,6 @@ void PhysicalBone3D::_bind_methods() { BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF); } -Skeleton3D *PhysicalBone3D::find_skeleton_parent(Node *p_parent) { - if (!p_parent) { - return nullptr; - } - Skeleton3D *s = Object::cast_to<Skeleton3D>(p_parent); - return s ? s : find_skeleton_parent(p_parent->get_parent()); -} - void PhysicalBone3D::_update_joint_offset() { _fix_joint_offset(); @@ -938,18 +934,20 @@ void PhysicalBone3D::_update_joint_offset() { void PhysicalBone3D::_fix_joint_offset() { // Clamp joint origin to bone origin - if (parent_skeleton) { + PhysicalBoneSimulator3D *simulator = get_simulator(); + if (simulator) { joint_offset.origin = body_offset.affine_inverse().origin; } } void PhysicalBone3D::_reload_joint() { - if (!parent_skeleton) { + PhysicalBoneSimulator3D *simulator = get_simulator(); + if (!simulator || !simulator->get_skeleton()) { PhysicsServer3D::get_singleton()->joint_clear(joint); return; } - PhysicalBone3D *body_a = parent_skeleton->get_physical_bone_parent(bone_id); + PhysicalBone3D *body_a = simulator->get_physical_bone_parent(bone_id); if (!body_a) { PhysicsServer3D::get_singleton()->joint_clear(joint); return; @@ -1041,6 +1039,36 @@ void PhysicalBone3D::_on_bone_parent_changed() { _reload_joint(); } +void PhysicalBone3D::_update_simulator_path() { + simulator_id = ObjectID(); + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(get_parent()); + if (sim) { + simulator_id = sim->get_instance_id(); + return; + } +#ifndef DISABLE_DEPRECATED + Skeleton3D *sk = cast_to<Skeleton3D>(get_parent()); + if (sk) { + PhysicalBoneSimulator3D *ssim = cast_to<PhysicalBoneSimulator3D>(sk->get_simulator()); + if (ssim) { + simulator_id = ssim->get_instance_id(); + } + } +#endif // _DISABLE_DEPRECATED +} + +PhysicalBoneSimulator3D *PhysicalBone3D::get_simulator() const { + return Object::cast_to<PhysicalBoneSimulator3D>(ObjectDB::get_instance(simulator_id)); +} + +Skeleton3D *PhysicalBone3D::get_skeleton() const { + PhysicalBoneSimulator3D *simulator = get_simulator(); + if (simulator) { + return simulator->get_skeleton(); + } + return nullptr; +} + #ifdef TOOLS_ENABLED void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) { gizmo_move_joint = p_move_joint; @@ -1059,10 +1087,6 @@ const PhysicalBone3D::JointData *PhysicalBone3D::get_joint_data() const { return joint_data; } -Skeleton3D *PhysicalBone3D::find_skeleton_parent() { - return find_skeleton_parent(this); -} - void PhysicalBone3D::set_joint_type(JointType p_joint_type) { if (p_joint_type == get_joint_type()) { return; @@ -1269,21 +1293,22 @@ PhysicalBone3D::~PhysicalBone3D() { } void PhysicalBone3D::update_bone_id() { - if (!parent_skeleton) { + PhysicalBoneSimulator3D *simulator = get_simulator(); + if (!simulator) { return; } - const int new_bone_id = parent_skeleton->find_bone(bone_name); + const int new_bone_id = simulator->find_bone(bone_name); if (new_bone_id != bone_id) { if (-1 != bone_id) { // Assert the unbind from old node - parent_skeleton->unbind_physical_bone_from_bone(bone_id); + simulator->unbind_physical_bone_from_bone(bone_id); } bone_id = new_bone_id; - parent_skeleton->bind_physical_bone_to_bone(bone_id, this); + simulator->bind_physical_bone_to_bone(bone_id, this); _fix_joint_offset(); reset_physics_simulation_state(); @@ -1292,10 +1317,12 @@ void PhysicalBone3D::update_bone_id() { void PhysicalBone3D::update_offset() { #ifdef TOOLS_ENABLED - if (parent_skeleton) { - Transform3D bone_transform(parent_skeleton->get_global_transform()); + PhysicalBoneSimulator3D *simulator = get_simulator(); + Skeleton3D *skeleton = get_skeleton(); + if (simulator && skeleton) { + Transform3D bone_transform(skeleton->get_global_transform()); if (-1 != bone_id) { - bone_transform *= parent_skeleton->get_bone_global_pose(bone_id); + bone_transform *= simulator->get_bone_global_pose(bone_id); } if (gizmo_move_joint) { @@ -1309,7 +1336,7 @@ void PhysicalBone3D::update_offset() { } void PhysicalBone3D::_start_physics_simulation() { - if (_internal_simulate_physics || !parent_skeleton) { + if (_internal_simulate_physics || !simulator_id.is_valid()) { return; } reset_to_rest_position(); @@ -1323,23 +1350,22 @@ void PhysicalBone3D::_start_physics_simulation() { } void PhysicalBone3D::_stop_physics_simulation() { - if (!parent_skeleton) { - return; - } - if (parent_skeleton->get_animate_physical_bones()) { - set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); - PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); - PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); - PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); - } else { - set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); - PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0); - PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); - PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0); + PhysicalBoneSimulator3D *simulator = get_simulator(); + if (simulator) { + if (simulator->is_simulating_physics()) { + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); + PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); + } else { + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); + PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0); + } } if (_internal_simulate_physics) { PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable()); - parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false); set_as_top_level(false); _internal_simulate_physics = false; } diff --git a/scene/3d/physics/physical_bone_3d.h b/scene/3d/physics/physical_bone_3d.h index 953400da2f..4765e41572 100644 --- a/scene/3d/physics/physical_bone_3d.h +++ b/scene/3d/physics/physical_bone_3d.h @@ -31,8 +31,10 @@ #ifndef PHYSICAL_BONE_3D_H #define PHYSICAL_BONE_3D_H +#include "scene/3d/physical_bone_simulator_3d.h" #include "scene/3d/physics/physics_body_3d.h" -#include "scene/3d/skeleton_3d.h" + +class PhysicalBoneSimulator3D; class PhysicalBone3D : public PhysicsBody3D { GDCLASS(PhysicalBone3D, PhysicsBody3D); @@ -169,7 +171,7 @@ private: Transform3D joint_offset; RID joint; - Skeleton3D *parent_skeleton = nullptr; + ObjectID simulator_id; Transform3D body_offset; Transform3D body_offset_inverse; bool simulate_physics = false; @@ -206,15 +208,19 @@ protected: private: void _sync_body_state(PhysicsDirectBodyState3D *p_state); - static Skeleton3D *find_skeleton_parent(Node *p_parent); void _update_joint_offset(); void _fix_joint_offset(); void _reload_joint(); + void _update_simulator_path(); + public: void _on_bone_parent_changed(); + PhysicalBoneSimulator3D *get_simulator() const; + Skeleton3D *get_skeleton() const; + void set_linear_velocity(const Vector3 &p_velocity); Vector3 get_linear_velocity() const override; @@ -231,7 +237,6 @@ public: #endif const JointData *get_joint_data() const; - Skeleton3D *find_skeleton_parent(); int get_bone_id() const { return bone_id; diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index f0ffb7b2d5..566801c9f7 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -32,10 +32,11 @@ #include "skeleton_3d.compat.inc" #include "core/variant/type_info.h" -#include "scene/3d/physics/physical_bone_3d.h" -#include "scene/3d/physics/physics_body_3d.h" #include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" +#ifndef DISABLE_DEPRECATED +#include "scene/3d/physical_bone_simulator_3d.h" +#endif // _DISABLE_DEPRECATED void SkinReference::_skin_changed() { if (skeleton_node) { @@ -70,6 +71,12 @@ SkinReference::~SkinReference() { bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { String path = p_path; +#ifndef DISABLE_DEPRECATED + if (path.begins_with("animate_physical_bones")) { + set_animate_physical_bones(p_value); + } +#endif + if (!path.begins_with("bones/")) { return false; } @@ -134,6 +141,12 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const { String path = p_path; +#ifndef DISABLE_DEPRECATED + if (path.begins_with("animate_physical_bones")) { + r_ret = get_animate_physical_bones(); + } +#endif + if (!path.begins_with("bones/")) { return false; } @@ -251,26 +264,70 @@ void Skeleton3D::_update_process_order() { } process_order_dirty = false; + + emit_signal("bone_list_changed"); } +#ifndef DISABLE_DEPRECATED +void Skeleton3D::setup_simulator() { + PhysicalBoneSimulator3D *sim = memnew(PhysicalBoneSimulator3D); + simulator = sim; + sim->is_compat = true; + sim->set_active(false); // Don't run unneeded process. + add_child(sim); +} + +void Skeleton3D::remove_simulator() { + remove_child(simulator); + memdelete(simulator); +} +#endif // _DISABLE_DEPRECATED + void Skeleton3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - if (dirty) { - notification(NOTIFICATION_UPDATE_SKELETON); - } + _process_changed(); + _make_modifiers_dirty(); + force_update_all_dirty_bones(); +#ifndef DISABLE_DEPRECATED + setup_simulator(); +#endif // _DISABLE_DEPRECATED + } break; +#ifndef DISABLE_DEPRECATED + case NOTIFICATION_EXIT_TREE: { + remove_simulator(); } break; +#endif // _DISABLE_DEPRECATED case NOTIFICATION_UPDATE_SKELETON: { - RenderingServer *rs = RenderingServer::get_singleton(); - Bone *bonesptr = bones.ptrw(); + // Update bone transforms to apply unprocessed poses. + force_update_all_dirty_bones(); + + updating = true; + Bone *bonesptr = bones.ptrw(); int len = bones.size(); - dirty = false; - // Update bone transforms. - force_update_all_bone_transforms(); + // Process modifiers. + _find_modifiers(); + LocalVector<Transform3D> current_bone_poses; + LocalVector<Vector3> current_pose_positions; + LocalVector<Quaternion> current_pose_rotations; + LocalVector<Vector3> current_pose_scales; + LocalVector<Transform3D> current_bone_global_poses; + if (!modifiers.is_empty()) { + // Store unmodified bone poses. + for (int i = 0; i < len; i++) { + current_bone_poses.push_back(bones[i].pose_cache); + current_pose_positions.push_back(bones[i].pose_position); + current_pose_rotations.push_back(bones[i].pose_rotation); + current_pose_scales.push_back(bones[i].pose_scale); + current_bone_global_poses.push_back(bones[i].global_pose); + } + _process_modifiers(); + } // Update skins. + RenderingServer *rs = RenderingServer::get_singleton(); for (SkinReference *E : skin_bindings) { const Skin *skin = E->skin.operator->(); RID skeleton = E->skeleton; @@ -322,74 +379,78 @@ void Skeleton3D::_notification(int p_what) { for (uint32_t i = 0; i < bind_count; i++) { uint32_t bone_index = E->skin_bone_indices_ptrs[i]; ERR_CONTINUE(bone_index >= (uint32_t)len); - rs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i)); + rs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].global_pose * skin->get_bind_pose(i)); } } - emit_signal(SceneStringNames::get_singleton()->pose_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(); - } - } + if (!modifiers.is_empty()) { + // Restore unmodified bone poses. + for (int i = 0; i < len; i++) { + bonesptr[i].pose_cache = current_bone_poses[i]; + bonesptr[i].pose_position = current_pose_positions[i]; + bonesptr[i].pose_rotation = current_pose_rotations[i]; + bonesptr[i].pose_scale = current_pose_scales[i]; + bonesptr[i].global_pose = current_bone_global_poses[i]; } } + + updating = false; + is_update_needed = false; } break; - case NOTIFICATION_READY: { - if (Engine::get_singleton()->is_editor_hint()) { - set_physics_process_internal(true); + case NOTIFICATION_INTERNAL_PROCESS: + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + _find_modifiers(); + if (!modifiers.is_empty()) { + _update_deferred(); } } break; -#endif // _3D_DISABLED } } -void Skeleton3D::clear_bones_global_pose_override() { - for (int i = 0; i < bones.size(); i += 1) { - bones.write[i].global_pose_override_amount = 0; - bones.write[i].global_pose_override_reset = true; +void Skeleton3D::set_modifier_callback_mode_process(Skeleton3D::ModifierCallbackModeProcess p_mode) { + if (modifier_callback_mode_process == p_mode) { + return; } - _make_dirty(); + modifier_callback_mode_process = p_mode; + _process_changed(); } -void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].global_pose_override_amount = p_amount; - bones.write[p_bone].global_pose_override = p_pose; - bones.write[p_bone].global_pose_override_reset = !p_persistent; - _make_dirty(); +Skeleton3D::ModifierCallbackModeProcess Skeleton3D::get_modifier_callback_mode_process() const { + return modifier_callback_mode_process; } -Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - return bones[p_bone].global_pose_override; +void Skeleton3D::_process_changed() { + if (modifier_callback_mode_process == MODIFIER_CALLBACK_MODE_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } else if (modifier_callback_mode_process == MODIFIER_CALLBACK_MODE_PROCESS_PHYSICS) { + set_process_internal(false); + set_physics_process_internal(true); + } +} + +void Skeleton3D::_make_modifiers_dirty() { + modifiers_dirty = true; + _update_deferred(); } Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - if (dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); - } - return bones[p_bone].pose_global; + const_cast<Skeleton3D *>(this)->force_update_all_dirty_bones(); + return bones[p_bone].global_pose; } -Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const { +void Skeleton3D::set_bone_global_pose(int p_bone, const Transform3D &p_pose) { const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - if (dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + ERR_FAIL_INDEX(p_bone, bone_size); + + Transform3D pt; + if (bones[p_bone].parent >= 0) { + pt = get_bone_global_pose(bones[p_bone].parent); } - return bones[p_bone].pose_global_no_override; + Transform3D t = pt.affine_inverse() * p_pose; + set_bone_pose(p_bone, t); } void Skeleton3D::set_motion_scale(float p_motion_scale) { @@ -548,7 +609,7 @@ Transform3D Skeleton3D::get_bone_global_rest(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); if (rest_dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + const_cast<Skeleton3D *>(this)->force_update_all_bone_transforms(); } return bones[p_bone].global_rest; } @@ -588,6 +649,19 @@ void Skeleton3D::clear_bones() { // Posing api +void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + + bones.write[p_bone].pose_position = p_pose.origin; + bones.write[p_bone].pose_rotation = p_pose.basis.get_rotation_quaternion(); + bones.write[p_bone].pose_scale = p_pose.basis.get_scale(); + bones.write[p_bone].pose_cache_dirty = true; + if (is_inside_tree()) { + _make_dirty(); + } +} + void Skeleton3D::set_bone_pose_position(int p_bone, const Vector3 &p_position) { const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone, bone_size); @@ -654,7 +728,7 @@ void Skeleton3D::reset_bone_poses() { Transform3D Skeleton3D::get_bone_pose(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - ((Skeleton3D *)this)->bones.write[p_bone].update_pose_cache(); + const_cast<Skeleton3D *>(this)->bones.write[p_bone].update_pose_cache(); return bones[p_bone].pose_cache; } @@ -662,11 +736,15 @@ void Skeleton3D::_make_dirty() { if (dirty) { return; } + dirty = true; + _update_deferred(); +} - if (is_inside_tree()) { - notify_deferred_thread_group(NOTIFICATION_UPDATE_SKELETON); +void Skeleton3D::_update_deferred() { + if (!is_update_needed && !updating && is_inside_tree()) { + is_update_needed = true; + notify_deferred_thread_group(NOTIFICATION_UPDATE_SKELETON); // It must never be called more than once in a single frame. } - dirty = true; } void Skeleton3D::localize_rests() { @@ -687,173 +765,6 @@ void Skeleton3D::localize_rests() { } } -void Skeleton3D::set_animate_physical_bones(bool p_enabled) { - animate_physical_bones = p_enabled; - - 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_enabled); - } -} - -bool Skeleton3D::get_animate_physical_bones() const { - return animate_physical_bones; -} - -void Skeleton3D::bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - ERR_FAIL_COND(bones[p_bone].physical_bone); - ERR_FAIL_NULL(p_physical_bone); - bones.write[p_bone].physical_bone = p_physical_bone; - - _rebuild_physical_bones_cache(); -} - -void Skeleton3D::unbind_physical_bone_from_bone(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].physical_bone = nullptr; - - _rebuild_physical_bones_cache(); -} - -PhysicalBone3D *Skeleton3D::get_physical_bone(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); - - return bones[p_bone].physical_bone; -} - -PhysicalBone3D *Skeleton3D::get_physical_bone_parent(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); - - if (bones[p_bone].cache_parent_physical_bone) { - return bones[p_bone].cache_parent_physical_bone; - } - - return _get_physical_bone_parent(p_bone); -} - -PhysicalBone3D *Skeleton3D::_get_physical_bone_parent(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); - - const int parent_bone = bones[p_bone].parent; - if (0 > parent_bone) { - return nullptr; - } - - PhysicalBone3D *pb = bones[parent_bone].physical_bone; - if (pb) { - return pb; - } else { - return get_physical_bone_parent(parent_bone); - } -} - -void Skeleton3D::_rebuild_physical_bones_cache() { - const int b_size = bones.size(); - for (int i = 0; i < b_size; ++i) { - PhysicalBone3D *parent_pb = _get_physical_bone_parent(i); - if (parent_pb != bones[i].cache_parent_physical_bone) { - bones.write[i].cache_parent_physical_bone = parent_pb; - if (bones[i].physical_bone) { - bones[i].physical_bone->_on_bone_parent_changed(); - } - } - } -} - -void _pb_stop_simulation(Node *p_node) { - for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { - _pb_stop_simulation(p_node->get_child(i)); - } - - PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); - if (pb) { - pb->set_simulate_physics(false); - } -} - -void Skeleton3D::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 Skeleton3D *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) { - for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { - _pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones); - } - - PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); - if (pb) { - if (p_sim_bones.is_empty()) { // If no bones is specified, activate ragdoll on full body. - pb->set_simulate_physics(true); - } else { - 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])) { - pb->set_simulate_physics(true); - break; - } - } - } - } -} - -void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones) { - set_physics_process_internal(false); - - Vector<int> sim_bones; - if (p_bones.size() > 0) { - sim_bones.resize(p_bones.size()); - int c = 0; - for (int i = sim_bones.size() - 1; 0 <= i; --i) { - int bone_id = find_bone(p_bones[i]); - if (bone_id != -1) { - sim_bones.write[c++] = bone_id; - } - } - sim_bones.resize(c); - } - - _pb_start_simulation(this, this, sim_bones); -} - -void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) { - for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { - _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception); - } - - CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_node); - if (co) { - if (p_add) { - PhysicsServer3D::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception); - } else { - PhysicsServer3D::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception); - } - } -} - -void Skeleton3D::physical_bones_add_collision_exception(RID p_exception) { - _physical_bones_add_remove_collision_exception(true, this, p_exception); -} - -void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) { - _physical_bones_add_remove_collision_exception(false, this, p_exception); -} - void Skeleton3D::_skin_changed() { _make_dirty(); } @@ -927,18 +838,23 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { } void Skeleton3D::force_update_all_dirty_bones() { - if (dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + if (!dirty) { + return; } + force_update_all_bone_transforms(); } void Skeleton3D::force_update_all_bone_transforms() { _update_process_order(); - for (int i = 0; i < parentless_bones.size(); i++) { force_update_bone_children_transforms(parentless_bones[i]); } rest_dirty = false; + dirty = false; + if (updating) { + return; + } + emit_signal(SceneStringNames::get_singleton()->pose_updated); } void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { @@ -961,32 +877,43 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { Transform3D pose = b.pose_cache; if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global * pose; - b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * pose; + b.global_pose = bonesptr[b.parent].global_pose * pose; } else { - b.pose_global = pose; - b.pose_global_no_override = pose; + b.global_pose = pose; } } else { if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global * b.rest; - b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * b.rest; + b.global_pose = bonesptr[b.parent].global_pose * b.rest; } else { - b.pose_global = b.rest; - b.pose_global_no_override = b.rest; + b.global_pose = b.rest; } } if (rest_dirty) { b.global_rest = b.parent >= 0 ? bonesptr[b.parent].global_rest * b.rest : b.rest; } +#ifndef DISABLE_DEPRECATED + if (bone_enabled) { + Transform3D pose = b.pose_cache; + if (b.parent >= 0) { + b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * pose; + } else { + b.pose_global_no_override = pose; + } + } else { + if (b.parent >= 0) { + b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * b.rest; + } else { + b.pose_global_no_override = b.rest; + } + } if (b.global_pose_override_amount >= CMP_EPSILON) { - b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount); + b.global_pose = b.global_pose.interpolate_with(b.global_pose_override, b.global_pose_override_amount); } - if (b.global_pose_override_reset) { b.global_pose_override_amount = 0.0; } +#endif // _DISABLE_DEPRECATED // Add the bone's children to the list of bones to be processed. int child_bone_size = b.child_bones.size(); @@ -998,6 +925,72 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { } } +void Skeleton3D::_find_modifiers() { + if (!modifiers_dirty) { + return; + } + modifiers.clear(); + for (int i = 0; i < get_child_count(); i++) { + SkeletonModifier3D *c = Object::cast_to<SkeletonModifier3D>(get_child(i)); + if (c) { + modifiers.push_back(c->get_instance_id()); + } + } + modifiers_dirty = false; +} + +void Skeleton3D::_process_modifiers() { + for (const ObjectID &oid : modifiers) { + Object *t_obj = ObjectDB::get_instance(oid); + if (!t_obj) { + continue; + } + SkeletonModifier3D *mod = cast_to<SkeletonModifier3D>(t_obj); + if (!mod) { + continue; + } + real_t influence = mod->get_influence(); + if (influence < 1.0) { + LocalVector<Transform3D> old_poses; + for (int i = 0; i < get_bone_count(); i++) { + old_poses.push_back(get_bone_pose(i)); + } + mod->process_modification(); + LocalVector<Transform3D> new_poses; + for (int i = 0; i < get_bone_count(); i++) { + new_poses.push_back(get_bone_pose(i)); + } + for (int i = 0; i < get_bone_count(); i++) { + if (old_poses[i] == new_poses[i]) { + continue; // Avoid unneeded calculation. + } + set_bone_pose(i, old_poses[i].interpolate_with(new_poses[i], influence)); + } + } else { + mod->process_modification(); + } + force_update_all_dirty_bones(); + } +} + +void Skeleton3D::add_child_notify(Node *p_child) { + if (Object::cast_to<SkeletonModifier3D>(p_child)) { + _make_modifiers_dirty(); + } +} + +void Skeleton3D::move_child_notify(Node *p_child) { + if (Object::cast_to<SkeletonModifier3D>(p_child)) { + _make_modifiers_dirty(); + } +} + +void Skeleton3D::remove_child_notify(Node *p_child) { + if (Object::cast_to<SkeletonModifier3D>(p_child)) { + _make_modifiers_dirty(); + } +} + void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone); ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone); @@ -1028,6 +1021,7 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones); ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose); + ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_pose); ClassDB::bind_method(D_METHOD("set_bone_pose_position", "bone_idx", "position"), &Skeleton3D::set_bone_pose_position); ClassDB::bind_method(D_METHOD("set_bone_pose_rotation", "bone_idx", "rotation"), &Skeleton3D::set_bone_pose_rotation); ClassDB::bind_method(D_METHOD("set_bone_pose_scale", "bone_idx", "scale"), &Skeleton3D::set_bone_pose_scale); @@ -1042,11 +1036,8 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled); ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override); - ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_bone_global_pose_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_override); ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton3D::get_bone_global_pose); - ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override); + ClassDB::bind_method(D_METHOD("set_bone_global_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_global_pose); ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms); ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms); @@ -1057,27 +1048,125 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_show_rest_only", "enabled"), &Skeleton3D::set_show_rest_only); ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton3D::is_show_rest_only); - ClassDB::bind_method(D_METHOD("set_animate_physical_bones", "enabled"), &Skeleton3D::set_animate_physical_bones); - ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones); - - ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton3D::physical_bones_stop_simulation); - ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton3D::physical_bones_start_simulation_on, DEFVAL(Array())); - ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception); - ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception); + ClassDB::bind_method(D_METHOD("set_modifier_callback_mode_process", "mode"), &Skeleton3D::set_modifier_callback_mode_process); + ClassDB::bind_method(D_METHOD("get_modifier_callback_mode_process"), &Skeleton3D::get_modifier_callback_mode_process); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motion_scale", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater"), "set_motion_scale", "get_motion_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only"); -#ifndef _3D_DISABLED - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones"); -#endif // _3D_DISABLED + + ADD_GROUP("Modifier", "modifier_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "modifier_callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_modifier_callback_mode_process", "get_modifier_callback_mode_process"); ADD_SIGNAL(MethodInfo("pose_updated")); ADD_SIGNAL(MethodInfo("bone_pose_changed", PropertyInfo(Variant::INT, "bone_idx"))); ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx"))); + ADD_SIGNAL(MethodInfo("bone_list_changed")); ADD_SIGNAL(MethodInfo("show_rest_only_changed")); BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); + BIND_ENUM_CONSTANT(MODIFIER_CALLBACK_MODE_PROCESS_PHYSICS); + BIND_ENUM_CONSTANT(MODIFIER_CALLBACK_MODE_PROCESS_IDLE); + +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override); + ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_bone_global_pose_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_override); + ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override); + + ClassDB::bind_method(D_METHOD("set_animate_physical_bones", "enabled"), &Skeleton3D::set_animate_physical_bones); + ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones); + ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton3D::physical_bones_stop_simulation); + ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton3D::physical_bones_start_simulation_on, DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception); + ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception); +#endif // _DISABLE_DEPRECATED +} + +#ifndef DISABLE_DEPRECATED +void Skeleton3D::clear_bones_global_pose_override() { + for (int i = 0; i < bones.size(); i += 1) { + bones.write[i].global_pose_override_amount = 0; + bones.write[i].global_pose_override_reset = true; + } + _make_dirty(); +} + +void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + bones.write[p_bone].global_pose_override_amount = p_amount; + bones.write[p_bone].global_pose_override = p_pose; + bones.write[p_bone].global_pose_override_reset = !p_persistent; + _make_dirty(); +} + +Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); + return bones[p_bone].global_pose_override; +} + +Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); + const_cast<Skeleton3D *>(this)->force_update_all_dirty_bones(); + return bones[p_bone].pose_global_no_override; +} + +Node *Skeleton3D::get_simulator() { + return simulator; +} + +void Skeleton3D::set_animate_physical_bones(bool p_enabled) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->set_active(p_enabled); +} + +bool Skeleton3D::get_animate_physical_bones() const { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return false; + } + return sim->is_active(); +} + +void Skeleton3D::physical_bones_stop_simulation() { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->physical_bones_stop_simulation(); + sim->set_active(false); +} + +void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->set_active(true); + sim->physical_bones_start_simulation_on(p_bones); +} + +void Skeleton3D::physical_bones_add_collision_exception(RID p_exception) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->physical_bones_add_collision_exception(p_exception); +} + +void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->physical_bones_remove_collision_exception(p_exception); } +#endif // _DISABLE_DEPRECATED Skeleton3D::Skeleton3D() { } diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 979e2e52b7..5b6f60dbd4 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -36,8 +36,8 @@ typedef int BoneId; -class PhysicalBone3D; class Skeleton3D; +class SkeletonModifier3D; class SkinReference : public RefCounted { GDCLASS(SkinReference, RefCounted) @@ -66,61 +66,71 @@ public: class Skeleton3D : public Node3D { GDCLASS(Skeleton3D, Node3D); +#ifndef DISABLE_DEPRECATED + Node *simulator = nullptr; + void setup_simulator(); + void remove_simulator(); +#endif // _DISABLE_DEPRECATED + +public: + enum ModifierCallbackModeProcess { + MODIFIER_CALLBACK_MODE_PROCESS_PHYSICS, + MODIFIER_CALLBACK_MODE_PROCESS_IDLE, + }; + private: friend class SkinReference; + void _update_deferred(); + bool is_update_needed = false; // Is updating reserved? + bool updating = false; // Is updating now? + struct Bone { String name; - bool enabled; int parent; + Vector<int> child_bones; Transform3D rest; Transform3D global_rest; - _FORCE_INLINE_ void update_pose_cache() { + bool enabled; + Transform3D pose_cache; + bool pose_cache_dirty = true; + Vector3 pose_position; + Quaternion pose_rotation; + Vector3 pose_scale = Vector3(1, 1, 1); + Transform3D global_pose; + + void update_pose_cache() { if (pose_cache_dirty) { pose_cache.basis.set_quaternion_scale(pose_rotation, pose_scale); pose_cache.origin = pose_position; pose_cache_dirty = false; } } - bool pose_cache_dirty = true; - Transform3D pose_cache; - Vector3 pose_position; - Quaternion pose_rotation; - Vector3 pose_scale = Vector3(1, 1, 1); - Transform3D pose_global; +#ifndef DISABLE_DEPRECATED Transform3D pose_global_no_override; - real_t global_pose_override_amount = 0.0; bool global_pose_override_reset = false; Transform3D global_pose_override; - - PhysicalBone3D *physical_bone = nullptr; - PhysicalBone3D *cache_parent_physical_bone = nullptr; - - Vector<int> child_bones; +#endif // _DISABLE_DEPRECATED Bone() { parent = -1; + child_bones = Vector<int>(); enabled = true; +#ifndef DISABLE_DEPRECATED global_pose_override_amount = 0; global_pose_override_reset = false; -#ifndef _3D_DISABLED - physical_bone = nullptr; - cache_parent_physical_bone = nullptr; -#endif // _3D_DISABLED - child_bones = Vector<int>(); +#endif // _DISABLE_DEPRECATED } }; HashSet<SkinReference *> skin_bindings; - void _skin_changed(); - bool animate_physical_bones = true; Vector<Bone> bones; bool process_order_dirty = false; @@ -138,6 +148,15 @@ private: void _update_process_order(); + // To process modifiers. + ModifierCallbackModeProcess modifier_callback_mode_process = MODIFIER_CALLBACK_MODE_PROCESS_IDLE; + LocalVector<ObjectID> modifiers; + bool modifiers_dirty = false; + void _find_modifiers(); + void _process_modifiers(); + void _process_changed(); + void _make_modifiers_dirty(); + #ifndef DISABLE_DEPRECATED void _add_bone_bind_compat_88791(const String &p_name); @@ -152,12 +171,16 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void add_child_notify(Node *p_child) override; + virtual void move_child_notify(Node *p_child) override; + virtual void remove_child_notify(Node *p_child) override; + public: enum { NOTIFICATION_UPDATE_SKELETON = 50 }; - // skeleton creation api + // Skeleton creation API uint64_t get_version() const; int add_bone(const String &p_name); int find_bone(const String &p_name) const; @@ -179,8 +202,6 @@ public: void set_bone_rest(int p_bone, const Transform3D &p_rest); Transform3D get_bone_rest(int p_bone) const; Transform3D get_bone_global_rest(int p_bone) const; - Transform3D get_bone_global_pose(int p_bone) const; - Transform3D get_bone_global_pose_no_override(int p_bone) const; void set_bone_enabled(int p_bone, bool p_enabled); bool is_bone_enabled(int p_bone) const; @@ -192,26 +213,23 @@ public: void set_motion_scale(float p_motion_scale); float get_motion_scale() const; - // posing api - - void set_bone_pose_position(int p_bone, const Vector3 &p_position); - void set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation); - void set_bone_pose_scale(int p_bone, const Vector3 &p_scale); - + // Posing API Transform3D get_bone_pose(int p_bone) const; - Vector3 get_bone_pose_position(int p_bone) const; Quaternion get_bone_pose_rotation(int p_bone) const; Vector3 get_bone_pose_scale(int p_bone) const; + void set_bone_pose(int p_bone, const Transform3D &p_pose); + void set_bone_pose_position(int p_bone, const Vector3 &p_position); + void set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation); + void set_bone_pose_scale(int p_bone, const Vector3 &p_scale); + + Transform3D get_bone_global_pose(int p_bone) const; + void set_bone_global_pose(int p_bone, const Transform3D &p_pose); void reset_bone_pose(int p_bone); void reset_bone_poses(); - void clear_bones_global_pose_override(); - Transform3D get_bone_global_pose_override(int p_bone) const; - void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false); - - void localize_rests(); // used for loaders and tools + void localize_rests(); // Used for loaders and tools. Ref<Skin> create_skin_from_rest_transforms(); @@ -221,31 +239,29 @@ public: void force_update_all_bone_transforms(); void force_update_bone_children_transforms(int bone_idx); - // Physical bone API + void set_modifier_callback_mode_process(ModifierCallbackModeProcess p_mode); + ModifierCallbackModeProcess get_modifier_callback_mode_process() const; + +#ifndef DISABLE_DEPRECATED + Transform3D get_bone_global_pose_no_override(int p_bone) const; + void clear_bones_global_pose_override(); + Transform3D get_bone_global_pose_override(int p_bone) const; + void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false); + Node *get_simulator(); void set_animate_physical_bones(bool p_enabled); bool get_animate_physical_bones() const; - - void bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone); - void unbind_physical_bone_from_bone(int p_bone); - - PhysicalBone3D *get_physical_bone(int p_bone); - PhysicalBone3D *get_physical_bone_parent(int p_bone); - -private: - /// This is a slow API, so it's cached - PhysicalBone3D *_get_physical_bone_parent(int p_bone); - void _rebuild_physical_bones_cache(); - -public: void physical_bones_stop_simulation(); void physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones); void physical_bones_add_collision_exception(RID p_exception); void physical_bones_remove_collision_exception(RID p_exception); +#endif // _DISABLE_DEPRECATED public: Skeleton3D(); ~Skeleton3D(); }; +VARIANT_ENUM_CAST(Skeleton3D::ModifierCallbackModeProcess); + #endif // SKELETON_3D_H diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index 286268b4a2..9581ae58d8 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -30,8 +30,6 @@ #include "skeleton_ik_3d.h" -#ifndef _3D_DISABLED - FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) { for (int i = children.size() - 1; 0 <= i; --i) { if (p_bone_id == children[i].bone) { @@ -236,46 +234,21 @@ void FabrikInverseKinematic::set_goal(Task *p_task, const Transform3D &p_goal) { p_task->goal_global_transform = p_goal; } -void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &p_inverse_transf, real_t blending_delta) { - if (blending_delta >= 0.99f) { - // Update the end_effector (local transform) without blending - p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform; - } else { - // End effector in local transform - const Transform3D end_effector_pose(p_task->skeleton->get_bone_global_pose_no_override(p_task->end_effectors[0].tip_bone)); - - // Update the end_effector (local transform) by blending with current pose - p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta); - } +void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &p_inverse_transf) { + // Update the end_effector (local transform) by blending with current pose + p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform; } -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) { - // Before skipping, make sure we undo the global pose overrides - ChainItem *ci(&p_task->chain.chain_root); - while (ci) { - p_task->skeleton->set_bone_global_pose_override(ci->bone, ci->initial_transform, 0.0, false); - - if (!ci->children.is_empty()) { - ci = &ci->children.write[0]; - } else { - ci = nullptr; - } - } - - return; // Skip solving - } - +void FabrikInverseKinematic::solve(Task *p_task, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position) { // Update the initial root transform so its synced with any animation changes _update_chain(p_task->skeleton, &p_task->chain.chain_root); - p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform3D(), 0.0, false); Vector3 origin_pos = p_task->skeleton->get_bone_global_pose(p_task->chain.chain_root.bone).origin; - make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta); + make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse()); if (p_use_magnet && p_task->chain.middle_chain_item) { - p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.lerp(p_magnet_position, blending_delta); + p_task->chain.magnet_position = p_magnet_position; solve_simple(p_task, true, origin_pos); } solve_simple(p_task, false, origin_pos); @@ -303,8 +276,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove // IK should not affect scale, so undo any scaling new_bone_pose.basis.orthonormalize(); new_bone_pose.basis.scale(p_task->skeleton->get_bone_global_pose(ci->bone).basis.get_scale()); - - p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0, true); + p_task->skeleton->set_bone_global_pose(ci->bone, Transform3D(new_bone_pose.basis, p_task->skeleton->get_bone_global_pose(ci->bone).origin)); if (!ci->children.is_empty()) { ci = &ci->children.write[0]; @@ -319,7 +291,7 @@ void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_ return; } - p_chain_item->initial_transform = p_sk->get_bone_global_pose_no_override(p_chain_item->bone); + p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone); p_chain_item->current_pos = p_chain_item->initial_transform.origin; ChainItem *items = p_chain_item->children.ptrw(); @@ -329,8 +301,10 @@ void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_ } void SkeletonIK3D::_validate_property(PropertyInfo &p_property) const { + SkeletonModifier3D::_validate_property(p_property); + if (p_property.name == "root_bone" || p_property.name == "tip_bone") { - Skeleton3D *skeleton = get_parent_skeleton(); + Skeleton3D *skeleton = get_skeleton(); if (skeleton) { String names("--,"); for (int i = 0; i < skeleton->get_bone_count(); i++) { @@ -356,9 +330,6 @@ void SkeletonIK3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tip_bone", "tip_bone"), &SkeletonIK3D::set_tip_bone); ClassDB::bind_method(D_METHOD("get_tip_bone"), &SkeletonIK3D::get_tip_bone); - ClassDB::bind_method(D_METHOD("set_interpolation", "interpolation"), &SkeletonIK3D::set_interpolation); - ClassDB::bind_method(D_METHOD("get_interpolation"), &SkeletonIK3D::get_interpolation); - ClassDB::bind_method(D_METHOD("set_target_transform", "target"), &SkeletonIK3D::set_target_transform); ClassDB::bind_method(D_METHOD("get_target_transform"), &SkeletonIK3D::get_target_transform); @@ -388,7 +359,6 @@ void SkeletonIK3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone"), "set_root_bone", "get_root_bone"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "tip_bone"), "set_tip_bone", "get_tip_bone"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "target", PROPERTY_HINT_NONE, "suffix:m"), "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"); @@ -398,21 +368,21 @@ void SkeletonIK3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "max_iterations"), "set_max_iterations", "get_max_iterations"); } +void SkeletonIK3D::_process_modification() { + if (!internal_active) { + return; + } + if (target_node_override_ref) { + reload_goal(); + } + _solve_chain(); +} + void SkeletonIK3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - skeleton_ref = Object::cast_to<Skeleton3D>(get_parent()); - set_process_priority(1); reload_chain(); } break; - - case NOTIFICATION_INTERNAL_PROCESS: { - if (target_node_override_ref) { - reload_goal(); - } - _solve_chain(); - } break; - case NOTIFICATION_EXIT_TREE: { stop(); } break; @@ -445,14 +415,6 @@ StringName SkeletonIK3D::get_tip_bone() const { return tip_bone; } -void SkeletonIK3D::set_interpolation(real_t p_interpolation) { - interpolation = p_interpolation; -} - -real_t SkeletonIK3D::get_interpolation() const { - return interpolation; -} - void SkeletonIK3D::set_target_transform(const Transform3D &p_target) { target = p_target; reload_goal(); @@ -505,33 +467,25 @@ void SkeletonIK3D::set_max_iterations(int p_iterations) { } Skeleton3D *SkeletonIK3D::get_parent_skeleton() const { - return cast_to<Skeleton3D>(skeleton_ref.get_validated_object()); + return get_skeleton(); } bool SkeletonIK3D::is_running() { - return is_processing_internal(); + return internal_active; } void SkeletonIK3D::start(bool p_one_time) { if (p_one_time) { - set_process_internal(false); - - if (target_node_override_ref) { - reload_goal(); - } - - _solve_chain(); + internal_active = true; + SkeletonModifier3D::process_modification(); + internal_active = false; } else { - set_process_internal(true); + internal_active = true; } } void SkeletonIK3D::stop() { - set_process_internal(false); - Skeleton3D *skeleton = get_parent_skeleton(); - if (skeleton) { - skeleton->clear_bones_global_pose_override(); - } + internal_active = false; } Transform3D SkeletonIK3D::_get_target_transform() { @@ -551,7 +505,7 @@ void SkeletonIK3D::reload_chain() { FabrikInverseKinematic::free_task(task); task = nullptr; - Skeleton3D *skeleton = get_parent_skeleton(); + Skeleton3D *skeleton = get_skeleton(); if (!skeleton) { return; } @@ -575,7 +529,5 @@ void SkeletonIK3D::_solve_chain() { if (!task) { return; } - FabrikInverseKinematic::solve(task, interpolation, override_tip_basis, use_magnet, magnet_position); + FabrikInverseKinematic::solve(task, override_tip_basis, use_magnet, magnet_position); } - -#endif // _3D_DISABLED diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h index 0a03e96905..eff018f2cc 100644 --- a/scene/3d/skeleton_ik_3d.h +++ b/scene/3d/skeleton_ik_3d.h @@ -31,9 +31,7 @@ #ifndef SKELETON_IK_3D_H #define SKELETON_IK_3D_H -#ifndef _3D_DISABLED - -#include "scene/3d/skeleton_3d.h" +#include "scene/3d/skeleton_modifier_3d.h" class FabrikInverseKinematic { struct EndEffector { @@ -111,18 +109,19 @@ public: static void free_task(Task *p_task); // The goal of chain should be always in local space static void set_goal(Task *p_task, const Transform3D &p_goal); - static void make_goal(Task *p_task, const Transform3D &p_inverse_transf, real_t blending_delta); - static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position); + static void make_goal(Task *p_task, const Transform3D &p_inverse_transf); + static void solve(Task *p_task, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position); static void _update_chain(const Skeleton3D *p_skeleton, ChainItem *p_chain_item); }; -class SkeletonIK3D : public Node { - GDCLASS(SkeletonIK3D, Node); +class SkeletonIK3D : public SkeletonModifier3D { + GDCLASS(SkeletonIK3D, SkeletonModifier3D); + + bool internal_active = false; StringName root_bone; StringName tip_bone; - real_t interpolation = 1.0; Transform3D target; NodePath target_node_path_override; bool override_tip_basis = true; @@ -132,7 +131,6 @@ class SkeletonIK3D : public Node { real_t min_distance = 0.01; int max_iterations = 10; - Variant skeleton_ref = Variant(); Variant target_node_override_ref = Variant(); FabrikInverseKinematic::Task *task = nullptr; @@ -142,6 +140,8 @@ protected: static void _bind_methods(); virtual void _notification(int p_what); + virtual void _process_modification() override; + public: SkeletonIK3D(); virtual ~SkeletonIK3D(); @@ -152,9 +152,6 @@ public: void set_tip_bone(const StringName &p_tip_bone); StringName get_tip_bone() const; - void set_interpolation(real_t p_interpolation); - real_t get_interpolation() const; - void set_target_transform(const Transform3D &p_target); const Transform3D &get_target_transform() const; @@ -190,6 +187,4 @@ private: void _solve_chain(); }; -#endif // _3D_DISABLED - #endif // SKELETON_IK_3D_H diff --git a/scene/3d/skeleton_modifier_3d.cpp b/scene/3d/skeleton_modifier_3d.cpp new file mode 100644 index 0000000000..96e3e33841 --- /dev/null +++ b/scene/3d/skeleton_modifier_3d.cpp @@ -0,0 +1,139 @@ +/**************************************************************************/ +/* skeleton_modifier_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "skeleton_modifier_3d.h" + +void SkeletonModifier3D::_validate_property(PropertyInfo &p_property) const { + // +} + +PackedStringArray SkeletonModifier3D::get_configuration_warnings() const { + PackedStringArray warnings = Node3D::get_configuration_warnings(); + if (skeleton_id.is_null()) { + warnings.push_back(RTR("Skeleton3D node not set! SkeletonModifier3D must be child of Skeleton3D or set a path to an external skeleton.")); + } + return warnings; +} + +/* Skeleton3D */ + +Skeleton3D *SkeletonModifier3D::get_skeleton() const { + return Object::cast_to<Skeleton3D>(ObjectDB::get_instance(skeleton_id)); +} + +void SkeletonModifier3D::_update_skeleton_path() { + skeleton_id = ObjectID(); + + // Make sure parent is a Skeleton3D. + Skeleton3D *sk = Object::cast_to<Skeleton3D>(get_parent()); + if (sk) { + skeleton_id = sk->get_instance_id(); + } +} + +void SkeletonModifier3D::_update_skeleton() { + if (!is_inside_tree()) { + return; + } + Skeleton3D *old_sk = get_skeleton(); + _update_skeleton_path(); + Skeleton3D *new_sk = get_skeleton(); + if (old_sk != new_sk) { + _skeleton_changed(old_sk, new_sk); + } + update_configuration_warnings(); +} + +void SkeletonModifier3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) { + // +} + +/* Process */ + +void SkeletonModifier3D::set_active(bool p_active) { + if (active == p_active) { + return; + } + active = p_active; + _set_active(active); +} + +bool SkeletonModifier3D::is_active() const { + return active; +} + +void SkeletonModifier3D::_set_active(bool p_active) { + // +} + +void SkeletonModifier3D::set_influence(real_t p_influence) { + influence = p_influence; +} + +real_t SkeletonModifier3D::get_influence() const { + return influence; +} + +void SkeletonModifier3D::process_modification() { + if (!active) { + return; + } + _process_modification(); + emit_signal(SNAME("modification_processed")); +} + +void SkeletonModifier3D::_process_modification() { + // +} + +void SkeletonModifier3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_PARENTED: { + _update_skeleton(); + } break; + } +} + +void SkeletonModifier3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_active", "active"), &SkeletonModifier3D::set_active); + ClassDB::bind_method(D_METHOD("is_active"), &SkeletonModifier3D::is_active); + + ClassDB::bind_method(D_METHOD("set_influence", "influence"), &SkeletonModifier3D::set_influence); + ClassDB::bind_method(D_METHOD("get_influence"), &SkeletonModifier3D::get_influence); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "influence", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_influence", "get_influence"); + + ADD_SIGNAL(MethodInfo("modification_processed")); +} + +SkeletonModifier3D::SkeletonModifier3D() { +} diff --git a/scene/3d/skeleton_modifier_3d.h b/scene/3d/skeleton_modifier_3d.h new file mode 100644 index 0000000000..25c09f3b93 --- /dev/null +++ b/scene/3d/skeleton_modifier_3d.h @@ -0,0 +1,81 @@ +/**************************************************************************/ +/* skeleton_modifier_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SKELETON_MODIFIER_3D_H +#define SKELETON_MODIFIER_3D_H + +#include "scene/3d/node_3d.h" + +#include "scene/3d/skeleton_3d.h" +#include "scene/animation/animation_mixer.h" + +class SkeletonModifier3D : public Node3D { + GDCLASS(SkeletonModifier3D, Node3D); + + void rebind(); + +protected: + bool active = true; + real_t influence = 1.0; + + // Cache them for the performance reason since finding node with NodePath is slow. + ObjectID skeleton_id; + + void _update_skeleton(); + void _update_skeleton_path(); + + virtual void _skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new); + + void _validate_property(PropertyInfo &p_property) const; + void _notification(int p_what); + static void _bind_methods(); + + virtual void _set_active(bool p_active); + + virtual void _process_modification(); + +public: + virtual PackedStringArray get_configuration_warnings() const override; + virtual bool has_process() const { return false; } // Return true if modifier needs to modify bone pose without external animation such as physics, jiggle and etc. + + void set_active(bool p_active); + bool is_active() const; + + void set_influence(real_t p_influence); + real_t get_influence() const; + + Skeleton3D *get_skeleton() const; + + void process_modification(); + + SkeletonModifier3D(); +}; + +#endif // SKELETON_MODIFIER_3D_H diff --git a/scene/3d/xr_body_modifier_3d.cpp b/scene/3d/xr_body_modifier_3d.cpp index ac648d66d0..0099784a05 100644 --- a/scene/3d/xr_body_modifier_3d.cpp +++ b/scene/3d/xr_body_modifier_3d.cpp @@ -38,9 +38,6 @@ void XRBodyModifier3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_body_tracker", "tracker_name"), &XRBodyModifier3D::set_body_tracker); ClassDB::bind_method(D_METHOD("get_body_tracker"), &XRBodyModifier3D::get_body_tracker); - ClassDB::bind_method(D_METHOD("set_target", "target"), &XRBodyModifier3D::set_target); - ClassDB::bind_method(D_METHOD("get_target"), &XRBodyModifier3D::get_target); - ClassDB::bind_method(D_METHOD("set_body_update", "body_update"), &XRBodyModifier3D::set_body_update); ClassDB::bind_method(D_METHOD("get_body_update"), &XRBodyModifier3D::get_body_update); @@ -51,7 +48,6 @@ void XRBodyModifier3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_show_when_tracked"), &XRBodyModifier3D::get_show_when_tracked); ADD_PROPERTY(PropertyInfo(Variant::STRING, "body_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/body"), "set_body_tracker", "get_body_tracker"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_target", "get_target"); ADD_PROPERTY(PropertyInfo(Variant::INT, "body_update", PROPERTY_HINT_FLAGS, "Upper Body,Lower Body,Hands"), "set_body_update", "get_body_update"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_when_tracked"), "set_show_when_tracked", "get_show_when_tracked"); @@ -73,18 +69,6 @@ StringName XRBodyModifier3D::get_body_tracker() const { return tracker_name; } -void XRBodyModifier3D::set_target(const NodePath &p_target) { - target = p_target; - - if (is_inside_tree()) { - _get_joint_data(); - } -} - -NodePath XRBodyModifier3D::get_target() const { - return target; -} - void XRBodyModifier3D::set_body_update(BitField<BodyUpdate> p_body_update) { body_update = p_body_update; } @@ -110,20 +94,6 @@ bool XRBodyModifier3D::get_show_when_tracked() const { return show_when_tracked; } -Skeleton3D *XRBodyModifier3D::get_skeleton() { - if (!has_node(target)) { - return nullptr; - } - - Node *node = get_node(target); - if (!node) { - return nullptr; - } - - Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); - return skeleton; -} - void XRBodyModifier3D::_get_joint_data() { // Table of Godot Humanoid bone names. static const String bone_names[XRBodyTracker::JOINT_MAX] = { @@ -281,7 +251,7 @@ void XRBodyModifier3D::_get_joint_data() { } } -void XRBodyModifier3D::_update_skeleton() { +void XRBodyModifier3D::_process_modification() { Skeleton3D *skeleton = get_skeleton(); if (!skeleton) { return; @@ -379,6 +349,10 @@ void XRBodyModifier3D::_tracker_changed(const StringName &p_tracker_name, const } } +void XRBodyModifier3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) { + _get_joint_data(); +} + void XRBodyModifier3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -388,10 +362,7 @@ void XRBodyModifier3D::_notification(int p_what) { xr_server->connect("body_tracker_updated", callable_mp(this, &XRBodyModifier3D::_tracker_changed)); xr_server->connect("body_tracker_removed", callable_mp(this, &XRBodyModifier3D::_tracker_changed).bind(Ref<XRBodyTracker>())); } - _get_joint_data(); - - set_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { XRServer *xr_server = XRServer::get_singleton(); @@ -400,17 +371,11 @@ void XRBodyModifier3D::_notification(int p_what) { xr_server->disconnect("body_tracker_updated", callable_mp(this, &XRBodyModifier3D::_tracker_changed)); xr_server->disconnect("body_tracker_removed", callable_mp(this, &XRBodyModifier3D::_tracker_changed).bind(Ref<XRBodyTracker>())); } - - set_process_internal(false); - for (int i = 0; i < XRBodyTracker::JOINT_MAX; i++) { joints[i].bone = -1; joints[i].parent_joint = -1; } } break; - case NOTIFICATION_INTERNAL_PROCESS: { - _update_skeleton(); - } break; default: { } break; } diff --git a/scene/3d/xr_body_modifier_3d.h b/scene/3d/xr_body_modifier_3d.h index 89ac69b6b0..03b1c07d53 100644 --- a/scene/3d/xr_body_modifier_3d.h +++ b/scene/3d/xr_body_modifier_3d.h @@ -31,7 +31,7 @@ #ifndef XR_BODY_MODIFIER_3D_H #define XR_BODY_MODIFIER_3D_H -#include "scene/3d/node_3d.h" +#include "scene/3d/skeleton_modifier_3d.h" #include "servers/xr/xr_body_tracker.h" class Skeleton3D; @@ -41,8 +41,8 @@ class Skeleton3D; data from an XRBodyTracker instance. */ -class XRBodyModifier3D : public Node3D { - GDCLASS(XRBodyModifier3D, Node3D); +class XRBodyModifier3D : public SkeletonModifier3D { + GDCLASS(XRBodyModifier3D, SkeletonModifier3D); public: enum BodyUpdate { @@ -60,9 +60,6 @@ public: void set_body_tracker(const StringName &p_tracker_name); StringName get_body_tracker() const; - void set_target(const NodePath &p_target); - NodePath get_target() const; - void set_body_update(BitField<BodyUpdate> p_body_update); BitField<BodyUpdate> get_body_update() const; @@ -77,6 +74,9 @@ public: protected: static void _bind_methods(); + virtual void _skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) override; + virtual void _process_modification() override; + private: struct JointData { int bone = -1; @@ -84,15 +84,12 @@ private: }; StringName tracker_name = "/user/body"; - NodePath target; BitField<BodyUpdate> body_update = BODY_UPDATE_UPPER_BODY | BODY_UPDATE_LOWER_BODY | BODY_UPDATE_HANDS; BoneUpdate bone_update = BONE_UPDATE_FULL; bool show_when_tracked = true; JointData joints[XRBodyTracker::JOINT_MAX]; - Skeleton3D *get_skeleton(); void _get_joint_data(); - void _update_skeleton(); void _tracker_changed(const StringName &p_tracker_name, const Ref<XRBodyTracker> &p_tracker); }; diff --git a/scene/3d/xr_hand_modifier_3d.cpp b/scene/3d/xr_hand_modifier_3d.cpp index 1e1449b54b..7fecb53008 100644 --- a/scene/3d/xr_hand_modifier_3d.cpp +++ b/scene/3d/xr_hand_modifier_3d.cpp @@ -30,7 +30,6 @@ #include "xr_hand_modifier_3d.h" -#include "scene/3d/skeleton_3d.h" #include "servers/xr/xr_pose.h" #include "servers/xr_server.h" @@ -38,14 +37,10 @@ void XRHandModifier3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hand_tracker", "tracker_name"), &XRHandModifier3D::set_hand_tracker); ClassDB::bind_method(D_METHOD("get_hand_tracker"), &XRHandModifier3D::get_hand_tracker); - ClassDB::bind_method(D_METHOD("set_target", "target"), &XRHandModifier3D::set_target); - ClassDB::bind_method(D_METHOD("get_target"), &XRHandModifier3D::get_target); - ClassDB::bind_method(D_METHOD("set_bone_update", "bone_update"), &XRHandModifier3D::set_bone_update); ClassDB::bind_method(D_METHOD("get_bone_update"), &XRHandModifier3D::get_bone_update); ADD_PROPERTY(PropertyInfo(Variant::STRING, "hand_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/left,/user/right"), "set_hand_tracker", "get_hand_tracker"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_target", "get_target"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update"); BIND_ENUM_CONSTANT(BONE_UPDATE_FULL); @@ -61,18 +56,6 @@ StringName XRHandModifier3D::get_hand_tracker() const { return tracker_name; } -void XRHandModifier3D::set_target(const NodePath &p_target) { - target = p_target; - - if (is_inside_tree()) { - _get_joint_data(); - } -} - -NodePath XRHandModifier3D::get_target() const { - return target; -} - void XRHandModifier3D::set_bone_update(BoneUpdate p_bone_update) { ERR_FAIL_INDEX(p_bone_update, BONE_UPDATE_MAX); bone_update = p_bone_update; @@ -82,21 +65,11 @@ XRHandModifier3D::BoneUpdate XRHandModifier3D::get_bone_update() const { return bone_update; } -Skeleton3D *XRHandModifier3D::get_skeleton() { - if (!has_node(target)) { - return nullptr; - } - - Node *node = get_node(target); - if (!node) { - return nullptr; +void XRHandModifier3D::_get_joint_data() { + if (!is_inside_tree()) { + return; } - Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); - return skeleton; -} - -void XRHandModifier3D::_get_joint_data() { // Table of bone names for different rig types. static const String bone_names[XRHandTracker::HAND_JOINT_MAX] = { "Palm", @@ -197,7 +170,7 @@ void XRHandModifier3D::_get_joint_data() { } } -void XRHandModifier3D::_update_skeleton() { +void XRHandModifier3D::_process_modification() { Skeleton3D *skeleton = get_skeleton(); if (!skeleton) { return; @@ -276,6 +249,10 @@ void XRHandModifier3D::_tracker_changed(StringName p_tracker_name, const Ref<XRH } } +void XRHandModifier3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) { + _get_joint_data(); +} + void XRHandModifier3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -287,8 +264,6 @@ void XRHandModifier3D::_notification(int p_what) { } _get_joint_data(); - - set_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { XRServer *xr_server = XRServer::get_singleton(); @@ -298,16 +273,11 @@ void XRHandModifier3D::_notification(int p_what) { xr_server->disconnect("hand_tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed).bind(Ref<XRHandTracker>())); } - set_process_internal(false); - for (int i = 0; i < XRHandTracker::HAND_JOINT_MAX; i++) { joints[i].bone = -1; joints[i].parent_joint = -1; } } break; - case NOTIFICATION_INTERNAL_PROCESS: { - _update_skeleton(); - } break; default: { } break; } diff --git a/scene/3d/xr_hand_modifier_3d.h b/scene/3d/xr_hand_modifier_3d.h index 2bc30d42d4..9f7ce45c9d 100644 --- a/scene/3d/xr_hand_modifier_3d.h +++ b/scene/3d/xr_hand_modifier_3d.h @@ -31,18 +31,16 @@ #ifndef XR_HAND_MODIFIER_3D_H #define XR_HAND_MODIFIER_3D_H -#include "scene/3d/node_3d.h" +#include "scene/3d/skeleton_modifier_3d.h" #include "servers/xr/xr_hand_tracker.h" -class Skeleton3D; - /** The XRHandModifier3D node drives a hand skeleton using hand tracking data from an XRHandTracking instance. */ -class XRHandModifier3D : public Node3D { - GDCLASS(XRHandModifier3D, Node3D); +class XRHandModifier3D : public SkeletonModifier3D { + GDCLASS(XRHandModifier3D, SkeletonModifier3D); public: enum BoneUpdate { @@ -54,9 +52,6 @@ public: void set_hand_tracker(const StringName &p_tracker_name); StringName get_hand_tracker() const; - void set_target(const NodePath &p_target); - NodePath get_target() const; - void set_bone_update(BoneUpdate p_bone_update); BoneUpdate get_bone_update() const; @@ -65,6 +60,9 @@ public: protected: static void _bind_methods(); + virtual void _skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) override; + virtual void _process_modification() override; + private: struct JointData { int bone = -1; @@ -72,13 +70,10 @@ private: }; StringName tracker_name = "/user/left"; - NodePath target; BoneUpdate bone_update = BONE_UPDATE_FULL; JointData joints[XRHandTracker::HAND_JOINT_MAX]; - Skeleton3D *get_skeleton(); void _get_joint_data(); - void _update_skeleton(); void _tracker_changed(StringName p_tracker_name, const Ref<XRHandTracker> &p_tracker); }; diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index 22f919ad36..757ac68e46 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -42,6 +42,7 @@ #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/node_3d.h" #include "scene/3d/skeleton_3d.h" +#include "scene/3d/skeleton_modifier_3d.h" #endif // _3D_DISABLED #ifdef TOOLS_ENABLED @@ -484,10 +485,6 @@ void AnimationMixer::set_callback_mode_process(AnimationCallbackModeProcess p_mo if (was_active) { set_active(true); } - -#ifdef TOOLS_ENABLED - emit_signal(SNAME("mixer_updated")); -#endif // TOOLS_ENABLED } AnimationMixer::AnimationCallbackModeProcess AnimationMixer::get_callback_mode_process() const { @@ -496,9 +493,7 @@ AnimationMixer::AnimationCallbackModeProcess AnimationMixer::get_callback_mode_p void AnimationMixer::set_callback_mode_method(AnimationCallbackModeMethod p_mode) { callback_mode_method = p_mode; -#ifdef TOOLS_ENABLED emit_signal(SNAME("mixer_updated")); -#endif // TOOLS_ENABLED } AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_method() const { @@ -507,9 +502,7 @@ AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_me void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) { callback_mode_discrete = p_mode; -#ifdef TOOLS_ENABLED emit_signal(SNAME("mixer_updated")); -#endif // TOOLS_ENABLED } AnimationMixer::AnimationCallbackModeDiscrete AnimationMixer::get_callback_mode_discrete() const { @@ -930,6 +923,7 @@ void AnimationMixer::_process_animation(double p_delta, bool p_update_only) { _blend_process(p_delta, p_update_only); _blend_apply(); _blend_post_process(); + emit_signal(SNAME("mixer_applied")); }; clear_animation_instances(); } @@ -2228,19 +2222,16 @@ void AnimationMixer::_bind_methods() { ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance); GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic"); + /* ---- Capture feature ---- */ + ClassDB::bind_method(D_METHOD("capture", "name", "duration", "trans_type", "ease_type"), &AnimationMixer::capture, DEFVAL(Tween::TRANS_LINEAR), DEFVAL(Tween::EASE_IN)); /* ---- Reset on save ---- */ ClassDB::bind_method(D_METHOD("set_reset_on_save_enabled", "enabled"), &AnimationMixer::set_reset_on_save_enabled); ClassDB::bind_method(D_METHOD("is_reset_on_save_enabled"), &AnimationMixer::is_reset_on_save_enabled); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled"); - - /* ---- Capture feature ---- */ - ClassDB::bind_method(D_METHOD("capture", "name", "duration", "trans_type", "ease_type"), &AnimationMixer::capture, DEFVAL(Tween::TRANS_LINEAR), DEFVAL(Tween::EASE_IN)); - - ADD_SIGNAL(MethodInfo("mixer_updated")); // For updating dummy player. + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root_node", "get_root_node"); ADD_GROUP("Root Motion", "root_motion_"); @@ -2270,6 +2261,8 @@ void AnimationMixer::_bind_methods() { ADD_SIGNAL(MethodInfo(SNAME("animation_finished"), PropertyInfo(Variant::STRING_NAME, "anim_name"))); ADD_SIGNAL(MethodInfo(SNAME("animation_started"), PropertyInfo(Variant::STRING_NAME, "anim_name"))); ADD_SIGNAL(MethodInfo(SNAME("caches_cleared"))); + ADD_SIGNAL(MethodInfo(SNAME("mixer_applied"))); + ADD_SIGNAL(MethodInfo(SNAME("mixer_updated"))); // For updating dummy player. ClassDB::bind_method(D_METHOD("_reset"), &AnimationMixer::reset); ClassDB::bind_method(D_METHOD("_restore", "backup"), &AnimationMixer::restore); diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index 682246f9ab..ed291bfe63 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -341,6 +341,8 @@ protected: /* ---- Blending processor ---- */ virtual void _process_animation(double p_delta, bool p_update_only = false); + + // For post process with retrieved key value during blending. virtual Variant _post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1); Variant post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1); GDVIRTUAL5RC(Variant, _post_process_key_value, Ref<Animation>, int, Variant, ObjectID, int); @@ -377,7 +379,6 @@ protected: #ifndef DISABLE_DEPRECATED virtual Variant _post_process_key_value_bind_compat_86687(const Ref<Animation> &p_anim, int p_track, Variant p_value, Object *p_object, int p_object_idx = -1); - static void _bind_compatibility_methods(); #endif // DISABLE_DEPRECATED @@ -436,7 +437,7 @@ public: void make_animation_instance(const StringName &p_name, const PlaybackInfo p_playback_info); void clear_animation_instances(); virtual void advance(double p_time); - virtual void clear_caches(); ///< must be called by hand if an animation was modified after added + virtual void clear_caches(); // Must be called by hand if an animation was modified after added. /* ---- Capture feature ---- */ void capture(const StringName &p_name, double p_duration, Tween::TransitionType p_trans_type = Tween::TRANS_LINEAR, Tween::EaseType p_ease_type = Tween::EASE_IN); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 2df1e81e25..4880a0f6ed 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -815,10 +815,7 @@ void AnimationTree::set_animation_player(const NodePath &p_path) { remove_animation_library(animation_libraries[0].name); } } -#ifdef TOOLS_ENABLED emit_signal(SNAME("animation_player_changed")); // Needs to unpin AnimationPlayerEditor. - emit_signal(SNAME("mixer_updated")); -#endif // TOOLS_ENABLED _setup_animation_player(); notify_property_list_changed(); } @@ -964,9 +961,7 @@ void AnimationTree::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node"), "set_advance_expression_base_node", "get_advance_expression_base_node"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player"); -#ifdef TOOLS_ENABLED ADD_SIGNAL(MethodInfo(SNAME("animation_player_changed"))); -#endif // TOOLS_ENABLED } AnimationTree::AnimationTree() { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 62bb14459d..f1a8c2f6ae 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -241,10 +241,6 @@ PackedStringArray Control::get_configuration_warnings() const { warnings.push_back(RTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\".")); } - if (get_z_index() != 0) { - warnings.push_back(RTR("Changing the Z index of a control only affects the drawing order, not the input event handling order.")); - } - return warnings; } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 11c200064e..beb2583b61 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -3780,7 +3780,7 @@ void Node::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_messages", PROPERTY_HINT_FLAGS, "Process,Physics Process"), "set_process_thread_messages", "get_process_thread_messages"); ADD_GROUP("Physics Interpolation", "physics_interpolation_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_physics_interpolation_mode", "get_physics_interpolation_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,On,Off"), "set_physics_interpolation_mode", "get_physics_interpolation_mode"); ADD_GROUP("Auto Translate", "auto_translate_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "auto_translate_mode", PROPERTY_HINT_ENUM, "Inherit,Always,Disabled"), "set_auto_translate_mode", "get_auto_translate_mode"); @@ -3833,7 +3833,7 @@ Node::Node() { data.unhandled_input = false; data.unhandled_key_input = false; - data.physics_interpolated = false; + data.physics_interpolated = true; data.parent_owned = false; data.in_constructor = true; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index f645bb5e73..752cfe2288 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -253,6 +253,7 @@ #include "scene/3d/node_3d.h" #include "scene/3d/occluder_instance_3d.h" #include "scene/3d/path_3d.h" +#include "scene/3d/physical_bone_simulator_3d.h" #include "scene/3d/physics/animatable_body_3d.h" #include "scene/3d/physics/area_3d.h" #include "scene/3d/physics/character_body_3d.h" @@ -277,6 +278,7 @@ #include "scene/3d/remote_transform_3d.h" #include "scene/3d/skeleton_3d.h" #include "scene/3d/skeleton_ik_3d.h" +#include "scene/3d/skeleton_modifier_3d.h" #include "scene/3d/soft_body_3d.h" #include "scene/3d/sprite_3d.h" #include "scene/3d/visible_on_screen_notifier_3d.h" @@ -586,6 +588,7 @@ void register_scene_types() { GDREGISTER_CLASS(CPUParticles3D); GDREGISTER_CLASS(Marker3D); GDREGISTER_CLASS(RootMotionView); + GDREGISTER_ABSTRACT_CLASS(SkeletonModifier3D); OS::get_singleton()->yield(); // may take time to init @@ -598,6 +601,7 @@ void register_scene_types() { GDREGISTER_CLASS(CharacterBody3D); GDREGISTER_CLASS(SpringArm3D); + GDREGISTER_CLASS(PhysicalBoneSimulator3D); GDREGISTER_CLASS(PhysicalBone3D); GDREGISTER_CLASS(SoftBody3D); diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp index 24ed480289..2c1d3d4a4c 100644 --- a/scene/resources/skeleton_profile.cpp +++ b/scene/resources/skeleton_profile.cpp @@ -68,7 +68,7 @@ bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) { } else if (what == "group") { set_group(which, p_value); } else if (what == "require") { - set_require(which, p_value); + set_required(which, p_value); } else { return false; } @@ -113,7 +113,7 @@ bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const { } else if (what == "group") { r_ret = get_group(which); } else if (what == "require") { - r_ret = is_require(which); + r_ret = is_required(which); } else { return false; } @@ -299,7 +299,7 @@ SkeletonProfile::TailDirection SkeletonProfile::get_tail_direction(int p_bone_id return bones[p_bone_idx].tail_direction; } -void SkeletonProfile::set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction) { +void SkeletonProfile::set_tail_direction(int p_bone_idx, TailDirection p_tail_direction) { if (is_read_only) { return; } @@ -328,7 +328,7 @@ Transform3D SkeletonProfile::get_reference_pose(int p_bone_idx) const { return bones[p_bone_idx].reference_pose; } -void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose) { +void SkeletonProfile::set_reference_pose(int p_bone_idx, const Transform3D &p_reference_pose) { if (is_read_only) { return; } @@ -342,7 +342,7 @@ Vector2 SkeletonProfile::get_handle_offset(int p_bone_idx) const { return bones[p_bone_idx].handle_offset; } -void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset) { +void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 &p_handle_offset) { if (is_read_only) { return; } @@ -365,17 +365,17 @@ void SkeletonProfile::set_group(int p_bone_idx, const StringName &p_group) { emit_signal("profile_updated"); } -bool SkeletonProfile::is_require(int p_bone_idx) const { +bool SkeletonProfile::is_required(int p_bone_idx) const { ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), false); - return bones[p_bone_idx].require; + return bones[p_bone_idx].required; } -void SkeletonProfile::set_require(int p_bone_idx, const bool p_require) { +void SkeletonProfile::set_required(int p_bone_idx, bool p_required) { if (is_read_only) { return; } ERR_FAIL_INDEX(p_bone_idx, bones.size()); - bones.write[p_bone_idx].require = p_require; + bones.write[p_bone_idx].required = p_required; emit_signal("profile_updated"); } @@ -432,6 +432,9 @@ void SkeletonProfile::_bind_methods() { ClassDB::bind_method(D_METHOD("get_group", "bone_idx"), &SkeletonProfile::get_group); ClassDB::bind_method(D_METHOD("set_group", "bone_idx", "group"), &SkeletonProfile::set_group); + ClassDB::bind_method(D_METHOD("is_required", "bone_idx"), &SkeletonProfile::is_required); + ClassDB::bind_method(D_METHOD("set_required", "bone_idx", "required"), &SkeletonProfile::set_required); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_root_bone", "get_root_bone"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "scale_base_bone", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_scale_base_bone", "get_scale_base_bone"); @@ -478,14 +481,14 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[1].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0); bones.write[1].handle_offset = Vector2(0.5, 0.5); bones.write[1].group = "Body"; - bones.write[1].require = true; + bones.write[1].required = true; bones.write[2].bone_name = "Spine"; bones.write[2].bone_parent = "Hips"; bones.write[2].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0); bones.write[2].handle_offset = Vector2(0.5, 0.43); bones.write[2].group = "Body"; - bones.write[2].require = true; + bones.write[2].required = true; bones.write[3].bone_name = "Chest"; bones.write[3].bone_parent = "Spine"; @@ -506,7 +509,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0); bones.write[5].handle_offset = Vector2(0.5, 0.23); bones.write[5].group = "Body"; - bones.write[5].require = false; + bones.write[5].required = false; bones.write[6].bone_name = "Head"; bones.write[6].bone_parent = "Neck"; @@ -514,7 +517,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[6].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0); bones.write[6].handle_offset = Vector2(0.5, 0.18); bones.write[6].group = "Body"; - bones.write[6].require = true; + bones.write[6].required = true; bones.write[7].bone_name = "LeftEye"; bones.write[7].bone_parent = "Head"; @@ -539,21 +542,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[10].reference_pose = Transform3D(0, 1, 0, 0, 0, 1, 1, 0, 0, 0.05, 0.1, 0); bones.write[10].handle_offset = Vector2(0.55, 0.235); bones.write[10].group = "Body"; - bones.write[10].require = true; + bones.write[10].required = true; bones.write[11].bone_name = "LeftUpperArm"; bones.write[11].bone_parent = "LeftShoulder"; bones.write[11].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0); bones.write[11].handle_offset = Vector2(0.6, 0.24); bones.write[11].group = "Body"; - bones.write[11].require = true; + bones.write[11].required = true; bones.write[12].bone_name = "LeftLowerArm"; bones.write[12].bone_parent = "LeftUpperArm"; bones.write[12].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0); bones.write[12].handle_offset = Vector2(0.7, 0.24); bones.write[12].group = "Body"; - bones.write[12].require = true; + bones.write[12].required = true; bones.write[13].bone_name = "LeftHand"; bones.write[13].bone_parent = "LeftLowerArm"; @@ -562,7 +565,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[13].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0); bones.write[13].handle_offset = Vector2(0.82, 0.235); bones.write[13].group = "Body"; - bones.write[13].require = true; + bones.write[13].required = true; bones.write[14].bone_name = "LeftThumbMetacarpal"; bones.write[14].bone_parent = "LeftHand"; @@ -659,21 +662,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[29].reference_pose = Transform3D(0, -1, 0, 0, 0, 1, -1, 0, 0, -0.05, 0.1, 0); bones.write[29].handle_offset = Vector2(0.45, 0.235); bones.write[29].group = "Body"; - bones.write[29].require = true; + bones.write[29].required = true; bones.write[30].bone_name = "RightUpperArm"; bones.write[30].bone_parent = "RightShoulder"; bones.write[30].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.05, 0); bones.write[30].handle_offset = Vector2(0.4, 0.24); bones.write[30].group = "Body"; - bones.write[30].require = true; + bones.write[30].required = true; bones.write[31].bone_name = "RightLowerArm"; bones.write[31].bone_parent = "RightUpperArm"; bones.write[31].reference_pose = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0.25, 0); bones.write[31].handle_offset = Vector2(0.3, 0.24); bones.write[31].group = "Body"; - bones.write[31].require = true; + bones.write[31].required = true; bones.write[32].bone_name = "RightHand"; bones.write[32].bone_parent = "RightLowerArm"; @@ -682,7 +685,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[32].reference_pose = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0.25, 0); bones.write[32].handle_offset = Vector2(0.18, 0.235); bones.write[32].group = "Body"; - bones.write[32].require = true; + bones.write[32].required = true; bones.write[33].bone_name = "RightThumbMetacarpal"; bones.write[33].bone_parent = "RightHand"; @@ -779,21 +782,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[48].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, 0.1, 0, 0); bones.write[48].handle_offset = Vector2(0.549, 0.49); bones.write[48].group = "Body"; - bones.write[48].require = true; + bones.write[48].required = true; bones.write[49].bone_name = "LeftLowerLeg"; bones.write[49].bone_parent = "LeftUpperLeg"; bones.write[49].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0); bones.write[49].handle_offset = Vector2(0.548, 0.683); bones.write[49].group = "Body"; - bones.write[49].require = true; + bones.write[49].required = true; bones.write[50].bone_name = "LeftFoot"; bones.write[50].bone_parent = "LeftLowerLeg"; bones.write[50].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0); bones.write[50].handle_offset = Vector2(0.545, 0.9); bones.write[50].group = "Body"; - bones.write[50].require = true; + bones.write[50].required = true; bones.write[51].bone_name = "LeftToes"; bones.write[51].bone_parent = "LeftFoot"; @@ -806,21 +809,21 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() { bones.write[52].reference_pose = Transform3D(-1, 0, 0, 0, -1, 0, 0, 0, 1, -0.1, 0, 0); bones.write[52].handle_offset = Vector2(0.451, 0.49); bones.write[52].group = "Body"; - bones.write[52].require = true; + bones.write[52].required = true; bones.write[53].bone_name = "RightLowerLeg"; bones.write[53].bone_parent = "RightUpperLeg"; bones.write[53].reference_pose = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0.375, 0); bones.write[53].handle_offset = Vector2(0.452, 0.683); bones.write[53].group = "Body"; - bones.write[53].require = true; + bones.write[53].required = true; bones.write[54].bone_name = "RightFoot"; bones.write[54].bone_parent = "RightLowerLeg"; bones.write[54].reference_pose = Transform3D(-1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0.375, 0); bones.write[54].handle_offset = Vector2(0.455, 0.9); bones.write[54].group = "Body"; - bones.write[54].require = true; + bones.write[54].required = true; bones.write[55].bone_name = "RightToes"; bones.write[55].bone_parent = "RightFoot"; diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h index 143f495c61..b5a3bce940 100644 --- a/scene/resources/skeleton_profile.h +++ b/scene/resources/skeleton_profile.h @@ -61,7 +61,7 @@ protected: Transform3D reference_pose; Vector2 handle_offset; StringName group; - bool require = false; + bool required = false; }; StringName root_bone; @@ -104,22 +104,22 @@ public: void set_bone_parent(int p_bone_idx, const StringName &p_bone_parent); TailDirection get_tail_direction(int p_bone_idx) const; - void set_tail_direction(int p_bone_idx, const TailDirection p_tail_direction); + void set_tail_direction(int p_bone_idx, TailDirection p_tail_direction); StringName get_bone_tail(int p_bone_idx) const; void set_bone_tail(int p_bone_idx, const StringName &p_bone_tail); Transform3D get_reference_pose(int p_bone_idx) const; - void set_reference_pose(int p_bone_idx, const Transform3D p_reference_pose); + void set_reference_pose(int p_bone_idx, const Transform3D &p_reference_pose); Vector2 get_handle_offset(int p_bone_idx) const; - void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset); + void set_handle_offset(int p_bone_idx, const Vector2 &p_handle_offset); StringName get_group(int p_bone_idx) const; void set_group(int p_bone_idx, const StringName &p_group); - bool is_require(int p_bone_idx) const; - void set_require(int p_bone_idx, const bool p_require); + bool is_required(int p_bone_idx) const; + void set_required(int p_bone_idx, bool p_required); bool has_bone(const StringName &p_bone_name); |