| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | # ##### BEGIN GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  | #  modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  | #  as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  | #  of the License, or (at your option) any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | #  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | #  GNU General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | #  along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  | #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # ##### END GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  | # <pep8 compliant> | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | __all__ = ( | 
					
						
							|  |  |  |     "bake_action", | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |     "bake_action_objects", | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     "bake_action_iter", | 
					
						
							|  |  |  |     "bake_action_objects_iter", | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import bpy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 14:30:03 +10:00
										 |  |  | def bake_action( | 
					
						
							|  |  |  |         obj, | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |         *, | 
					
						
							|  |  |  |         action, frames, | 
					
						
							| 
									
										
										
										
											2017-09-14 17:03:40 +10:00
										 |  |  |         **kwargs | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  | ): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     :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, | 
					
						
							| 
									
										
										
										
											2017-09-14 17:03:40 +10:00
										 |  |  |         **kwargs | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  | ): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     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, | 
					
						
							| 
									
										
										
										
											2017-09-14 17:03:40 +10:00
										 |  |  |         **kwargs | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  | ): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     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, | 
					
						
							| 
									
										
										
										
											2017-09-10 14:30:03 +10:00
										 |  |  |         only_selected=False, | 
					
						
							|  |  |  |         do_pose=True, | 
					
						
							|  |  |  |         do_object=True, | 
					
						
							|  |  |  |         do_visual_keying=True, | 
					
						
							|  |  |  |         do_constraint_clear=False, | 
					
						
							|  |  |  |         do_parents_clear=False, | 
					
						
							| 
									
										
										
										
											2017-09-14 17:03:40 +10:00
										 |  |  |         do_clean=False | 
					
						
							| 
									
										
										
										
											2017-09-10 14:30:03 +10:00
										 |  |  | ): | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |     An coroutine that bakes action for a single object. | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 14:30:03 +10:00
										 |  |  |     :arg obj: Object to bake. | 
					
						
							|  |  |  |     :type obj: :class:`bpy.types.Object` | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |     :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 | 
					
						
							| 
									
										
										
										
											2016-09-16 11:49:42 +02:00
										 |  |  |     :arg only_selected: Only bake selected bones. | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     :type only_selected: bool | 
					
						
							|  |  |  |     :arg do_pose: Bake pose channels. | 
					
						
							|  |  |  |     :type do_pose: bool | 
					
						
							|  |  |  |     :arg do_object: Bake objects. | 
					
						
							|  |  |  |     :type do_object: bool | 
					
						
							| 
									
										
										
										
											2013-07-04 23:52:02 +00:00
										 |  |  |     :arg do_visual_keying: Use the final transformations for baking ('visual keying') | 
					
						
							|  |  |  |     :type do_visual_keying: bool | 
					
						
							|  |  |  |     :arg do_constraint_clear: Remove constraints after baking. | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     :type do_constraint_clear: bool | 
					
						
							| 
									
										
										
										
											2013-04-11 08:42:25 +00:00
										 |  |  |     :arg do_parents_clear: Unparent after baking objects. | 
					
						
							|  |  |  |     :type do_parents_clear: bool | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     :arg do_clean: Remove redundant keyframes after baking. | 
					
						
							|  |  |  |     :type do_clean: bool | 
					
						
							| 
									
										
										
										
											2011-09-26 15:39:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     :return: an action or None | 
					
						
							|  |  |  |     :rtype: :class:`bpy.types.Action` | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # ------------------------------------------------------------------------- | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |     # Helper Functions and vars | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 07:16:59 +11:00
										 |  |  |     def pose_frame_info(obj): | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |         matrix = {} | 
					
						
							|  |  |  |         for name, pbone in obj.pose.bones.items(): | 
					
						
							|  |  |  |             if do_visual_keying: | 
					
						
							|  |  |  |                 # Get the final transform of the bone in its own local space... | 
					
						
							|  |  |  |                 matrix[name] = obj.convert_space(pbone, pbone.matrix, 'POSE', 'LOCAL') | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 matrix[name] = pbone.matrix_basis.copy() | 
					
						
							|  |  |  |         return matrix | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 08:42:25 +00:00
										 |  |  |     if do_parents_clear: | 
					
						
							| 
									
										
										
										
											2015-02-17 07:16:59 +11:00
										 |  |  |         if do_visual_keying: | 
					
						
							|  |  |  |             def obj_frame_info(obj): | 
					
						
							|  |  |  |                 return obj.matrix_world.copy() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             def obj_frame_info(obj): | 
					
						
							|  |  |  |                 parent = obj.parent | 
					
						
							|  |  |  |                 matrix = obj.matrix_basis | 
					
						
							|  |  |  |                 if parent: | 
					
						
							|  |  |  |                     return parent.matrix_world * matrix | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     return matrix.copy() | 
					
						
							| 
									
										
										
										
											2015-02-03 15:41:34 +01:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2015-02-17 07:16:59 +11:00
										 |  |  |         if do_visual_keying: | 
					
						
							|  |  |  |             def obj_frame_info(obj): | 
					
						
							|  |  |  |                 parent = obj.parent | 
					
						
							|  |  |  |                 matrix = obj.matrix_world | 
					
						
							|  |  |  |                 if parent: | 
					
						
							|  |  |  |                     return parent.matrix_world.inverted_safe() * matrix | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     return matrix.copy() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             def obj_frame_info(obj): | 
					
						
							|  |  |  |                 return obj.matrix_basis.copy() | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # ------------------------------------------------------------------------- | 
					
						
							|  |  |  |     # Setup the Context | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |     if obj.pose is None: | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |         do_pose = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |     if not (do_pose or do_object): | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |         raise Exception("Pose and object baking is disabled, no action needed") | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     pose_info = [] | 
					
						
							|  |  |  |     obj_info = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |     options = {'INSERTKEY_NEEDED'} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     # ------------------------------------------------------------------------- | 
					
						
							|  |  |  |     # Collect transformations | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |     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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |         if do_pose: | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |             pose_info.append((frame, pose_frame_info(obj))) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |         if do_object: | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |             obj_info.append((frame, obj_frame_info(obj))) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-08 03:59:03 +10:00
										 |  |  |     # ------------------------------------------------------------------------- | 
					
						
							|  |  |  |     # Clean (store initial data) | 
					
						
							|  |  |  |     if do_clean and action is not None: | 
					
						
							|  |  |  |         clean_orig_data = {fcu: {p.co[1] for p in fcu.keyframe_points} for fcu in action.fcurves} | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         clean_orig_data = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     # ------------------------------------------------------------------------- | 
					
						
							|  |  |  |     # Create action | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 04:37:37 +00:00
										 |  |  |     # in case animation data hasn't been created | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     atd = obj.animation_data_create() | 
					
						
							|  |  |  |     if action is None: | 
					
						
							|  |  |  |         action = bpy.data.actions.new("Action") | 
					
						
							| 
									
										
										
										
											2016-07-24 03:18:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Leave tweak mode before trying to modify the action (T48397) | 
					
						
							|  |  |  |     if atd.use_tweak_mode: | 
					
						
							|  |  |  |         atd.use_tweak_mode = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     atd.action = action | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # ------------------------------------------------------------------------- | 
					
						
							|  |  |  |     # Apply transformations to action | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # pose | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |     if do_pose: | 
					
						
							|  |  |  |         for name, pbone in obj.pose.bones.items(): | 
					
						
							|  |  |  |             if only_selected and not pbone.bone.select: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if do_constraint_clear: | 
					
						
							|  |  |  |                 while pbone.constraints: | 
					
						
							|  |  |  |                     pbone.constraints.remove(pbone.constraints[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # create compatible eulers | 
					
						
							|  |  |  |             euler_prev = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |             for (f, matrix) in pose_info: | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |                 pbone.matrix_basis = matrix[name].copy() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 pbone.keyframe_insert("location", -1, f, name, options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 rotation_mode = pbone.rotation_mode | 
					
						
							|  |  |  |                 if rotation_mode == 'QUATERNION': | 
					
						
							|  |  |  |                     pbone.keyframe_insert("rotation_quaternion", -1, f, name, options) | 
					
						
							|  |  |  |                 elif rotation_mode == 'AXIS_ANGLE': | 
					
						
							|  |  |  |                     pbone.keyframe_insert("rotation_axis_angle", -1, f, name, options) | 
					
						
							|  |  |  |                 else:  # euler, XYZ, ZXY etc | 
					
						
							|  |  |  |                     if euler_prev is not None: | 
					
						
							|  |  |  |                         euler = pbone.rotation_euler.copy() | 
					
						
							|  |  |  |                         euler.make_compatible(euler_prev) | 
					
						
							|  |  |  |                         pbone.rotation_euler = euler | 
					
						
							|  |  |  |                         euler_prev = euler | 
					
						
							|  |  |  |                         del euler | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         euler_prev = pbone.rotation_euler.copy() | 
					
						
							|  |  |  |                     pbone.keyframe_insert("rotation_euler", -1, f, name, options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 pbone.keyframe_insert("scale", -1, f, name, options) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # object. TODO. multiple objects | 
					
						
							|  |  |  |     if do_object: | 
					
						
							|  |  |  |         if do_constraint_clear: | 
					
						
							|  |  |  |             while obj.constraints: | 
					
						
							|  |  |  |                 obj.constraints.remove(obj.constraints[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-25 12:37:15 +00:00
										 |  |  |         # create compatible eulers | 
					
						
							|  |  |  |         euler_prev = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |         for (f, matrix) in obj_info: | 
					
						
							| 
									
										
										
										
											2013-03-28 19:33:14 +00:00
										 |  |  |             name = "Action Bake"  # XXX: placeholder | 
					
						
							| 
									
										
										
										
											2013-01-21 02:40:51 +00:00
										 |  |  |             obj.matrix_basis = matrix | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-21 02:40:51 +00:00
										 |  |  |             obj.keyframe_insert("location", -1, f, name, options) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             rotation_mode = obj.rotation_mode | 
					
						
							|  |  |  |             if rotation_mode == 'QUATERNION': | 
					
						
							| 
									
										
										
										
											2013-01-21 02:40:51 +00:00
										 |  |  |                 obj.keyframe_insert("rotation_quaternion", -1, f, name, options) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |             elif rotation_mode == 'AXIS_ANGLE': | 
					
						
							| 
									
										
										
										
											2013-01-21 02:40:51 +00:00
										 |  |  |                 obj.keyframe_insert("rotation_axis_angle", -1, f, name, options) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |             else:  # euler, XYZ, ZXY etc | 
					
						
							| 
									
										
										
										
											2012-08-25 12:37:15 +00:00
										 |  |  |                 if euler_prev is not None: | 
					
						
							|  |  |  |                     euler = obj.rotation_euler.copy() | 
					
						
							|  |  |  |                     euler.make_compatible(euler_prev) | 
					
						
							|  |  |  |                     obj.rotation_euler = euler | 
					
						
							|  |  |  |                     euler_prev = euler | 
					
						
							|  |  |  |                     del euler | 
					
						
							| 
									
										
										
										
											2012-12-28 13:34:19 +00:00
										 |  |  |                 else: | 
					
						
							| 
									
										
										
										
											2012-08-25 12:37:15 +00:00
										 |  |  |                     euler_prev = obj.rotation_euler.copy() | 
					
						
							| 
									
										
										
										
											2013-01-21 02:40:51 +00:00
										 |  |  |                 obj.keyframe_insert("rotation_euler", -1, f, name, options) | 
					
						
							| 
									
										
										
										
											2012-08-25 12:37:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-21 02:40:51 +00:00
										 |  |  |             obj.keyframe_insert("scale", -1, f, name, options) | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 08:42:25 +00:00
										 |  |  |         if do_parents_clear: | 
					
						
							|  |  |  |             obj.parent = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |     # ------------------------------------------------------------------------- | 
					
						
							|  |  |  |     # Clean | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if do_clean: | 
					
						
							|  |  |  |         for fcu in action.fcurves: | 
					
						
							| 
									
										
										
										
											2015-09-08 03:59:03 +10:00
										 |  |  |             fcu_orig_data = clean_orig_data.get(fcu, set()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |             keyframe_points = fcu.keyframe_points | 
					
						
							|  |  |  |             i = 1 | 
					
						
							| 
									
										
										
										
											2015-09-08 03:59:03 +10:00
										 |  |  |             while i < len(keyframe_points) - 1: | 
					
						
							|  |  |  |                 val = keyframe_points[i].co[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if val in fcu_orig_data: | 
					
						
							|  |  |  |                     i += 1 | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-22 22:51:54 +00:00
										 |  |  |                 val_prev = keyframe_points[i - 1].co[1] | 
					
						
							|  |  |  |                 val_next = keyframe_points[i + 1].co[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if abs(val - val_prev) + abs(val - val_next) < 0.0001: | 
					
						
							|  |  |  |                     keyframe_points.remove(keyframe_points[i]) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     i += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 16:58:04 +10:00
										 |  |  |     yield action |