Animation
WARNING: Never set the current keyframe as a variable, always use the frame_set function!
# This will work correctly:
bpy.context.scene.frame_set(10)
# NEVER NEVER NEVER do that, even though blender does it itself!!!
bpy.context.scene.frame_current = 10
This is necessary to update all animation data.
Simply setting the frame_current variable will not update the animation data during a script!!!
Keyframes
Example of how to create keyframes of base transformations:
import bpy
obj = bpy.context.active_object
for i in range(bpy.context.scene.frame_start, bpy.context.scene.frame_end, 10):
bpy.context.scene.frame_current = i
obj.keyframe_insert("location")
obj.keyframe_insert("rotation_euler")
obj.keyframe_insert("scale")
Example of how to bake rotation and position of constraints:
def set_key_frames(obj):
for i in range(bpy.context.scene.frame_start, bpy.context.scene.frame_end):
bpy.context.scene.frame_current = i
bpy.context.view_layer.update() # needed to evaluate constriants
obj.location = obj.matrix_world.translation
obj.keyframe_insert("location")
obj.rotation_euler = obj.matrix_world.to_euler()
obj.keyframe_insert("rotation_euler")
def deactivate_constraints(obj):
for const in obj.constraints
const.enabled = False
set_key_frames(bpy.context.active_object)
deactivate_constraints(bpy.context.active_object)
FCurves
FCurves are the curves in the animation panel. They are defined by keyframes and will be sampled to generate values per frame.
They are stored in Actions. Actions are stored in AnimData aswell (?) as in BlendData. (TBtested!)
Ref: FCurve ◻ Keyframe ◻ AnimData
Examples
Counting frames:
import bpy
obj = bpy.context.active_object
keys = dict() # where we collecting the keys
for f in obj.animation_data.action.fcurves:
print(f"Curve {f.data_path} - {f.group} - {len(f.keyframe_points)}")
for k in f.keyframe_points:
t = int(k.co[0])
if not t in keys:
keys[t]=1
else:
keys[t]+=1
print(f"Unique keys: {len(keys)}")
My script for collection eye positions:
fcurves_pos = sorted(
[f for f in obj.animation_data.action.fcurves if f.data_path=="location"],
key=lambda f: f.array_index
)
if len(fcurves_pos)==3:
keylist=list()
for kid in range(len(fcurves_pos[0].keyframe_points)):
kfid=int(fcurves_pos[0].keyframe_points[kid].co[0])
head_name=self.get_shapekey_name(context, kfid)
if head_name:
keydata={
"type": "position",
"name" : "None" if not head_name else head_name,
"key": kfid,
"x": fcurves_pos[0].keyframe_points[kid].co[1],
"y": fcurves_pos[1].keyframe_points[kid].co[1],
"z": fcurves_pos[2].keyframe_points[kid].co[1]
}
keylist.append(keydata)
with open(jsonpath, "w") as kfile:
json.dump(keylist, kfile, indent=2)