Fix #129385: Bake Action operator not working with slots

This fixes the issue by traversing the new data structure for actions.
* When a slot is assigned, the action is baked into the slot.
* if no slot is assigned, it creates a new slot and bakes into that. However since no slot was assigned, the animation will be static.

Pull Request: https://projects.blender.org/blender/blender/pulls/129525
This commit is contained in:
Christoph Lendenfeld
2024-10-29 16:39:10 +01:00
committed by Christoph Lendenfeld
parent 1d5a3ca129
commit 2fb0847dd1

View File

@@ -11,7 +11,7 @@ __all__ = (
)
import bpy
from bpy.types import Action
from bpy.types import Action, ActionSlot
from dataclasses import dataclass
from collections.abc import (
@@ -73,6 +73,26 @@ class BakeOptions:
"""Bake custom properties."""
def _get_channelbag_for_slot(action: Action, slot: ActionSlot):
# This is on purpose limited to the first layer and strip. To support more
# than 1 layer, a rewrite of this operator is needed which ideally would
# happen in C++.
for layer in action.layers:
for strip in layer.strips:
channelbag = strip.channels(slot.handle)
return channelbag
def _ensure_channelbag_exists(action: Action, slot: ActionSlot):
channelbag = _get_channelbag_for_slot(action, slot)
if channelbag:
return channelbag
for layer in action.layers:
for strip in layer.strips:
return strip.channelbags.new(slot)
def bake_action(
obj,
*,
@@ -357,6 +377,11 @@ def bake_action_iter(
is_new_action = action is None
if is_new_action:
action = bpy.data.actions.new("Action")
else:
# When baking into the current action, a slot needs to be assigned.
if not atd.action_slot:
slot = action.slots.new(for_id=obj)
atd.action_slot = slot
# Only leave tweak mode if we actually need to modify the action (#57159)
if action != atd.action:
@@ -377,7 +402,13 @@ def bake_action_iter(
# Apply transformations to action
# pose
lookup_fcurves = {(fcurve.data_path, fcurve.array_index): fcurve for fcurve in action.fcurves}
lookup_fcurves = {}
assert action.is_action_layered
channelbag = _get_channelbag_for_slot(action, atd.action_slot)
if channelbag:
# channelbag can be None if no layers or strips exist in the action.
lookup_fcurves = {(fcurve.data_path, fcurve.array_index): fcurve for fcurve in channelbag.fcurves}
if bake_options.do_pose:
for f, armature_custom_properties in armature_info:
bake_custom_properties(obj, custom_props=armature_custom_properties,
@@ -470,7 +501,8 @@ def bake_action_iter(
if is_new_action:
keyframes.insert_keyframes_into_new_action(total_new_keys, action, name)
else:
keyframes.insert_keyframes_into_existing_action(lookup_fcurves, total_new_keys, action, name)
keyframes.insert_keyframes_into_existing_action(
lookup_fcurves, total_new_keys, action, atd.action_slot)
# object. TODO. multiple objects
if bake_options.do_object:
@@ -536,7 +568,8 @@ def bake_action_iter(
if is_new_action:
keyframes.insert_keyframes_into_new_action(total_new_keys, action, name)
else:
keyframes.insert_keyframes_into_existing_action(lookup_fcurves, total_new_keys, action, name)
keyframes.insert_keyframes_into_existing_action(
lookup_fcurves, total_new_keys, action, atd.action_slot)
if bake_options.do_parents_clear:
obj.parent = None
@@ -652,7 +685,7 @@ class KeyframesCo:
lookup_fcurves: Mapping[FCurveKey, bpy.types.FCurve],
total_new_keys: int,
action: Action,
action_group_name: str,
action_slot: ActionSlot,
) -> None:
"""
Assumes the action already exists, that it might already have F-curves. Otherwise, the
@@ -675,9 +708,12 @@ class KeyframesCo:
fcurve = lookup_fcurves.get(fc_key, None)
if fcurve is None:
data_path, array_index = fc_key
fcurve = action.fcurves.new(
data_path, index=array_index, action_group=action_group_name
)
assert action.is_action_layered
channelbag = _ensure_channelbag_exists(action, action_slot)
if not channelbag:
# Can happen if no layers or strips exist on the action.
continue
fcurve = channelbag.fcurves.new(data_path, index=array_index)
keyframe_points = fcurve.keyframe_points