3
$\begingroup$

Someone asked for the functionality to change multiple fcurves at once (f.e. Loc X, Loc Y, Loc Z).

Now I managed to get all selected Fcurves in an array but I can't find any way to change their values. There is the bpy.types.FCurve.evaluate() method which only reads the given value at a frame.

How could I change it(optionally at a specific frame)?

EDIT: Found a workaround and posted it as solution.

$\endgroup$
3
$\begingroup$

An fcurve is made up of splines connecting key frame points. FCurve.keyframe_points a set of points (x, y) analogous to (frame, value).

import bpy
context = bpy.context
# use action on active object

obj = context.object
action = obj.animation_data.action

# location fcurves
fcurves = [fc for fc in action.fcurves if fc.data_path == "location"]

# set value of all fcurves to value at frame
edit_frame = 1
edit_value = (10.0, 0.0, -1.0)

for fc in fcurves:
    axis = fc.array_index
    # remove keyframe points already at edit_frame
    [fc.keyframe_points.remove(p) for p in fc.keyframe_points
           if abs(p.co.x - edit_frame) < 0.0001]
    # insert a keyframe
    fc.keyframe_points.insert(edit_frame, edit_value[axis])

Note this wont work for baked fcurves, which have sampled points. The value of fcurve.evaluate(frame) will evaluate curve after applying any fcurve modifiers.

$\endgroup$
  • $\begingroup$ Thanks a lot for this! I thought about replacing the keyframe points too but it somehow seemed to be too much of an improvisation for me. I guess this will work fine though. $\endgroup$ – johnmcdon321 Jul 30 '17 at 15:27
1
$\begingroup$

Alright, I managed this little workaround that will change the property of the object associated with the selected FCurve and make a new keyframe for it.

Thanks to batFINGER, I'll also take a deeper look into this keyframe point method.

This would be my solution:

def fcurve_change(value,frames):
    ob = bpy.context.active_object
    sel_fcrvs = [fc for fc in ob.animation_data.action.fcurves if fc.select]

    for fc in sel_fcrvs:
        for fr in frames:
            ob.keyframe_delete(fc.data_path,fc.array_index,fr)
            getattr(bpy.context.active_object, fc.data_path)[fc.array_index] = value
            ob.keyframe_insert(fc.data_path,fc.array_index,fr)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.