4
$\begingroup$

So I have one FBX that have it's own armature and one object. Let's call it T pose. I have second FBX that contains one armature with let's say walk animation.

I am trying to assign walk animation to object with t-pose with no success. What have I tried so far:

  • Adding just walk armature to object won't work. I mean I can add the armature, but walk armature's rest pose is different than t-pose's rest pose. If I just change armature, animation is awkward.

  • I wrote one simple Python script that copy rest pose of walk animation and paste it to rest pose of t-pose. That didn't helped.

  • tried Copying FBX animation to armature

Am I right that deformations in animations are just offsets from rest pose?

I see others had same problems like: Merge multiple fbx animations into single rig or Import fbx animation

Is there any solution for this? Any comment is appreciated.

$\endgroup$

1 Answer 1

2
$\begingroup$

The solution is rather simple.

You need to add Bone Constraint -> Copy Transforms to armature without animation. As Target add armature with animation, and as a Bone, bone with the same name. Rinse and repeat for all bones.

Here is the code that automates all:

  • Creates constraints and link bones with other armature
  • Iterate over all frames, apply transform, and insert keyframes for all bones
  • Delete constrains

Just fill source and target armature, and animation from and to. Moreover, you can just call add_constraints() function which will link armatures and bones.

import bpy

source = "Bip001"
target = "Bip001.001"
frame_from = 0
frame_to = 35

# add constrains and link them with target bones
def add_constraints():
    global source, target
    
    source_ob = bpy.data.objects[source]
    
    for bone in source_ob.pose.bones:
        sel_bone=source_ob.data.bones[bone.name]
        sel_bone.select=True
        bpy.context.object.data.bones.active=sel_bone

        trans_bone = bpy.context.object.pose.bones[bone.name]
        if trans_bone.constraints.find('Copy Transforms') == -1:
            if bpy.data.objects[target].pose.bones.get(bone.name) is not None:
                bpy.ops.pose.constraint_add(type='COPY_TRANSFORMS')
                trans_bone.constraints["Copy Transforms"].target = bpy.data.objects[target]
                trans_bone.constraints["Copy Transforms"].subtarget = bone.name

# delete previously created constrains     
def del_constraints( ):
    for bone in bpy.context.selected_pose_bones:
        copyLocConstraints = [ c for c in bone.constraints if c.type == 'COPY_TRANSFORMS' ]
        # Iterate over all the bone's copy location constraints and delete them all
        for c in copyLocConstraints:
            bone.constraints.remove( c ) # Remove constraint

def apply_animation():
    global source, target, frame_from, frame_to
    #set keying set to whole character
    #we have all bones selected
    scene = bpy.context.scene
    for frame in range(frame_from, frame_to ):
        scene.frame_current = frame
        scene.frame_set(scene.frame_current)
        # apply visual transfrom to pose Ctrl+A
        bpy.ops.pose.visual_transform_apply()
        # insert all keyframes -> press I
        bpy.ops.anim.keyframe_insert_menu(type='__ACTIVE__', confirm_success=True) 

def select_all_bones():
    global source, target
    ob = bpy.data.objects[source]
    for bone in ob.pose.bones:
        b=ob.data.bones[bone.name]
        b.select=True
        bpy.context.object.data.bones.active=b
      
ks = bpy.data.scenes["Scene"].keying_sets_all
ks.active = ks['Whole Character'] 

ob = bpy.data.objects[source]
# uncomment line below if you are using Blender version below 2.8 and comment out 2nd line
#bpy.context.scene.objects.active = ob 
bpy.context.view_layer.objects.active = ob
bpy.ops.object.mode_set(mode='POSE')  
#select_all_bones()
add_constraints()
apply_animation()
del_constraints()
$\endgroup$
5
  • 2
    $\begingroup$ Thank you for that plugin code Izzy. I just ran it on Blender 2.8.8lts and it works great, with one caveat. The source and target in the code are reversed, it seems. I had to enter my actual source as Target, and my actual target as Source in your code. Thanks again for filling in one of the multiple gaps that the Blender Foundation allows to remain in their software. $\endgroup$
    – nmc
    Nov 4, 2020 at 20:17
  • $\begingroup$ You are welcome @nmc. If I get some free time, I may create an addon from it. $\endgroup$
    – Izzy
    Nov 5, 2020 at 11:15
  • $\begingroup$ Thank you for the code, it works great in the GUI. However, it fails when called from the command line (headless mode). The problem is with the call to bpy.ops.anim.keyframe_insert_menu, which throws a "context is incorrect" error. I believe it's because the call refers to a menu, which is not available in a non-GUI context. Is there any other call that would accomplish the same thing? $\endgroup$
    – Rafael
    Jan 20, 2021 at 19:25
  • $\begingroup$ @Rafael Idk, maybe in that case you are in object mode. Did you try to switch to edit mode? $\endgroup$
    – Izzy
    Jan 20, 2021 at 20:23
  • 1
    $\begingroup$ @Izzy, I solved the problem by replacing your call to keyframe_insert_menu with a block that calls bone.keyframe_insert for each bone. $\endgroup$
    – Rafael
    Jan 20, 2021 at 20:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .