I want to offset an entire range of keyframes (all) in an individual animation fcurve using python. Is there an operator or function that will do this without needing to iterate through the keyframes individually - basically like performing a move command in the graph editor (G Y, 10)? More specifically, I would like to apply an object's Delta Transforms into its current animation in a python script.
2 Answers
Move All keyframe_points for a object
import bpy
def move_kp(obj, dx):
anim_data = obj.animation_data
if not anim_data: return
action = anim_data.action
if not action: return
for fc in action.fcurves:
for kp in fc.keyframe_points:
kp.co[0] += dx
kp.handle_left[0] += dx
kp.handle_right[0] += dx
move_kp(bpy.context.object, 10)
There have a api function to move keypoint
But only work on special cases
bpy.ops.transform.translate(value=(10, 0, 0), orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', constraint_axis=(True, True, True), mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)
-
$\begingroup$ Thanks for the method, which is basically iterating through individual keyframes. I would prefer to use the transform ALL method, but I didn't know how to apply it to the graph editor instead of the object. Maybe it is context sensitive like it is in the interface (which ever panel the mouse is over). I need to figure out how to change the context to the graph editor, then isolate only a specific channel on which to apply the translate method. I'm sure it can be done, I only have difficulty finding the proper commands in the API. $\endgroup$– zippyCommented May 1, 2022 at 21:58
In response to your comment to your question, here's an example, using an operator override, to move every fcurve 3 units on the X axis:
def get_override(area_type, region_type):
for area in bpy.context.screen.areas:
if area.type == area_type:
for region in area.regions:
if region.type == region_type:
override = {'area': area, 'region': region}
return override
raise RuntimeError("Wasn't able to find", region_type," in area ", area_type,
"\n Make sure it's open while executing script.")
override = get_override( 'GRAPH_EDITOR', 'WINDOW' )
bpy.ops.graph.select_all(override)
bpy.ops.transform.translate(override, value=(3, 0, 0))
What you need to do is replace the select_all
call with code that selects only the F-Curve you want to modify, as the transform op operates on all selected curves.
This will only work if you do have a graph editor window open.
Here is the manual entry with details on overriding context if you need more information.
3.2 Update
Context overrides are deprecated in Blender 3.2 and are scheduled to be removed in Blender 3.3 The replacement is temp_override
. The manual has examples of how to use the new function.
-
$\begingroup$ Thanks much. That looks like it would do what I want. The catch is keeping the Graph Editor panel open. $\endgroup$– zippyCommented May 2, 2022 at 0:27
-
$\begingroup$ If you want to use
bpy.ops
99% of the time you have to have an appropriate editor open, alas. $\endgroup$ Commented May 2, 2022 at 0:31