4
$\begingroup$

This is the script I've got. It just basically offsets every selected objects animation for the other one as shown in this Tutorial

import bpy
obj = bpy.context.selected_objects
objlist = len(obj)
offset = range(objlist+1)

for i in range(objlist):
    animData = obj[i].animation_data
    action = animData.action
    fcurves = action.fcurves
    for curve in fcurves:
        keyframePoints = curve.keyframe_points
        for keyframe in keyframePoints:
            keyframe.co[0] += offset[i]
            keyframe.handle_left[0] += offset[i]
            keyframe.handle_right[0] += offset[i]

It works alright but when I change it to:

import bpy

obj = bpy.context.selected_pose_bones
objlist = len(obj)
offset = range(objlist+1)

for i in range(objlist):
    animData = obj[i].animation_data
    action = animData.action
    fcurves = action.fcurves
    for curve in fcurves:
        keyframePoints = curve.keyframe_points
        for keyframe in keyframePoints:
            keyframe.co[0] += offset[i]
            keyframe.handle_left[0] += offset[i]
            keyframe.handle_right[0] += offset[i]

I get this error

AttributeError:'PoseBone' object has no attribute 'animation_data'

$\endgroup$

2 Answers 2

4
$\begingroup$

Armatures store data differently than other objects, they contain a rest position for each bone that locates the bone within the armature structure as well as pose position used for animation. The data for an action is stored within a generic objects data, to get the armature animation data you want, you need to treat the armature as an object to get there. The path to the fcurves of the armatures action is

bpy.context.active_object.animation_data.action.fcurves

The list of fcurves in the armatures action will contain every curve for every channel of every bone in the armature that is keyframed, each curve has a data_path with a value like pose.bones["hips"].location, by extracting the name you can compare it to the selected bone names with something like -

bone_names = [b.name for b in bpy.context.selected_pose_bones]
...
for curve in fcurves:
    if curve.data_path.split('"')[1] in bone_names:
        # do stuff
$\endgroup$
3
  • $\begingroup$ It worked in that its moving all the fcurves in the armarture Action. but hoped for was to move every bones fcurves individually +=1. for example moving pose.bones["Bone.004"].location fcurve +1 frame in the x direction $\endgroup$
    – alec farai
    Commented May 30, 2015 at 10:52
  • $\begingroup$ Once you get the fcurve, it's data is the same as what you are using, you just need to use object.animation_data not pose_bone.animation_data $\endgroup$
    – sambler
    Commented May 30, 2015 at 12:13
  • $\begingroup$ it finally worked though I defined fcurves = bpy.context.active_object.animation_data.action.fcurves then said keyframePoints = fcurves[i].keyframe_points and finally for keyframe in keyframePoints:___` keyframe.handle_left[0] += .01` Which moved the first chanel on the actions furve +1 in X direction Working Final Version here >> dropbox.com/s/73uzj5e7i1vpafw/move_bone_Fcurves.py?dl=0. thanks for the tip :) $\endgroup$
    – alec farai
    Commented May 30, 2015 at 15:01
5
$\begingroup$

Working final code for those curious :

import bpy

bone_names = [b.name for b in bpy.context.selected_pose_bones]
fcurves = bpy.context.active_object.animation_data.action.fcurves

for curve in fcurves:
    if curve.data_path.split('"')[1] in bone_names:
        #1
        keyframePoints = fcurves[4].keyframe_points#intiger being the index counting down the Actions Channel list e.g X location= [1] Y location = [2]
        for keyframe in keyframePoints:
            keyframe.co[0] += .04 # the float value is How far it has to go in the X location. 
            keyframe.handle_left[0] += .04
            keyframe.handle_right[0] += .04
$\endgroup$

You must log in to answer this question.

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