Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py144
-rw-r--r--release/scripts/startup/bl_operators/anim.py27
2 files changed, 120 insertions, 51 deletions
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
index ee270c6e8c7..f2df1bc16b3 100644
--- a/release/scripts/modules/bpy_extras/anim_utils.py
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -20,17 +20,102 @@
__all__ = (
"bake_action",
- )
+ "bake_action_objects",
+
+ "bake_action_iter",
+ "bake_action_objects_iter",
+)
import bpy
-# XXX visual keying is actually always considered as True in this code...
def bake_action(
obj,
- frame_start,
- frame_end,
- frame_step=1,
+ *,
+ action, frames,
+ **kwargs,
+):
+ """
+ :arg obj: Object to bake.
+ :type obj: :class:`bpy.types.Object`
+ :arg action: An action to bake the data into, or None for a new action
+ to be created.
+ :type action: :class:`bpy.types.Action` or None
+ :arg frames: Frames to bake.
+ :type frames: iterable of int
+
+ :return: an action or None
+ :rtype: :class:`bpy.types.Action`
+ """
+ if not (do_pose or do_object):
+ return None
+
+ action, = bake_action_objects(
+ [(obj, action)],
+ frames,
+ **kwargs,
+ )
+ return action
+
+
+def bake_action_objects(
+ object_action_pairs,
+ *,
+ frames,
+ **kwargs,
+):
+ """
+ A version of :func:`bake_action_objects_iter` that takes frames and returns the output.
+
+ :arg frames: Frames to bake.
+ :type frames: iterable of int
+
+ :return: A sequence of Action or None types (aligned with `object_action_pairs`)
+ :rtype: sequence of :class:`bpy.types.Action`
+ """
+ iter = bake_action_objects_iter(object_action_pairs, **kwargs)
+ iter.send(None)
+ for frame in frames:
+ iter.send(frame)
+ return iter.send(None)
+
+
+def bake_action_objects_iter(
+ object_action_pairs,
+ **kwargs,
+):
+ """
+ An coroutine that bakes actions for multiple objects.
+
+ :arg object_action_pairs: Sequence of object action tuples,
+ action is the destination for the baked data. When None a new action will be created.
+ :type object_action_pairs: Sequence of (:class:`bpy.types.Object`, :class:`bpy.types.Action`)
+ """
+ scene = bpy.context.scene
+ frame_back = scene.frame_current
+ iter_all = tuple(
+ bake_action_iter(obj, action=action, **kwargs)
+ for (obj, action) in object_action_pairs
+ )
+ for iter in iter_all:
+ iter.send(None)
+ while True:
+ frame = yield None
+ if frame is None:
+ break
+ scene.frame_set(frame)
+ scene.update()
+ for iter in iter_all:
+ iter.send(frame)
+ scene.frame_set(frame_back)
+ yield tuple(iter.send(None) for iter in iter_all)
+
+
+# XXX visual keying is actually always considered as True in this code...
+def bake_action_iter(
+ obj,
+ *,
+ action,
only_selected=False,
do_pose=True,
do_object=True,
@@ -38,21 +123,15 @@ def bake_action(
do_constraint_clear=False,
do_parents_clear=False,
do_clean=False,
- action=None,
):
-
"""
- Return an image from the file path with options to search multiple paths
- and return a placeholder if its not found.
+ An coroutine that bakes action for a single object.
:arg obj: Object to bake.
:type obj: :class:`bpy.types.Object`
- :arg frame_start: First frame to bake.
- :type frame_start: int
- :arg frame_end: Last frame to bake.
- :type frame_end: int
- :arg frame_step: Frame step.
- :type frame_step: int
+ :arg action: An action to bake the data into, or None for a new action
+ to be created.
+ :type action: :class:`bpy.types.Action` or None
:arg only_selected: Only bake selected bones.
:type only_selected: bool
:arg do_pose: Bake pose channels.
@@ -67,14 +146,10 @@ def bake_action(
:type do_parents_clear: bool
:arg do_clean: Remove redundant keyframes after baking.
:type do_clean: bool
- :arg action: An action to bake the data into, or None for a new action
- to be created.
- :type action: :class:`bpy.types.Action` or None
:return: an action or None
:rtype: :class:`bpy.types.Action`
"""
-
# -------------------------------------------------------------------------
# Helper Functions and vars
@@ -116,33 +191,32 @@ def bake_action(
# -------------------------------------------------------------------------
# Setup the Context
- # TODO, pass data rather then grabbing from the context!
- scene = bpy.context.scene
- frame_back = scene.frame_current
-
if obj.pose is None:
do_pose = False
if not (do_pose or do_object):
- return None
+ raise Exception("Pose and object baking is disabled, no action needed")
pose_info = []
obj_info = []
options = {'INSERTKEY_NEEDED'}
- frame_range = range(frame_start, frame_end + 1, frame_step)
-
# -------------------------------------------------------------------------
# Collect transformations
- for f in frame_range:
- scene.frame_set(f)
- scene.update()
+ while True:
+ # Caller is responsible for setting the frame and updating the scene.
+ frame = yield None
+
+ # Signal we're done!
+ if frame is None:
+ break
+
if do_pose:
- pose_info.append(pose_frame_info(obj))
+ pose_info.append((frame, pose_frame_info(obj)))
if do_object:
- obj_info.append(obj_frame_info(obj))
+ obj_info.append((frame, obj_frame_info(obj)))
# -------------------------------------------------------------------------
# Clean (store initial data)
@@ -181,7 +255,7 @@ def bake_action(
# create compatible eulers
euler_prev = None
- for (f, matrix) in zip(frame_range, pose_info):
+ for (f, matrix) in pose_info:
pbone.matrix_basis = matrix[name].copy()
pbone.keyframe_insert("location", -1, f, name, options)
@@ -213,7 +287,7 @@ def bake_action(
# create compatible eulers
euler_prev = None
- for (f, matrix) in zip(frame_range, obj_info):
+ for (f, matrix) in obj_info:
name = "Action Bake" # XXX: placeholder
obj.matrix_basis = matrix
@@ -264,6 +338,4 @@ def bake_action(
else:
i += 1
- scene.frame_set(frame_back)
-
- return action
+ yield action
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index 380c1257a3d..0632f9bc3ca 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -198,7 +198,7 @@ class ANIM_OT_keying_set_export(Operator):
class BakeAction(Operator):
- """Bake object/pose loc/scale/rotation animation to a new action"""
+ """Bake all selected objects loc/scale/rotation animation to an action"""
bl_idname = "nla.bake"
bl_label = "Bake Action"
bl_options = {'REGISTER', 'UNDO'}
@@ -222,7 +222,7 @@ class BakeAction(Operator):
default=1,
)
only_selected = BoolProperty(
- name="Only Selected",
+ name="Only Selected Bones",
description="Only key selected bones (Pose baking only)",
default=True,
)
@@ -259,18 +259,16 @@ class BakeAction(Operator):
def execute(self, context):
from bpy_extras import anim_utils
+ objects = context.selected_editable_objects
+ object_action_pairs = (
+ [(obj, getattr(obj.animation_data, "action", None)) for obj in objects]
+ if self.use_current_action else
+ [(obj, None) for obj in objects]
+ )
- obj = context.object
- action = None
- if self.use_current_action:
- if obj.animation_data:
- action = obj.animation_data.action
-
- action = anim_utils.bake_action(
- obj,
- self.frame_start,
- self.frame_end,
- frame_step=self.step,
+ actions = anim_utils.bake_action_objects(
+ object_action_pairs,
+ frames=range(self.frame_start, self.frame_end + 1, self.step),
only_selected=self.only_selected,
do_pose='POSE' in self.bake_types,
do_object='OBJECT' in self.bake_types,
@@ -278,10 +276,9 @@ class BakeAction(Operator):
do_constraint_clear=self.clear_constraints,
do_parents_clear=self.clear_parents,
do_clean=True,
- action=action,
)
- if action is None:
+ if not any(actions):
self.report({'INFO'}, "Nothing to bake")
return {'CANCELLED'}