diff --git a/scene/3d/physical_bone_simulator_3d.cpp b/scene/3d/physical_bone_simulator_3d.cpp index 4a619da4e44..491a3073732 100644 --- a/scene/3d/physical_bone_simulator_3d.cpp +++ b/scene/3d/physical_bone_simulator_3d.cpp @@ -73,9 +73,14 @@ void PhysicalBoneSimulator3D::_pose_updated() { if (!skeleton || simulating) { return; } - ERR_FAIL_COND(skeleton->get_bone_count() != bones.size()); - for (int i = 0; i < skeleton->get_bone_count(); i++) { - _bone_pose_updated(skeleton, i); + // If this triggers that means that we likely haven't rebuilt the bone list yet. + if (skeleton->get_bone_count() != bones.size()) { + // NOTE: this is re-entrant and will call _pose_updated again. + _bone_list_changed(); + } else { + for (int i = 0; i < skeleton->get_bone_count(); i++) { + _bone_pose_updated(skeleton, i); + } } } diff --git a/scene/3d/physics/physical_bone_3d.cpp b/scene/3d/physics/physical_bone_3d.cpp index cf6af50d2ef..49359a7e8ac 100644 --- a/scene/3d/physics/physical_bone_3d.cpp +++ b/scene/3d/physics/physical_bone_3d.cpp @@ -752,8 +752,9 @@ void PhysicalBone3D::_get_property_list(List *p_list) const { void PhysicalBone3D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_PARENTED: + // We need to wait until the bone has finished being added to the tree + // or none of the global transform calls will work correctly. + case NOTIFICATION_POST_ENTER_TREE: _update_simulator_path(); update_bone_id(); reset_to_rest_position(); @@ -763,6 +764,9 @@ void PhysicalBone3D::_notification(int p_what) { } break; + // If we're detached from the skeleton we need to + // clear our references to it. + case NOTIFICATION_UNPARENTED: case NOTIFICATION_EXIT_TREE: { PhysicalBoneSimulator3D *simulator = get_simulator(); if (simulator) { diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 3fd77d4641a..0c5429c0918 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -838,6 +838,13 @@ bool Skeleton3D::is_show_rest_only() const { void Skeleton3D::clear_bones() { bones.clear(); name_to_bone_index.clear(); + + // All these structures contain references to now invalid bone indices. + skin_bindings.clear(); + bone_global_pose_dirty.clear(); + parentless_bones.clear(); + nested_set_offset_to_bone_index.clear(); + process_order_dirty = true; version++; _make_dirty(); @@ -1091,6 +1098,8 @@ void Skeleton3D::_force_update_bone_children_transforms(int p_bone_idx) const { const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone_idx, bone_size); + _update_process_order(); + Bone *bonesptr = bones.ptr(); // Loop through nested set.