anim_utils.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software Foundation,
  15. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18. # <pep8 compliant>
  19. __all__ = (
  20. "bake_action",
  21. "bake_action_objects",
  22. "bake_action_iter",
  23. "bake_action_objects_iter",
  24. )
  25. import bpy
  26. def bake_action(
  27. obj,
  28. *,
  29. action, frames,
  30. **kwargs
  31. ):
  32. """
  33. :arg obj: Object to bake.
  34. :type obj: :class:`bpy.types.Object`
  35. :arg action: An action to bake the data into, or None for a new action
  36. to be created.
  37. :type action: :class:`bpy.types.Action` or None
  38. :arg frames: Frames to bake.
  39. :type frames: iterable of int
  40. :return: an action or None
  41. :rtype: :class:`bpy.types.Action`
  42. """
  43. if not (kwargs.get("do_pose") or kwargs.get("do_object")):
  44. return None
  45. action, = bake_action_objects(
  46. [(obj, action)],
  47. frames=frames,
  48. **kwargs,
  49. )
  50. return action
  51. def bake_action_objects(
  52. object_action_pairs,
  53. *,
  54. frames,
  55. **kwargs
  56. ):
  57. """
  58. A version of :func:`bake_action_objects_iter` that takes frames and returns the output.
  59. :arg frames: Frames to bake.
  60. :type frames: iterable of int
  61. :return: A sequence of Action or None types (aligned with `object_action_pairs`)
  62. :rtype: sequence of :class:`bpy.types.Action`
  63. """
  64. iter = bake_action_objects_iter(object_action_pairs, **kwargs)
  65. iter.send(None)
  66. for frame in frames:
  67. iter.send(frame)
  68. return iter.send(None)
  69. def bake_action_objects_iter(
  70. object_action_pairs,
  71. **kwargs
  72. ):
  73. """
  74. An coroutine that bakes actions for multiple objects.
  75. :arg object_action_pairs: Sequence of object action tuples,
  76. action is the destination for the baked data. When None a new action will be created.
  77. :type object_action_pairs: Sequence of (:class:`bpy.types.Object`, :class:`bpy.types.Action`)
  78. """
  79. scene = bpy.context.scene
  80. frame_back = scene.frame_current
  81. iter_all = tuple(
  82. bake_action_iter(obj, action=action, **kwargs)
  83. for (obj, action) in object_action_pairs
  84. )
  85. for iter in iter_all:
  86. iter.send(None)
  87. while True:
  88. frame = yield None
  89. if frame is None:
  90. break
  91. scene.frame_set(frame)
  92. bpy.context.view_layer.update()
  93. for iter in iter_all:
  94. iter.send(frame)
  95. scene.frame_set(frame_back)
  96. yield tuple(iter.send(None) for iter in iter_all)
  97. # XXX visual keying is actually always considered as True in this code...
  98. def bake_action_iter(
  99. obj,
  100. *,
  101. action,
  102. only_selected=False,
  103. do_pose=True,
  104. do_object=True,
  105. do_visual_keying=True,
  106. do_constraint_clear=False,
  107. do_parents_clear=False,
  108. do_clean=False
  109. ):
  110. """
  111. An coroutine that bakes action for a single object.
  112. :arg obj: Object to bake.
  113. :type obj: :class:`bpy.types.Object`
  114. :arg action: An action to bake the data into, or None for a new action
  115. to be created.
  116. :type action: :class:`bpy.types.Action` or None
  117. :arg only_selected: Only bake selected bones.
  118. :type only_selected: bool
  119. :arg do_pose: Bake pose channels.
  120. :type do_pose: bool
  121. :arg do_object: Bake objects.
  122. :type do_object: bool
  123. :arg do_visual_keying: Use the final transformations for baking ('visual keying')
  124. :type do_visual_keying: bool
  125. :arg do_constraint_clear: Remove constraints after baking.
  126. :type do_constraint_clear: bool
  127. :arg do_parents_clear: Unparent after baking objects.
  128. :type do_parents_clear: bool
  129. :arg do_clean: Remove redundant keyframes after baking.
  130. :type do_clean: bool
  131. :return: an action or None
  132. :rtype: :class:`bpy.types.Action`
  133. """
  134. # -------------------------------------------------------------------------
  135. # Helper Functions and vars
  136. # Note: BBONE_PROPS is a list so we can preserve the ordering
  137. BBONE_PROPS = [
  138. 'bbone_curveinx', 'bbone_curveoutx',
  139. 'bbone_curveiny', 'bbone_curveouty',
  140. 'bbone_rollin', 'bbone_rollout',
  141. 'bbone_scaleinx', 'bbone_scaleoutx',
  142. 'bbone_scaleiny', 'bbone_scaleouty',
  143. 'bbone_easein', 'bbone_easeout'
  144. ]
  145. def pose_frame_info(obj):
  146. matrix = {}
  147. bbones = {}
  148. for name, pbone in obj.pose.bones.items():
  149. if do_visual_keying:
  150. # Get the final transform of the bone in its own local space...
  151. matrix[name] = obj.convert_space(pose_bone=pbone, matrix=pbone.matrix,
  152. from_space='POSE', to_space='LOCAL')
  153. else:
  154. matrix[name] = pbone.matrix_basis.copy()
  155. # Bendy Bones
  156. if pbone.bone.bbone_segments > 1:
  157. bbones[name] = {bb_prop: getattr(pbone, bb_prop) for bb_prop in BBONE_PROPS}
  158. return matrix, bbones
  159. if do_parents_clear:
  160. if do_visual_keying:
  161. def obj_frame_info(obj):
  162. return obj.matrix_world.copy()
  163. else:
  164. def obj_frame_info(obj):
  165. parent = obj.parent
  166. matrix = obj.matrix_basis
  167. if parent:
  168. return parent.matrix_world @ matrix
  169. else:
  170. return matrix.copy()
  171. else:
  172. if do_visual_keying:
  173. def obj_frame_info(obj):
  174. parent = obj.parent
  175. matrix = obj.matrix_world
  176. if parent:
  177. return parent.matrix_world.inverted_safe() @ matrix
  178. else:
  179. return matrix.copy()
  180. else:
  181. def obj_frame_info(obj):
  182. return obj.matrix_basis.copy()
  183. # -------------------------------------------------------------------------
  184. # Setup the Context
  185. if obj.pose is None:
  186. do_pose = False
  187. if not (do_pose or do_object):
  188. raise Exception("Pose and object baking is disabled, no action needed")
  189. pose_info = []
  190. obj_info = []
  191. options = {'INSERTKEY_NEEDED'}
  192. # -------------------------------------------------------------------------
  193. # Collect transformations
  194. while True:
  195. # Caller is responsible for setting the frame and updating the scene.
  196. frame = yield None
  197. # Signal we're done!
  198. if frame is None:
  199. break
  200. if do_pose:
  201. pose_info.append((frame, *pose_frame_info(obj)))
  202. if do_object:
  203. obj_info.append((frame, obj_frame_info(obj)))
  204. # -------------------------------------------------------------------------
  205. # Clean (store initial data)
  206. if do_clean and action is not None:
  207. clean_orig_data = {fcu: {p.co[1] for p in fcu.keyframe_points} for fcu in action.fcurves}
  208. else:
  209. clean_orig_data = {}
  210. # -------------------------------------------------------------------------
  211. # Create action
  212. # in case animation data hasn't been created
  213. atd = obj.animation_data_create()
  214. if action is None:
  215. action = bpy.data.actions.new("Action")
  216. # Leave tweak mode before trying to modify the action (T48397)
  217. if atd.use_tweak_mode:
  218. atd.use_tweak_mode = False
  219. atd.action = action
  220. # -------------------------------------------------------------------------
  221. # Apply transformations to action
  222. # pose
  223. if do_pose:
  224. for name, pbone in obj.pose.bones.items():
  225. if only_selected and not pbone.bone.select:
  226. continue
  227. if do_constraint_clear:
  228. while pbone.constraints:
  229. pbone.constraints.remove(pbone.constraints[0])
  230. # create compatible eulers
  231. euler_prev = None
  232. for (f, matrix, bbones) in pose_info:
  233. pbone.matrix_basis = matrix[name].copy()
  234. pbone.keyframe_insert("location", index=-1, frame=f, group=name, options=options)
  235. rotation_mode = pbone.rotation_mode
  236. if rotation_mode == 'QUATERNION':
  237. pbone.keyframe_insert("rotation_quaternion", index=-1, frame=f, group=name, options=options)
  238. elif rotation_mode == 'AXIS_ANGLE':
  239. pbone.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name, options=options)
  240. else: # euler, XYZ, ZXY etc
  241. if euler_prev is not None:
  242. euler = pbone.rotation_euler.copy()
  243. euler.make_compatible(euler_prev)
  244. pbone.rotation_euler = euler
  245. euler_prev = euler
  246. del euler
  247. else:
  248. euler_prev = pbone.rotation_euler.copy()
  249. pbone.keyframe_insert("rotation_euler", index=-1, frame=f, group=name, options=options)
  250. pbone.keyframe_insert("scale", index=-1, frame=f, group=name, options=options)
  251. # Bendy Bones
  252. if pbone.bone.bbone_segments > 1:
  253. bbone_shape = bbones[name]
  254. for bb_prop in BBONE_PROPS:
  255. # update this property with value from bbone_shape, then key it
  256. setattr(pbone, bb_prop, bbone_shape[bb_prop])
  257. pbone.keyframe_insert(bb_prop, index=-1, frame=f, group=name, options=options)
  258. # object. TODO. multiple objects
  259. if do_object:
  260. if do_constraint_clear:
  261. while obj.constraints:
  262. obj.constraints.remove(obj.constraints[0])
  263. # create compatible eulers
  264. euler_prev = None
  265. for (f, matrix) in obj_info:
  266. name = "Action Bake" # XXX: placeholder
  267. obj.matrix_basis = matrix
  268. obj.keyframe_insert("location", index=-1, frame=f, group=name, options=options)
  269. rotation_mode = obj.rotation_mode
  270. if rotation_mode == 'QUATERNION':
  271. obj.keyframe_insert("rotation_quaternion", index=-1, frame=f, group=name, options=options)
  272. elif rotation_mode == 'AXIS_ANGLE':
  273. obj.keyframe_insert("rotation_axis_angle", index=-1, frame=f, group=name, options=options)
  274. else: # euler, XYZ, ZXY etc
  275. if euler_prev is not None:
  276. euler = obj.rotation_euler.copy()
  277. euler.make_compatible(euler_prev)
  278. obj.rotation_euler = euler
  279. euler_prev = euler
  280. del euler
  281. else:
  282. euler_prev = obj.rotation_euler.copy()
  283. obj.keyframe_insert("rotation_euler", index=-1, frame=f, group=name, options=options)
  284. obj.keyframe_insert("scale", index=-1, frame=f, group=name, options=options)
  285. if do_parents_clear:
  286. obj.parent = None
  287. # -------------------------------------------------------------------------
  288. # Clean
  289. if do_clean:
  290. for fcu in action.fcurves:
  291. fcu_orig_data = clean_orig_data.get(fcu, set())
  292. keyframe_points = fcu.keyframe_points
  293. i = 1
  294. while i < len(keyframe_points) - 1:
  295. val = keyframe_points[i].co[1]
  296. if val in fcu_orig_data:
  297. i += 1
  298. continue
  299. val_prev = keyframe_points[i - 1].co[1]
  300. val_next = keyframe_points[i + 1].co[1]
  301. if abs(val - val_prev) + abs(val - val_next) < 0.0001:
  302. keyframe_points.remove(keyframe_points[i])
  303. else:
  304. i += 1
  305. yield action