[Maya]Scripting Notes
Keywords: Maya, Scripting, Python, MEL, PyMel
Common Cases
How to enable command line running
If want to run python script in background process without GUI, you should initialize maya env at first.
On task beginning:
import maya.standalone
maya.standalone.initialize()
On task end:
maya.standalone.uninitialize()
origin: Initializing and uninitializing in Python
If want to import fbx file in CLI, must load fbx plugin at first, otherwise you would get error RuntimeError: Unrecognized file
or RuntimeError: Invalid file type specified: FBX
.
Load fbx plugin:
import maya.cmds as cmds
cmds.loadPlugin("fbxmaya")
How to import fbx file
import maya.cmds as cmds
from os.path import join
my_filename = "test.fbx"
my_folder = "C:/workspace/maya"
file_path = join(my_folder, my_filename).replace('\\', '/')
# ReturnNewNodes(rnn) flag will tell us if it added anything
new_nodes = cmds.file(file_path, i=True, rnn=True)
print("Nodes added: {}".format(new_nodes))
# If nothing was added to the scene, import as reference
if not new_nodes:
cmds.file(file_path, mnc=True, reference=True)
# Make reference part of the scene
cmds.file(file_path, importReference=True)
Origin:
https://stackoverflow.com/a/68227985/1645289
How to export fbx file
import maya.mel as mel
import maya.cmds as cmds
# select object wanted to export
cmds.select( 'pCylinder1', visible=True )
#-s means export selection only
mel.eval("FBXExport -f \"{0}\" -s".format("D:/pCylinder1.fbx"))
Don’t export fbx file to system drive in Windows, e.g. C:/test.fbx
, and drive character must be upper case. Otherwise script would run failed with error.
Ohter options:
mel.eval('FBXResetExport')
mel.eval('FBXExportBakeComplexAnimation -v 1')
mel.eval('FBXExportInAscii -v 1')
mel.eval('FBXExportFileVersion -v FBX20200')
mel.eval('FBXExportSmoothMesh -v true')
mel.eval('FBXExportUseSceneName -v true')
mel.eval('FBXExportUpAxis y')
mel.eval('FBXExportCameras -v false')
mel.eval('FBXExportLights -v false')
How to get object list
Get all selected objects:
from maya import cmds
selList = cmds.ls(selection= True, long=True) or []
for obj in selList:
print(obj)
Get all geometry objects:
from maya import cmds
geometryList = cmds.ls(geometry = True, long=True)
for geo in geometryList:
print(geo)
Get all objects and check object type:
from maya import cmds
## dag=True : We will only get objects which are listed in the outliner, and none of the hidden objects inside of Maya.
objList = cmds.ls(dag=True, long=True)
for geo in objList:
if cmds.objectType(geo) == "mesh":
print(geo)
How to rename all mesh objects listed in Outliner
Example:
from maya import cmds
objList = cmds.ls(dag=True, long=True)
lst = []
for obj in objList:
isMeshTransform = False
if cmds.objectType(obj) == "transform":
meshList = cmds.listRelatives(obj, children=True, fullPath=True)
if meshList is not None:
for mesh in meshList:
if cmds.objectType(mesh) == "mesh":
isMeshTransform = True
break
if isMeshTransform:
lst.append(obj)
for obj in lst:
newName = "www_#"
cmds.rename(obj, newName)
How to rename duplicate Objects
import re
from maya import cmds
def renameDuplicates():
#Find all objects that have the same shortname as another
#We can indentify them because they have | in the name
duplicates = [f for f in cmds.ls() if '|' in f]
#Sort them by hierarchy so that we don't rename a parent before a child.
duplicates.sort(key=lambda obj: obj.count('|'), reverse=True)
#if we have duplicates, rename them
if duplicates:
for name in duplicates:
# extract the base name
m = re.compile("[^|]*$").search(name)
shortname = m.group(0)
# extract the numeric suffix
m2 = re.compile(".*[^0-9]").match(shortname)
if m2:
stripSuffix = m2.group(0)
else:
stripSuffix = shortname
#rename, adding '#' as the suffix, which tells maya to find the next available number
newname = cmds.rename(name, (stripSuffix + "#"))
print("renamed %s to %s" % (name, newname))
return "Renamed %s objects with duplicated name." % len(duplicates)
else:
return "No Duplicates"
renameDuplicates()
Origin:
https://erwanleroy.com/maya-python-renaming-duplicate-objects/
How to drop object to floor
import pymel.core as pm
def drop_to_floor():
"""
Iterate over the user's selection and drop every object to the origin plane.
"""
for transform in pm.ls(selection=True):
# This is dirty, but its an easy way to make sure the bounding box is in world space.
# Create a temp duplicate of the object and freeze its transforms
temp_dupe = pm.duplicate(transform)[0]
pm.makeIdentity(temp_dupe, apply=True, translate=True, rotate=True, scale=True, normal=True)
# Query the pivot points and bounding box information, then calculate a new height
current_position = pm.xform(transform, translation=True, worldSpace=True, query=True)
bounding_box = pm.xform(temp_dupe, boundingBox=True, query=True, objectSpace=True)
pivots = pm.xform(temp_dupe, pivots=True, query=True, worldSpace=True)
new_height = pivots[1] - bounding_box[1]
# Delete the temp and set the original object's new height
pm.delete(temp_dupe)
pm.xform(transform, translation=[current_position[0], new_height, current_position[2]], worldSpace=True)
if __name__ == '__main__':
drop_to_floor()
How to list all materials used in scene
CLI without graphics:
from maya import cmds
# Doing it with purely cmds
def get_materials_in_scene():
for shading_engine in cmds.ls(type='shadingEngine'):
if cmds.sets(shading_engine, q=True):
for material in cmds.ls(cmds.listConnections(shading_engine), materials=True):
yield material
Pymel version (GUI input bar):
import pymel.core as pm
def get_materials_in_scene():
# No need to pass in a string to `type`, if you don't want to.
for shading_engine in pm.ls(type=pm.nt.ShadingEngine):
# ShadingEngines are collections, so you can check against their length
if len(shading_engine):
# You can call listConnections directly on the attribute you're looking for.
for material in shading_engine.surfaceShader.listConnections():
yield material
One line code:
# And because it is stupid, here it is as a one liner
sorted(set(cmds.ls([mat for item in cmds.ls(type='shadingEngine') for mat in cmds.listConnections(item) if cmds.sets(item, q=True)], materials=True)))
Origin:
https://discourse.techart.online/t/list-all-materials-used-in-scene/10185/4
Maya Rigging Script
Create Control
import maya.cmds as cmds
# Function to create a control for each item in given list
# at that item's position and orientation in worldspace.
def CreateControl(joint_name_list=[]):
for joint_name in joint_name_list:
circle_name = cmds.circle(n="{0}_CTL".format(joint_name), nr=(1,0,0) )[0]
group_name = cmds.group(circle_name, n="{0}_OFFSET".format(joint_name) )
cmds.matchTransform(group_name, joint_name)
cmds.pointConstraint(circle_name, joint_name)
cmds.orientConstraint(circle_name, joint_name)
# Select desired joints, then call your function.
CreateControl(cmds.ls(sl=1))
## OR ##
# Feed a list of joints, then call your function.
joint_name_list = ["thigh_JNT", "knee_JNT", "ankle_JNT"]
CreateControl(joint_name_list)
## OR ##
# Feed it a list of every joint object in the scene, then call your function.
joint_name_list = cmds.ls(type='joint')
CreateControl(joint_name_list)
Origin:Selecting Joints in hierarchy one at a time in Maya - reddit.com
Issues
Cannot find procedure “internalTimeUnitStringToDisplayFPSString”
Error on executing cmds.file
, code:
new_nodes = cmds.file('D:/test01.fbx', i=True, rnn=True, type="FBX")
Log:
Warning: Frame rate mismatch: The imported scene frame rate 'ntsc' differs from the existing frame rate 'film'.
Imported animation keys may not match scene frames and become fractional.
File read in 0.31 seconds.
Error: line 1: Cannot find procedure "internalTimeUnitStringToDisplayFPSString".
Solution:
Use o=True
instead of i=True
.
new_nodes = cmds.file('D:/test01.fbx', o=True, rnn=True, type="FBX")
RuntimeError: Unsaved changes.
Error on executing cmds.file()
, code:
new_nodes = cmds.file('D:/test01.fbx', o=True, rnn=True, type="FBX")
Log:
RuntimeError: Unsaved changes.
Solution:
Run cmds.file(new=True, force=True)
before open new file.
cmds.file(new=True, force=True)
new_nodes = cmds.file('D:/test01.fbx', o=True, rnn=True, type="FBX")
Origin:
https://stackoverflow.com/a/43438675/1645289
References
Blogs
Python maya.cmds模塊代碼示例
https://vimsky.com/zh-tw/examples/detail/python-module-maya.cmds.html
Roy Nieterau
https://gist.github.com/BigRoy
BATCHING ASSETS USING HEADLESS MAYA
https://www.simplygon.com/posts/81ddb551-d62e-4634-b02b-de1fb230a585
Roy Nieterau
https://gist.github.com/BigRoy
“Whatever is rejected from the self, appears in the world as an event.” ― Carl Gustav Jung