From 84367f8cb9ed8169898f0719aa7ff291d8420e23 Mon Sep 17 00:00:00 2001 From: Jesse Yurkovich Date: Thu, 17 Jul 2025 19:49:29 +0200 Subject: [PATCH] Fix #142084: Importing broken USD skeletons can crash The repro file in question contained invalid paths for the USD Skeleton. This was not detected in our import code which proceeded to create bones with empty (`""`), incorrect, names and subsequently allowed the rest-pose setup to use non-existent bones during processing. The primary fix here is to ensure that all incoming joint paths are both valid and unique[1]. A secondary fix is made to the rest-pose function to use our joint-to-bone map to ensure we are using the correct bone names. [1] https://openusd.org/release/api/class_usd_skel_skeleton.html#aa6bf8297f4aae6de9fbf1b784c524d30 Pull Request: https://projects.blender.org/blender/blender/pulls/142133 --- .../blender/io/usd/intern/usd_skel_convert.cc | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/source/blender/io/usd/intern/usd_skel_convert.cc b/source/blender/io/usd/intern/usd_skel_convert.cc index 32ae7108752..28ec291fd0b 100644 --- a/source/blender/io/usd/intern/usd_skel_convert.cc +++ b/source/blender/io/usd/intern/usd_skel_convert.cc @@ -665,6 +665,7 @@ static void set_rest_pose(Main *bmain, bArmature *arm, const pxr::VtArray &bind_xforms, const pxr::VtTokenArray &joint_order, + const blender::Map &joint_to_bone_map, const pxr::UsdSkelTopology &skel_topology, const pxr::UsdSkelSkeletonQuery &skel_query) { @@ -678,9 +679,13 @@ static void set_rest_pose(Main *bmain, int64_t i = 0; for (const pxr::TfToken &joint : joint_order) { - const pxr::SdfPath joint_path(joint); - const std::string &name = joint_path.GetName(); - bPoseChannel *pchan = BKE_pose_channel_find_name(arm_obj->pose, name.c_str()); + const std::string *name = joint_to_bone_map.lookup_ptr(joint); + if (name == nullptr) { + /* This joint doesn't correspond to any bone we created. Skip. */ + continue; + } + + bPoseChannel *pchan = BKE_pose_channel_find_name(arm_obj->pose, name->c_str()); pxr::GfMatrix4d xf = rest_xforms.AsConst()[i]; pxr::GfMatrix4d bind_xf = bind_xforms[i]; @@ -734,6 +739,23 @@ void import_skeleton(Main *bmain, return; } + /* Each joint path should be valid and unique. */ + blender::Set unique_joint_paths; + unique_joint_paths.reserve(joint_order.size()); + const bool all_valid_paths = std::all_of( + joint_order.cbegin(), joint_order.cend(), [&unique_joint_paths](const pxr::TfToken &val) { + const bool is_valid = pxr::SdfPath::IsValidPathString(val); + return is_valid && unique_joint_paths.add(val); + }); + if (!all_valid_paths) { + BKE_reportf(reports, + RPT_WARNING, + "%s: USD joint order array contains invalid or duplicated paths for skeleton %s", + __func__, + skel.GetPath().GetAsString().c_str()); + return; + } + bArmature *arm = static_cast(arm_obj->data); /* Set the armature to edit mode when creating the bones. */ @@ -962,7 +984,8 @@ void import_skeleton(Main *bmain, ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); - set_rest_pose(bmain, arm_obj, arm, bind_xforms, joint_order, skel_topology, skel_query); + set_rest_pose( + bmain, arm_obj, arm, bind_xforms, joint_order, joint_to_bone_map, skel_topology, skel_query); if (import_anim && valid_skeleton) { import_skeleton_curves(bmain, arm_obj, skel_query, joint_to_bone_map, reports);