animation pose and key insertion automation script

I’ve been writing a python script to automate a manual workaround for some animation import problem, and I could use a hand here to figure out what I’m doing wrong.

First the problem: when I import a model with animation from a COLLADA file, the transforms (scale, rotation, position) get repeated 5 times each for some reason. The animation works, but you cant insert any new keyframes into it, which defeates the purpose of importing it so that I can re-pose the model.

The workaround for this problem is to create a new action in the dopesheet editor, then use the imported action to pose the model at each keyframe, and then insert a new key into new action. However, this is a very laborious procedure which I am attempting to automate. Attempting to just copy the data doesnt work, because the junk data goes along with it.

So, I wrote a script sets the sets the imported action to be “active” in the dopesheet editor, advances the frame, updates the scene, makes the new action active in the dopesheet editor, then inserts a new keyframe (default insert, for all channels).

This procedure works manually, but when I attempt to do it in code, I get a new action which is populated with five keys which I assume are exactly the same as the first key, which leads me to believe that the model isnt being posed the way I think it is by the python API functions I’m calling.



#   Get the source and target actions
            sourceAction = bpy.data.actions[SOURCE_ACTION]   
            targetAction = bpy.data.actions[TARGET_ACTION]         
            
#   Set the context area to the dopesheet editor
            a = bpy.context.area
            a.type = "DOPESHEET_EDITOR"

#   Set the dopesheet editor to Action Editor mode        
            x = bpy.context.space_data         
            x.mode = "ACTION"
            
#   Set the active action in the dopesheet editor             
            x.action = sourceAction            
            bpy.ops.anim.change_frame(frame=0)
            x.action = targetAction
            
#   Go to the 3D window, pose mode, and insert a keyframe
            a.type = "VIEW_3D" 
            bpy.ops.object.mode_set(mode='POSE')    
            bpy.ops.pose.select_all(action='SELECT')
            bpy.ops.anim.keyframe_insert_menu(type='LocRotScale')
            
#   Now go back to the Dopesheet in ActionEditor mode, and get ready to
#   copy the posed animation     
            a.type = "DOPESHEET_EDITOR"
            
#   Now copy all the frames after zero
            numberOfFrames = int(sourceAction.frame_range[1] + 1)
            
            for f in range(1, numberOfFrames):
                x.action = sourceAction
                bpy.ops.anim.change_frame(frame=f)                                
                bpy.data.scenes['Scene'].update()
                x.action = targetAction                               
                bpy.ops.action.keyframe_insert()
                
#   return to the 3D view
            a.type = "VIEW_3D"

Some additional notes:

  • The code above is contained in an operator button which I click after initializing the variables “SOURCE_ACTION” and “TARGET_ACTION” to be valid strings referring to an action in bpy.data.actions list

  • Before running this code, I manually create the target action in the dopesheet editor, and delete all of the channels associated with each bone so that the action is completely empty; those are created fresh by the initial key insert above (“LocRotScale”), which appears to work properly.

Thanks much,

bw42

OK, I got it:

I needed to replace:

bpy.ops.anim.change_frame(frame=f)

with:

bpy.data.scenes[‘Scene’].frame_set(f)

The first must advance a frame counter but doesnt force a pose update until the script exits. The second one forces a pose update every time the frame is set.

bw42