4
$\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$

2 Answers 2

5
$\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$
1
  • $\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$ Jul 30, 2017 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$

You must log in to answer this question.

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