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:
committed by
Christoph Lendenfeld
parent
1d5a3ca129
commit
2fb0847dd1
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user