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
This commit is contained in:
committed by
Jesse Yurkovich
parent
1d2c1d2fa7
commit
84367f8cb9
@@ -665,6 +665,7 @@ static void set_rest_pose(Main *bmain,
|
||||
bArmature *arm,
|
||||
const pxr::VtArray<pxr::GfMatrix4d> &bind_xforms,
|
||||
const pxr::VtTokenArray &joint_order,
|
||||
const blender::Map<pxr::TfToken, std::string> &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<pxr::TfToken> 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<bArmature *>(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);
|
||||
|
||||
Reference in New Issue
Block a user