Update
This commit is contained in:
425
2023/scripts/animation_tools/studiolibrary/mutils/cmds.py
Normal file
425
2023/scripts/animation_tools/studiolibrary/mutils/cmds.py
Normal file
@@ -0,0 +1,425 @@
|
||||
# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
|
||||
#
|
||||
# This library is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version. This library 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 Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import platform
|
||||
import traceback
|
||||
|
||||
from studiovendor.Qt import QtCore
|
||||
from studiovendor.Qt import QtWidgets
|
||||
|
||||
try:
|
||||
import maya.mel
|
||||
import maya.cmds
|
||||
except ImportError:
|
||||
traceback.print_exc()
|
||||
|
||||
import mutils
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MayaUtilsError(Exception):
|
||||
"""Base class for exceptions in this module."""
|
||||
|
||||
|
||||
class ObjectsError(MayaUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
class SelectionError(MayaUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
class NoMatchFoundError(MayaUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
class NoObjectFoundError(MayaUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
class MoreThanOneObjectFoundError(MayaUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
class ModelPanelNotInFocusError(MayaUtilsError):
|
||||
pass
|
||||
|
||||
|
||||
def system():
|
||||
"""
|
||||
Return the current platform in lowercase.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return platform.system().lower()
|
||||
|
||||
|
||||
def isMac():
|
||||
"""
|
||||
Return True if the current OS is Mac.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return system().startswith("os") or \
|
||||
system().startswith("mac") or \
|
||||
system().startswith("darwin")
|
||||
|
||||
|
||||
def isLinux():
|
||||
"""
|
||||
Return True if the current OS is linux.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return system().lower().startswith("lin")
|
||||
|
||||
|
||||
def isWindows():
|
||||
"""
|
||||
Return True if the current OS is windows.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return system().lower().startswith("win")
|
||||
|
||||
|
||||
def isMaya():
|
||||
"""
|
||||
Return True if the current python session is in Maya.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
try:
|
||||
import maya.cmds
|
||||
maya.cmds.about(batch=True)
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
def selectionModifiers():
|
||||
"""
|
||||
Return a dictionary of the current key modifiers
|
||||
|
||||
:rtype: dict
|
||||
"""
|
||||
result = {"add": False, "deselect": False}
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
|
||||
if modifiers == QtCore.Qt.ShiftModifier:
|
||||
result["deselect"] = True
|
||||
elif modifiers == QtCore.Qt.ControlModifier:
|
||||
result["add"] = True
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def ls(*args, **kwargs):
|
||||
"""
|
||||
List all the node objects for the given options.
|
||||
|
||||
:type args: list
|
||||
:type kwargs: dict
|
||||
"""
|
||||
return [mutils.Node(name) for name in maya.cmds.ls(*args, **kwargs) or []]
|
||||
|
||||
|
||||
def listAttr(name, **kwargs):
|
||||
"""
|
||||
List all the attributes for the given object name.
|
||||
|
||||
:type name: str
|
||||
:type kwargs: str
|
||||
:rtype: list[mutils.Attribute]
|
||||
"""
|
||||
attrs = maya.cmds.listAttr(name, **kwargs) or []
|
||||
attrs = list(set(attrs))
|
||||
return [mutils.Attribute(name, attr) for attr in attrs]
|
||||
|
||||
|
||||
def disconnectAll(name):
|
||||
"""
|
||||
Disconnect all connections from the given object name.
|
||||
|
||||
:type name: str
|
||||
"""
|
||||
plugins = maya.cmds.listConnections(name, plugs=True, source=False) or []
|
||||
|
||||
for plug in plugins:
|
||||
source, = maya.cmds.listConnections(plug, plugs=True)
|
||||
maya.cmds.disconnectAttr(source, plug)
|
||||
|
||||
|
||||
def animCurve(fullname):
|
||||
"""
|
||||
Return the animation curve name for the give attribute.
|
||||
|
||||
:type fullname: str or None
|
||||
:rtype: str or None
|
||||
"""
|
||||
attribute = mutils.Attribute(fullname)
|
||||
return attribute.animCurve()
|
||||
|
||||
|
||||
def deleteUnknownNodes():
|
||||
"""Delete all unknown nodes in the Maya scene."""
|
||||
nodes = maya.cmds.ls(type="unknown")
|
||||
if nodes:
|
||||
for node in nodes:
|
||||
if maya.cmds.objExists(node) and \
|
||||
maya.cmds.referenceQuery(node, inr=True):
|
||||
maya.cmds.delete(node)
|
||||
|
||||
|
||||
def currentModelPanel():
|
||||
"""
|
||||
Get the current model panel name.
|
||||
|
||||
:rtype: str or None
|
||||
"""
|
||||
currentPanel = maya.cmds.getPanel(withFocus=True)
|
||||
currentPanelType = maya.cmds.getPanel(typeOf=currentPanel)
|
||||
|
||||
if currentPanelType not in ['modelPanel']:
|
||||
return None
|
||||
|
||||
return currentPanel
|
||||
|
||||
|
||||
def getBakeAttrs(objects):
|
||||
"""
|
||||
Get the attributes that are not connected to an animation curve.
|
||||
|
||||
:type objects: list[str]
|
||||
:rtype: list[str]
|
||||
"""
|
||||
result = []
|
||||
|
||||
if not objects:
|
||||
raise Exception("No objects specified")
|
||||
|
||||
connections = maya.cmds.listConnections(
|
||||
objects,
|
||||
plugs=True,
|
||||
source=True,
|
||||
connections=True,
|
||||
destination=False
|
||||
) or []
|
||||
|
||||
for i in range(0, len(connections), 2):
|
||||
dstObj = connections[i]
|
||||
srcObj = connections[i + 1]
|
||||
|
||||
nodeType = maya.cmds.nodeType(srcObj)
|
||||
|
||||
if "animCurve" not in nodeType:
|
||||
result.append(dstObj)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def bakeConnected(objects, time, sampleBy=1):
|
||||
"""
|
||||
Bake the given objects.
|
||||
|
||||
:type objects: list[str]
|
||||
:type time: (int, int)
|
||||
:type sampleBy: int
|
||||
"""
|
||||
bakeAttrs = getBakeAttrs(objects)
|
||||
|
||||
if bakeAttrs:
|
||||
maya.cmds.bakeResults(
|
||||
bakeAttrs,
|
||||
time=time,
|
||||
shape=False,
|
||||
simulation=True,
|
||||
sampleBy=sampleBy,
|
||||
controlPoints=False,
|
||||
minimizeRotation=True,
|
||||
bakeOnOverrideLayer=False,
|
||||
preserveOutsideKeys=False,
|
||||
sparseAnimCurveBake=False,
|
||||
disableImplicitControl=True,
|
||||
removeBakedAttributeFromLayer=False,
|
||||
)
|
||||
else:
|
||||
logger.error("Cannot find any connection to bake!")
|
||||
|
||||
|
||||
def getSelectedObjects():
|
||||
"""
|
||||
Get a list of the selected objects in Maya.
|
||||
|
||||
:rtype: list[str]
|
||||
:raises: mutils.SelectionError:
|
||||
"""
|
||||
selection = maya.cmds.ls(selection=True)
|
||||
if not selection:
|
||||
raise mutils.SelectionError("No objects selected!")
|
||||
return selection
|
||||
|
||||
|
||||
def getSelectedAttrs():
|
||||
"""
|
||||
Get the attributes that are selected in the channel box.
|
||||
|
||||
:rtype: list[str]
|
||||
"""
|
||||
attributes = maya.cmds.channelBox(
|
||||
"mainChannelBox",
|
||||
query=True,
|
||||
selectedMainAttributes=True
|
||||
)
|
||||
|
||||
if attributes is not None:
|
||||
attributes = str(attributes)
|
||||
attributes = attributes.replace("tx", "translateX")
|
||||
attributes = attributes.replace("ty", "translateY")
|
||||
attributes = attributes.replace("tz", "translateZ")
|
||||
attributes = attributes.replace("rx", "rotateX")
|
||||
attributes = attributes.replace("ry", "rotateY")
|
||||
attributes = attributes.replace("rz", "rotateZ")
|
||||
attributes = eval(attributes)
|
||||
|
||||
return attributes
|
||||
|
||||
|
||||
def currentFrameRange():
|
||||
"""
|
||||
Get the current first and last frame depending on the context.
|
||||
|
||||
:rtype: (int, int)
|
||||
"""
|
||||
start, end = selectedFrameRange()
|
||||
|
||||
if end == start:
|
||||
start, end = selectedObjectsFrameRange()
|
||||
|
||||
if start == end:
|
||||
start, end = playbackFrameRange()
|
||||
|
||||
return start, end
|
||||
|
||||
|
||||
def playbackFrameRange():
|
||||
"""
|
||||
Get the first and last frame from the play back options.
|
||||
|
||||
:rtype: (int, int)
|
||||
"""
|
||||
start = maya.cmds.playbackOptions(query=True, min=True)
|
||||
end = maya.cmds.playbackOptions(query=True, max=True)
|
||||
return start, end
|
||||
|
||||
|
||||
def selectedFrameRange():
|
||||
"""
|
||||
Get the first and last frame from the play back slider.
|
||||
|
||||
:rtype: (int, int)
|
||||
"""
|
||||
result = maya.mel.eval("timeControl -q -range $gPlayBackSlider")
|
||||
start, end = result.replace('"', "").split(":")
|
||||
start, end = int(start), int(end)
|
||||
if end - start == 1:
|
||||
end = start
|
||||
return start, end
|
||||
|
||||
|
||||
def selectedObjectsFrameRange(objects=None):
|
||||
"""
|
||||
Get the first and last animation frame from the given objects.
|
||||
|
||||
:type objects: list[str]
|
||||
:rtype: (int, int)
|
||||
"""
|
||||
start = 0
|
||||
end = 0
|
||||
|
||||
if not objects:
|
||||
objects = maya.cmds.ls(selection=True) or []
|
||||
|
||||
if objects:
|
||||
start = int(maya.cmds.findKeyframe(objects, which='first'))
|
||||
end = int(maya.cmds.findKeyframe(objects, which='last'))
|
||||
|
||||
return start, end
|
||||
|
||||
|
||||
def getDurationFromNodes(objects, time=None):
|
||||
"""
|
||||
Get the duration of the animation from the given object names.
|
||||
|
||||
:type time: [str, str]
|
||||
:type objects: list[str]
|
||||
:rtype: float
|
||||
"""
|
||||
if objects:
|
||||
|
||||
first = maya.cmds.findKeyframe(objects, which='first')
|
||||
last = maya.cmds.findKeyframe(objects, which='last')
|
||||
|
||||
if time:
|
||||
startKey = maya.cmds.findKeyframe(objects, time=(time[0], time[0]), which="next")
|
||||
if startKey > time[1] or startKey < time[0]:
|
||||
return 0
|
||||
|
||||
if first == last:
|
||||
if maya.cmds.keyframe(objects, query=True, keyframeCount=True) > 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
return last - first
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def getReferencePaths(objects, withoutCopyNumber=False):
|
||||
"""
|
||||
Get the reference paths for the given objects.
|
||||
|
||||
:type objects: list[str]
|
||||
:type withoutCopyNumber: bool
|
||||
:rtype: list[str]
|
||||
"""
|
||||
paths = []
|
||||
for obj in objects:
|
||||
if maya.cmds.referenceQuery(obj, isNodeReferenced=True):
|
||||
paths.append(maya.cmds.referenceQuery(obj, f=True, wcn=withoutCopyNumber))
|
||||
|
||||
return list(set(paths))
|
||||
|
||||
|
||||
def getReferenceData(objects):
|
||||
"""
|
||||
Get the reference paths for the given objects.
|
||||
|
||||
:type objects: list[str]
|
||||
:rtype: list[dict]
|
||||
"""
|
||||
data = []
|
||||
paths = getReferencePaths(objects)
|
||||
|
||||
for path in paths:
|
||||
data.append({
|
||||
"filename": path,
|
||||
"unresolved": maya.cmds.referenceQuery(path, filename=True, withoutCopyNumber=True),
|
||||
"namespace": maya.cmds.file(path, q=True, namespace=True),
|
||||
"node": maya.cmds.referenceQuery(path, referenceNode=True)
|
||||
})
|
||||
|
||||
return data
|
||||
Reference in New Issue
Block a user