zeffii's answer is better than using bpy.ops, but if you want to get closer to the metal, it gets a little clumsy. Blender's action API is missing several convenience functions.
It boils down to these steps
- make sure the datablock has animation_data
- get the
animation_data.action or .action=bpy.data.actions.new(name)
- find the
action_data.fcurves[i] that matches the data_path and array_index, or create the fcurve
- make sure there are enough
fcurve.keyframe_points to load our data into
- assign the
fcurve.keyframe_points[j].co and possibly .interpolation, .handle_left, .handle_right, etc.
There are a couple of examples embedded in http://web.purplefrog.com/~thoth/blender/python-cookbook/movie-card-stack.html and http://web.purplefrog.com/~thoth/blender/python-cookbook/csv-to-fcurve.html which I will summarize here:
def make_or_get_fcurve(obj, data_path, index=-1):
"""
:param obj: the data block from which we'll get the fcurve
:param data_path:
:param index:
:return:
"""
# freshly created objects don't have animation_data yet.
if obj.animation_data is None:
obj.animation_data_create()
ad=obj.animation_data
if ad.action is None:
ad.action = bpy.data.actions.new(obj.name+"Action")
for fc in ad.action.fcurves:
if (fc.data_path != data_path):
continue
if index<0 or index==fc.array_index:
return fc
# the action didn't have the fcurve we needed, yet
return ad.action.fcurves.new(data_path, index)
and from the other example
def find_or_create_fcurve(action, data_path, array_index= -1):
for fc in action.fcurves:
if fc.data_path == data_path and ( array_index<0 or fc.array_index==array_index):
return fc
fc = action.fcurves.new(data_path, array_index)
return fc
def make_eyeball_look_at(armature, frame):
eyeball = get_eyeball()
cns = find_constraint_track_to(eyeball, armature, "card release")
data_path = 'constraints["%s"].influence' % cns.name
fc = find_or_create_fcurve(eyeball.animation_data.action, data_path)
i0 = len(fc.keyframe_points)
fc.keyframe_points.add(4)
kp0 = fc.keyframe_points[i0]
kp1 = fc.keyframe_points[i0 + 1]
kp2 = fc.keyframe_points[i0 + 2]
kp3 = fc.keyframe_points[i0 + 3]
kp0.handle_left = [frame - 7, 0]
kp0.co = [frame - 6, 0]
kp0.handle_right = [frame - 5, 0]
kp1.handle_left = [frame - 4, 1]
kp1.co = [frame - 3, 1]
kp1.handle_right = [frame - 2, 1]
kp2.handle_left = [frame + 2, 1]
kp2.co = [frame + 3, 1]
kp2.handle_right = [frame + 4, 1]
kp3.handle_left = [frame + 5, 0]
kp3.co = [frame + 6, 0]
kp3.handle_right = [frame + 7, 0]
def add_keyframe_points(fcurve, kps):
idx0 = len(fcurve.keyframe_points)
fcurve.keyframe_points.add(len(kps))
rval = []
for i in range(len(kps)):
kp = fcurve.keyframe_points[idx0 + i]
kp.co = kps[i]
rval.append(kp)
return rval