100 lines
3.7 KiB
Python
100 lines
3.7 KiB
Python
# 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)
|