Fix #130907: Use Blender Action name as the UsdSkelAnimation name

Rather than using a default "Anim" name when exporting armature
animations, use the animation's Action name instead. Likewise use the
UsdSkelAnimation name for the Action's name during import.

Blendshapes/shapekeys still use the default "Anim" name as there's no
action for these situations.

Pull Request: https://projects.blender.org/blender/blender/pulls/131021
This commit is contained in:
Jesse Yurkovich
2024-12-04 23:43:07 +01:00
committed by Jesse Yurkovich
parent cb94b62775
commit 69c63311fa
5 changed files with 29 additions and 14 deletions

View File

@@ -304,19 +304,26 @@ void remap_blend_shape_anim(pxr::UsdStageRefPtr stage,
const pxr::SdfPath &skel_path, const pxr::SdfPath &skel_path,
const pxr::SdfPathSet &mesh_paths) const pxr::SdfPathSet &mesh_paths)
{ {
pxr::UsdSkelSkeleton skel = pxr::UsdSkelSkeleton::Get(stage, skel_path); pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Get(stage, skel_path);
if (!skel) { if (!skel_api) {
CLOG_WARN(&LOG, "Couldn't get skeleton from path %s", skel_path.GetAsString().c_str()); CLOG_WARN(&LOG, "Couldn't get skeleton from path %s", skel_path.GetAsString().c_str());
return; return;
} }
/* Create the animation. */ /* Use existing animation if possible, otherwise create a new one. */
pxr::SdfPath anim_path = skel_path.AppendChild(usdtokens::Anim); pxr::UsdPrim anim_prim;
const pxr::UsdSkelAnimation anim = pxr::UsdSkelAnimation::Define(stage, anim_path); pxr::UsdSkelAnimation anim;
if (skel_api.GetAnimationSource(&anim_prim)) {
anim = pxr::UsdSkelAnimation(anim_prim);
}
else {
pxr::SdfPath anim_path = skel_path.AppendChild(usdtokens::Anim);
anim = pxr::UsdSkelAnimation::Define(stage, anim_path);
}
if (!anim) { if (!anim) {
CLOG_WARN(&LOG, "Couldn't define animation at path %s", anim_path.GetAsString().c_str()); CLOG_WARN(&LOG, "Couldn't get animation under skeleton %s", skel_path.GetAsString().c_str());
return; return;
} }

View File

@@ -27,6 +27,7 @@
#include "BKE_deform.hh" #include "BKE_deform.hh"
#include "BKE_fcurve.hh" #include "BKE_fcurve.hh"
#include "BKE_key.hh" #include "BKE_key.hh"
#include "BKE_lib_id.hh"
#include "BKE_modifier.hh" #include "BKE_modifier.hh"
#include "BKE_object_deform.h" #include "BKE_object_deform.h"
#include "BKE_report.hh" #include "BKE_report.hh"
@@ -143,6 +144,7 @@ void import_skeleton_curves(Main *bmain,
/* Create the action on the armature. */ /* Create the action on the armature. */
bAction *act = blender::animrig::id_action_ensure(bmain, &arm_obj->id); bAction *act = blender::animrig::id_action_ensure(bmain, &arm_obj->id);
BKE_id_rename(*bmain, act->id, anim_query.GetPrim().GetName().GetText());
/* Create the curves. */ /* Create the curves. */

View File

@@ -4,6 +4,9 @@
#include "usd_writer_armature.hh" #include "usd_writer_armature.hh"
#include "usd_armature_utils.hh" #include "usd_armature_utils.hh"
#include "usd_utils.hh"
#include "ANIM_action.hh"
#include "BKE_action.hh" #include "BKE_action.hh"
@@ -19,10 +22,6 @@
#include "CLG_log.h" #include "CLG_log.h"
static CLG_LogRef LOG = {"io.usd"}; static CLG_LogRef LOG = {"io.usd"};
namespace usdtokens {
static const pxr::TfToken Anim("Anim", pxr::TfToken::Immortal);
} // namespace usdtokens
/** /**
* Get the pose matrix for the given channel. * Get the pose matrix for the given channel.
* The matrix is computed relative to its parent, if a parent exists. * The matrix is computed relative to its parent, if a parent exists.
@@ -110,7 +109,7 @@ static void initialize(const Object *obj,
if (skel_anim) { if (skel_anim) {
usd_skel_api.CreateAnimationSourceRel().SetTargets( usd_skel_api.CreateAnimationSourceRel().SetTargets(
pxr::SdfPathVector({pxr::SdfPath(usdtokens::Anim)})); pxr::SdfPathVector({pxr::SdfPath(skel_anim.GetPath().GetName())}));
create_pose_joints(skel_anim, *obj, deform_bones, allow_unicode); create_pose_joints(skel_anim, *obj, deform_bones, allow_unicode);
} }
} }
@@ -169,9 +168,15 @@ void USDArmatureWriter::do_write(HierarchyContext &context)
pxr::UsdSkelAnimation skel_anim; pxr::UsdSkelAnimation skel_anim;
const bool allow_unicode = usd_export_context_.export_params.allow_unicode;
if (usd_export_context_.export_params.export_animation) { if (usd_export_context_.export_params.export_animation) {
/* Use the action name as the animation name. */
const animrig::Action *action = animrig::get_action(context.object->id);
const pxr::TfToken anim_name(make_safe_name(action->id.name + 2, allow_unicode));
/* Create the skeleton animation primitive as a child of the skeleton. */ /* Create the skeleton animation primitive as a child of the skeleton. */
pxr::SdfPath anim_path = usd_export_context_.usd_path.AppendChild(usdtokens::Anim); pxr::SdfPath anim_path = usd_export_context_.usd_path.AppendChild(anim_name);
skel_anim = pxr::UsdSkelAnimation::Define(stage, anim_path); skel_anim = pxr::UsdSkelAnimation::Define(stage, anim_path);
if (!skel_anim) { if (!skel_anim) {
@@ -180,7 +185,6 @@ void USDArmatureWriter::do_write(HierarchyContext &context)
} }
} }
const bool allow_unicode = usd_export_context_.export_params.allow_unicode;
Map<StringRef, const Bone *> *deform_map = usd_export_context_.export_params.only_deform_bones ? Map<StringRef, const Bone *> *deform_map = usd_export_context_.export_params.only_deform_bones ?
&deform_map_ : &deform_map_ :
nullptr; nullptr;

View File

@@ -753,6 +753,7 @@ class USDExportTest(AbstractUSDTest):
self.assertEqual(prim.GetTypeName(), "Skeleton") self.assertEqual(prim.GetTypeName(), "Skeleton")
prim_skel = UsdSkel.BindingAPI(prim) prim_skel = UsdSkel.BindingAPI(prim)
anim = UsdSkel.Animation(prim_skel.GetAnimationSource()) anim = UsdSkel.Animation(prim_skel.GetAnimationSource())
self.assertEqual(anim.GetPrim().GetName(), "ArmatureAction_001")
self.assertEqual(anim.GetJointsAttr().Get(), self.assertEqual(anim.GetJointsAttr().Get(),
['Bone', ['Bone',
'Bone/Bone_001', 'Bone/Bone_001',

View File

@@ -533,6 +533,7 @@ class USDImportTest(AbstractUSDTest):
ob_arm = bpy.data.objects["column_anim_armature"] ob_arm = bpy.data.objects["column_anim_armature"]
ob_arm2_side_a = bpy.data.objects["side_a"] ob_arm2_side_a = bpy.data.objects["side_a"]
ob_arm2_side_b = bpy.data.objects["side_b"] ob_arm2_side_b = bpy.data.objects["side_b"]
self.assertEqual(bpy.data.objects["Armature"].animation_data.action.name, "ArmatureAction_001")
bpy.context.scene.frame_set(1) bpy.context.scene.frame_set(1)
self.assertEqual(len(ob_xform.constraints), 1) self.assertEqual(len(ob_xform.constraints), 1)
@@ -678,7 +679,7 @@ class USDImportTest(AbstractUSDTest):
self.assertAlmostEqual(mesh_obj.vertex_groups['Elbow'].weight( self.assertAlmostEqual(mesh_obj.vertex_groups['Elbow'].weight(
8 + i), 1.0, 2, "Unexpected weight for Elbow deform vert") 8 + i), 1.0, 2, "Unexpected weight for Elbow deform vert")
action = bpy.data.actions['SkelAction'] action = bpy.data.actions['Anim1']
# Verify the Elbow joint rotation animation. # Verify the Elbow joint rotation animation.
curve_path = 'pose.bones["Elbow"].rotation_quaternion' curve_path = 'pose.bones["Elbow"].rotation_quaternion'