When baking an action we can select which bones to bake, by choosing selected only option. But can you have more control over which types of channels to bake? For example if I would like to only bake translation and rotation channels of the bones, is this possible to achieve with or without scripting? Locking channels in the transform panel for each bone prevents those channels from being keyframed but they still get baked.
Asked
Active
Viewed 437 times
1 Answers
2
Script Solution
Can look at the datapath of an fcurve of an action. Here is the fcurves of default armature object of single pose bone with a LocRotScale action
>>> a = C.object.animation_data.action
>>> for fc in a.fcurves:
... fc.data_path
...
'pose.bones["Bone"].location'
'pose.bones["Bone"].location'
'pose.bones["Bone"].location'
'pose.bones["Bone"].rotation_quaternion'
'pose.bones["Bone"].rotation_quaternion'
'pose.bones["Bone"].rotation_quaternion'
'pose.bones["Bone"].rotation_quaternion'
'pose.bones["Bone"].scale'
'pose.bones["Bone"].scale'
'pose.bones["Bone"].scale'
A script to convert any fcurve of an action to samples (bake it) that has a datapath that ends with "location" or "rotation_quaternion"
import bpy
context = bpy.context
ob = context.object
action = ob.animation_data.action
to_bake = ("location",
"rotation_quaternion",
)
fcs = (fc for fc in action.fcurves
if any(fc.data_path.endswith(p) for p in to_bake))
for fc in fcs:
fc.convert_to_samples(*action.frame_range)
Further to this, can make a lookup dictionary of the fcurves, then use it based on selected pose bones
The first part of the datapath from a pose bone
>>> C.active_pose_bone.path_from_id()
'pose.bones["Bone"]'
Similar to above, but only baking the location and quat rot of selected pose bones.
import bpy
from collections import defaultdict
context = bpy.context
ob = context.object
action = ob.animation_data.action
to_bake = ("location",
"rotation_quaternion",
)
fcurves = defaultdict(list)
for fc in action.fcurves:
fcurves[fc.data_path].append(fc)
for pb in context.selected_pose_bones:
path = pb.path_from_id()
for sfx in to_bake:
fcs = fcurves[f"{path}.{sfx}"]
for fc in fcs:
print("Bake", fc.data_path, "xyzw"[fc.array_index])
fc.convert_to_samples(*action.frame_range)
batFINGER
- 84,216
- 10
- 108
- 233
bpy.ops.nla.bake()command to bake previously. Aside from it being restrictive, I don't like using these "context specific" commands in my script. Being able to bake each fcurve separately as needed and not having to rely on the correct context is really nice! – Mar 29 '20 at 19:04bpy.ops.nla.bake()if I want that. – Mar 29 '20 at 20:44