MetaBox/Scripts/Animation/epic_pose_wrangler/v2/extensions/bake_poses.py

100 lines
3.7 KiB
Python
Raw Permalink Normal View History

2025-01-14 03:06:35 +08:00
# Copyright Epic Games, Inc. All Rights Reserved.
import traceback
from functools import partial
from maya import cmds
from epic_pose_wrangler.log import LOG
from epic_pose_wrangler.v2.model import base_extension, pose_blender
class BakePosesToTimeline(base_extension.PoseWranglerExtension):
__category__ = "Core Extensions"
@property
def view(self):
if self._view is not None:
return self._view
from PySide2 import QtWidgets
self._view = QtWidgets.QPushButton("Bake Poses To Timeline")
self._view.clicked.connect(partial(self.execute, None))
return self._view
def execute(self, context=None, **kwargs):
if context is None:
context = self.api.get_context()
if context.current_solver is not None:
bake_poses_to_timeline(solver=context.current_solver, view=self._display_view)
def bake_poses_to_timeline(start_frame=0, anim_layer=None, solver=None, view=False):
"""
Bakes the poses to the timeline and sets the time range to the given animation.
:param start_frame :type int: start frame of he baked animation
:param anim_layer :type str: if given the animations will be baked on that layer or created if it doesn't exist
:param solver :type api.RBFNode: solver reference
:param view :type bool: is the view present
"""
# Grab all the transforms for the solver
transforms = solver.drivers()
transforms.extend(solver.driven_nodes(pose_blender.UEPoseBlenderNode.node_type))
bake_enabled = True
pose_list = []
# Set default anim layer if one isn't specified
if not anim_layer:
anim_layer = "BaseAnimation"
# If the layer doesnt exist, create it
if not cmds.animLayer(anim_layer, query=True, exists=True):
cmds.animLayer(anim_layer)
try:
cmds.autoKeyframe(e=1, st=0)
# If we are running with the view, provide a popup
if view:
from PySide2 import QtWidgets
msg = ("This will bake the poses to the timeline, change your time range, "
"and delete inputs on driving and driven transforms.\n"
"Do you want this to happen?")
ret = QtWidgets.QMessageBox.warning(
None, "WARNING: DESTRUCTIVE FUNCTION", msg,
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
QtWidgets.QMessageBox.Cancel
)
if ret == QtWidgets.QMessageBox.StandardButton.Ok:
bake_enabled = True
cmds.undoInfo(openChunk=True, undoName='Bake poses to timeline')
else:
bake_enabled = False
# If we are baking, do the bake
if bake_enabled:
i = start_frame
for pose_name in solver.poses():
# let's key it on the previous and next frames before we pose it
cmds.select(transforms)
cmds.animLayer(anim_layer, addSelectedObjects=True, e=True)
cmds.setKeyframe(transforms, t=[(i - 1), (i + 1)], animLayer=anim_layer)
# assume the pose
solver.go_to_pose(pose_name)
cmds.setKeyframe(transforms, t=[i], animLayer=anim_layer)
pose_list.append(pose_name)
# increment to next keyframe
i += 1
# set the range to the number of keyframes
cmds.playbackOptions(minTime=0, maxTime=i, animationStartTime=0, animationEndTime=i - 1)
cmds.dgdirty(a=1)
return pose_list
cmds.dgdirty(a=1)
except Exception as e:
LOG.error(traceback.format_exc())
finally:
cmds.undoInfo(closeChunk=True)