Animation: Add channel type options to the Bake Action operator #110903

Closed
Colin Basnett wants to merge 1 commits from cmbasnett/bdk-blender:anim-bake-components into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 98 additions and 48 deletions

View File

@ -124,7 +124,11 @@ def bake_action_iter(
do_visual_keying=True,
do_constraint_clear=False,
do_parents_clear=False,
do_clean=False
do_clean=False,
do_location=True,
do_rotation=True,
do_scale=True,
do_bbone=True
):
"""
An coroutine that bakes action for a single object.
@ -148,6 +152,14 @@ def bake_action_iter(
:type do_parents_clear: bool
:arg do_clean: Remove redundant keyframes after baking.
:type do_clean: bool
:arg do_location: Bake location channels.
:type do_location: bool
:arg do_rotation: Bake rotation channels.
:type do_rotation: bool
:arg do_scale: Bake scale channels.
:type do_scale: bool
:arg do_bbone: Bake b-bone channels.
:type do_bbone: bool
:return: an action or None
:rtype: :class:`bpy.types.Action`
@ -306,7 +318,16 @@ def bake_action_iter(
keyframes.add_paths(path_euler, 3)
keyframes.add_paths(path_scale, 3)
if pbone.bone.bbone_segments > 1:
if do_location:
keyframes.add_paths(path_location, 3)
if do_rotation:
keyframes.add_paths(path_quaternion, 4)
keyframes.add_paths(path_axis_angle, 4)
keyframes.add_paths(path_euler, 3)
if do_scale:
keyframes.add_paths(path_scale, 3)
Review

It looks like all of these keyframes.add_paths(...) in the conditionals are already run unconditionally on lines 314-319. Were those lines meant to be removed?

It looks like all of these `keyframes.add_paths(...)` in the conditionals are already run unconditionally on lines 314-319. Were those lines meant to be removed?
if do_bbone and pbone.bone.bbone_segments > 1:
for prop_name, path in zip(BBONE_PROPS, paths_bbprops):
keyframes.add_paths(path, BBONE_PROPS_LENGTHS[prop_name])
@ -315,32 +336,35 @@ def bake_action_iter(
for (f, matrix, bbones) in pose_info:
pbone.matrix_basis = matrix[name].copy()
keyframes.extend_co_values(path_location, 3, f, pbone.location)
if do_location:
keyframes.extend_co_values(path_location, 3, f, pbone.location)
if rotation_mode == 'QUATERNION':
if quat_prev is not None:
quat = pbone.rotation_quaternion.copy()
quat.make_compatible(quat_prev)
pbone.rotation_quaternion = quat
quat_prev = quat
del quat
else:
quat_prev = pbone.rotation_quaternion.copy()
keyframes.extend_co_values(path_quaternion, 4, f, pbone.rotation_quaternion)
elif rotation_mode == 'AXIS_ANGLE':
keyframes.extend_co_values(path_axis_angle, 4, f, pbone.rotation_axis_angle)
else: # euler, XYZ, ZXY etc
if euler_prev is not None:
euler = pbone.matrix_basis.to_euler(pbone.rotation_mode, euler_prev)
pbone.rotation_euler = euler
del euler
euler_prev = pbone.rotation_euler.copy()
keyframes.extend_co_values(path_euler, 3, f, pbone.rotation_euler)
if do_rotation:
if rotation_mode == 'QUATERNION':
if quat_prev is not None:
quat = pbone.rotation_quaternion.copy()
quat.make_compatible(quat_prev)
pbone.rotation_quaternion = quat
quat_prev = quat
del quat
else:
quat_prev = pbone.rotation_quaternion.copy()
keyframes.extend_co_values(path_quaternion, 4, f, pbone.rotation_quaternion)
elif rotation_mode == 'AXIS_ANGLE':
keyframes.extend_co_values(path_axis_angle, 4, f, pbone.rotation_axis_angle)
else: # euler, XYZ, ZXY etc
if euler_prev is not None:
euler = pbone.matrix_basis.to_euler(pbone.rotation_mode, euler_prev)
pbone.rotation_euler = euler
del euler
euler_prev = pbone.rotation_euler.copy()
keyframes.extend_co_values(path_euler, 3, f, pbone.rotation_euler)
keyframes.extend_co_values(path_scale, 3, f, pbone.scale)
if do_scale:
keyframes.extend_co_values(path_scale, 3, f, pbone.scale)
# Bendy Bones
if pbone.bone.bbone_segments > 1:
if do_bbone and pbone.bone.bbone_segments > 1:
bbone_shape = bbones[name]
for prop_index, prop_name in enumerate(BBONE_PROPS):
prop_len = BBONE_PROPS_LENGTHS[prop_name]
@ -375,11 +399,14 @@ def bake_action_iter(
path_scale = "scale"
keyframes = KeyframesCo()
keyframes.add_paths(path_location, 3)
keyframes.add_paths(path_quaternion, 4)
keyframes.add_paths(path_axis_angle, 4)
keyframes.add_paths(path_euler, 3)
keyframes.add_paths(path_scale, 3)
if do_location:
keyframes.add_paths(path_location, 3)
if do_rotation:
keyframes.add_paths(path_quaternion, 4)
keyframes.add_paths(path_axis_angle, 4)
keyframes.add_paths(path_euler, 3)
if do_scale:
keyframes.add_paths(path_scale, 3)
rotation_mode = obj.rotation_mode
total_new_keys = len(obj_info)
@ -387,28 +414,31 @@ def bake_action_iter(
name = "Action Bake" # XXX: placeholder
obj.matrix_basis = matrix
keyframes.extend_co_values(path_location, 3, f, obj.location)
if do_location:
keyframes.extend_co_values(path_location, 3, f, obj.location)
if rotation_mode == 'QUATERNION':
if quat_prev is not None:
quat = obj.rotation_quaternion.copy()
quat.make_compatible(quat_prev)
obj.rotation_quaternion = quat
quat_prev = quat
del quat
else:
quat_prev = obj.rotation_quaternion.copy()
keyframes.extend_co_values(path_quaternion, 4, f, obj.rotation_quaternion)
if do_rotation:
if rotation_mode == 'QUATERNION':
if quat_prev is not None:
quat = obj.rotation_quaternion.copy()
quat.make_compatible(quat_prev)
obj.rotation_quaternion = quat
quat_prev = quat
del quat
else:
quat_prev = obj.rotation_quaternion.copy()
keyframes.extend_co_values(path_quaternion, 4, f, obj.rotation_quaternion)
elif rotation_mode == 'AXIS_ANGLE':
keyframes.extend_co_values(path_axis_angle, 4, f, obj.rotation_axis_angle)
else: # euler, XYZ, ZXY etc
if euler_prev is not None:
obj.rotation_euler = matrix.to_euler(obj.rotation_mode, euler_prev)
euler_prev = obj.rotation_euler.copy()
keyframes.extend_co_values(path_euler, 3, f, obj.rotation_euler)
elif rotation_mode == 'AXIS_ANGLE':
keyframes.extend_co_values(path_axis_angle, 4, f, obj.rotation_axis_angle)
else: # euler, XYZ, ZXY etc
if euler_prev is not None:
obj.rotation_euler = matrix.to_euler(obj.rotation_mode, euler_prev)
euler_prev = obj.rotation_euler.copy()
keyframes.extend_co_values(path_euler, 3, f, obj.rotation_euler)
keyframes.extend_co_values(path_scale, 3, f, obj.scale)
if do_scale:
keyframes.extend_co_values(path_scale, 3, f, obj.scale)
if is_new_action:
keyframes.insert_keyframes_into_new_action(total_new_keys, action, name)

View File

@ -252,11 +252,27 @@ class NLA_OT_bake(Operator):
),
default={'POSE'},
)
channel_types: EnumProperty(
name="Channels",
description="Which channels to bake",
options={'ENUM_FLAG'},
items=(
('LOCATION', "Location", "Bake location channels"),
('ROTATION', "Rotation", "Bake rotation channels"),
('SCALE', "Scale", "Bake scale channels"),
('BBONE', "B-Bone", "Bake b-bone channels"),
),
default={'LOCATION', 'ROTATION', 'SCALE', 'BBONE'},
)
def execute(self, context):
from bpy_extras import anim_utils
do_pose = 'POSE' in self.bake_types
do_object = 'OBJECT' in self.bake_types
do_location = 'LOCATION' in self.channel_types
do_rotation = 'ROTATION' in self.channel_types
do_scale = 'SCALE' in self.channel_types
do_bbone = 'BBONE' in self.channel_types
if do_pose and self.only_selected:
pose_bones = context.selected_pose_bones or []
@ -283,6 +299,10 @@ class NLA_OT_bake(Operator):
do_constraint_clear=self.clear_constraints,
do_parents_clear=self.clear_parents,
do_clean=self.clean_curves,
do_location=do_location,
do_rotation=do_rotation,
do_scale=do_scale,
do_bbone=do_bbone,
)
if not any(actions):