diff --git a/core/object/object.h b/core/object/object.h index c6446a2a0209..d8909ec6e320 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -585,6 +585,7 @@ class Object { // Store on each object a bitfield to quickly test whether it is derived from some "key" classes // that are commonly tested in performance sensitive code. // Ensure unsigned to bitpack. + // If you want to add more classes, please make sure to edit the Object::_ancestry field. enum class AncestralClass : unsigned int { REF_COUNTED = 1 << 0, NODE = 1 << 1, @@ -603,6 +604,8 @@ class Object { COLLISION_OBJECT_3D = 1 << 12, PHYSICS_BODY_3D = 1 << 13, MESH_INSTANCE_3D = 1 << 14, + // Used a lot in AnimationMixer, SkeletonModifier3D and BoneAttachment3D. + SKELETON_3D = 1 << 15, }; static constexpr AncestralClass static_ancestral_class = (AncestralClass)0; @@ -653,7 +656,7 @@ class Object { void _initialize(); void _postinitialize(); - uint32_t _ancestry : 15; + uint32_t _ancestry : 16; bool _block_signals : 1; bool _can_translate : 1; diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index a66655ebd3a5..ac186ca57483 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -321,7 +321,6 @@ void Skeleton3D::_notification(int p_what) { // Process modifiers. - LocalVector bones_backup; _find_modifiers(); if (!modifiers.is_empty()) { bones_backup.resize(bones.size()); @@ -840,12 +839,16 @@ void Skeleton3D::clear_bones() { // Posing api void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) { + set_bone_pose_components(p_bone, p_pose.origin, p_pose.basis.get_rotation_quaternion(), p_pose.basis.get_scale()); +} + +void Skeleton3D::set_bone_pose_components(int p_bone, const Vector3 &p_position, const Quaternion &p_rotation, const Vector3 &p_scale) { const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone, bone_size); - bones[p_bone].pose_position = p_pose.origin; - bones[p_bone].pose_rotation = p_pose.basis.get_rotation_quaternion(); - bones[p_bone].pose_scale = p_pose.basis.get_scale(); + bones[p_bone].pose_position = p_position; + bones[p_bone].pose_rotation = p_rotation; + bones[p_bone].pose_scale = p_scale; bones[p_bone].pose_cache_dirty = true; if (is_inside_tree()) { _make_dirty(); @@ -1416,6 +1419,7 @@ void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) { #endif // _DISABLE_DEPRECATED Skeleton3D::Skeleton3D() { + _define_ancestry(AncestralClass::SKELETON_3D); } Skeleton3D::~Skeleton3D() { diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 66ae8bd7c6fb..1ae318bc1e8e 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -76,6 +76,8 @@ class Skeleton3D : public Node3D { #endif // _DISABLE_DEPRECATED && PHYSICS_3D_DISABLED public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::SKELETON_3D; + enum ModifierCallbackModeProcess { MODIFIER_CALLBACK_MODE_PROCESS_PHYSICS, MODIFIER_CALLBACK_MODE_PROCESS_IDLE, @@ -160,6 +162,7 @@ class Skeleton3D : public Node3D { HashSet skin_bindings; void _skin_changed(); + LocalVector bones_backup; mutable LocalVector bones; mutable bool process_order_dirty = false; @@ -267,6 +270,7 @@ class Skeleton3D : public Node3D { 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_components(int p_bone, const Vector3 &p_position, const Quaternion &p_rotation, const Vector3 &p_scale); 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); diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index 5890baa2ef07..6be6b499704a 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -1878,29 +1878,39 @@ void AnimationMixer::_blend_apply() { if (!t_skeleton) { return; } - if (t->loc_used) { - t_skeleton->set_bone_pose_position(t->bone_idx, t->loc); - } - if (t->rot_used) { - t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot); - } - if (t->scale_used) { - t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale); - } + if (t->loc_used && t->rot_used && t->scale_used) { + t_skeleton->set_bone_pose_components(t->bone_idx, t->loc, t->rot, t->scale); + } else { + if (t->loc_used) { + t_skeleton->set_bone_pose_position(t->bone_idx, t->loc); + } + if (t->rot_used) { + t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot); + } + if (t->scale_used) { + t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale); + } + } } else if (!t->skeleton_id.is_valid()) { Node3D *t_node_3d = ObjectDB::get_instance(t->object_id); if (!t_node_3d) { return; } - if (t->loc_used) { - t_node_3d->set_position(t->loc); - } - if (t->rot_used) { - t_node_3d->set_rotation(t->rot.get_euler()); - } - if (t->scale_used) { - t_node_3d->set_scale(t->scale); + + if (t->loc_used && t->rot_used && t->scale_used) { + Transform3D transform = Transform3D(Basis(t->rot).scaled(t->scale), t->loc); + t_node_3d->set_transform(transform); + } else { + if (t->loc_used) { + t_node_3d->set_position(t->loc); + } + if (t->rot_used) { + t_node_3d->set_rotation(t->rot.get_euler()); + } + if (t->scale_used) { + t_node_3d->set_scale(t->scale); + } } } #endif // _3D_DISABLED