Quantcast
Channel: mel wiki
Viewing all 610 articles
Browse latest View live

How can I draw a simple message to the screen?

$
0
0
inViewMessage creates a great little bubble-shaped message that can be different colors and fade out, etc.
http://help.autodesk.com/cloudhelp/2016/ENU/Maya-Tech-Docs/CommandsPython/inViewMessage.html
import maya.cmds as mc
mc.inViewMessage(assistMessage='In-view message <hl>test</hl>.', position='midCenter', fade=True, backColor=0x00990000)

You can use the headsUpMessage command to do this. It will disappear on the next screen refresh (by default). It has arguments to have it display for a fixed amount of time, or be centered on a particular object \ object selection.

You could do something similar with a confirmDialog or promptDialog, but they are modal dialog boxes that stop the user from interacting until their condition is met. headsUpMessage doesn't stop the user from interaction, and automatically goes away.

From the docs:
headsUpMessage "Ouch!";
headsUpMessage -object circle1 "This is Circle 1";
headsUpMessage -selection "These objects are selected";
headsUpMessage -time 5.0 "Text appears for minimum of 5 seconds.";
headsUpMessage -verticalOffset 20 "Text appears 20 pixels above point.";
headsUpMessage -horizontalOffset -20 "Text appears 20 pixels to the left of the point.";

Query Maya & Maya Python Executable Locations

$
0
0

From Windows:

You can use the where command (which on Linux/Mac).
For example, you can give it a starting path to narrow the search, so it's not searching the whole HD:
> where /R "c:\Program Files\Autodesk" maya.exe
c:\Program Files\Autodesk\Maya2016\bin\maya.exe
c:\Program Files\Autodesk\Maya2016.5\bin\maya.exe

From Maya:

Querying this in a Python script ran in Maya is pretty trivial: maya.exe and mayapy.exe (the Python executable) live in the same directory for Windows. You can also query where Python thinks its install location is (important for imports).
import os
import sys

print sys.executable
print os.path.join(os.path.split(sys.executable)[0], 'mayapy.exe')
print sys.prefix

C:\Program Files\Autodesk\Maya<version>\bin\maya.exe
C:\Program Files\Autodesk\Maya\bin\mayapy.exe
C:/Program Files/Autodesk/Maya<version>/Python
On Mac, it's a bit different:
import sys

print sys.executable
print sys.prefix

/Applications/Autodesk/maya<version>/Maya.app/Contents/MacOS/Maya
/Applications/Autodesk/maya<version>/Maya.app/Contents/Frameworks/Python.framework/Versions/Current
Since the mayapy app lives here:
/Applications/Autodesk/maya<version>/Maya.app/Contents/bin/mayapy

PyMel Also makes this really easy:
import pymel.mayautils as pmu

print pmu.getMayaLocation()
Windows result:
C:\Program Files\Autodesk\Maya2014
Mac result:
/Applications/Autodesk/maya2013/Maya.app/Contents

There's also the MAYA_LOCATION env var, that Maya appears to create on the fly when it launches:
import os
print os.getenv("MAYA_LOCATION")
C:/Program Files/Autodesk/Maya2016 // 

Batching Maya Files via Python

$
0
0
This subject is about batching Maya files in a session of Maya other than the one that is currently open, via Python. It's one thing to (via the currently opened Maya) loop over a list of files opening them in succession and executing code. But if you want to launch external Maya's in batch mode (so as to not disturb your current Maya session), open a file, and execute code on that file (all in Python), it's a different story.

To batch file via Maya with mel, it's pretty straightforward via maya.exe:
> maya -batch -file someMayaFile.ma -command someMelProc
There is mayapy.exe as well, but this doesn't launch Maya: It launches Maya's version of Python. It is a Maya mirror of python.exe. However, once it has been launched, Maya itself can be imported in as a Python module, and then batching can take place. Method A explains this below.


Different methods below. I came up with Method C first, got suggested Method B, then sort of combined the two to come up with Method A.
  • Method A & C launches a new Maya in batch mode from an existing Maya.
  • Method B launches a new Maya in batch from from a .bat file on disk.

Method A

The example below will batch over all the passed in Maya files, and saves a new group node in them as proof it worked. Some of the magic is using subprocess.call to call to mayapy.exe, and passing in an additional argument that is the name of the current file to work on. Another bit of trickery is having the module do double-duty: When executed in GUI Maya the user runs its main() function to start it up, but when it is called to via mayapy.exe putting it in 'batch mode', the top & bottom section 'if __name__ == "__main__":' are executed as well which both imports maya.standalone (thus now physically has Maya running inside of mayapy.exe) and calls to the batchOperation() function, which can then query, via sys.argv the command-line arguments passed in (which are the names of the files to batch over). I have a feeling that's not terribly clear. I hope the code makes more sense ;)

I'll label each thing has it's executed so you can see the data flow.
GUI mode starts with GUI A and ends with GUI D, which then starts BATCH A and ends with BATCH E.
# batchTest.py
import subprocess

if __name__ == "__main__":
    # If we're in 'batch' mode, it means that mayapy.exe is running,
    # so load maya.standalone into it:
    import maya.standalone
    maya.standalone.initialize(name='python')
    # If you have a userSetup.py that is needed for happy Maya execution, call
    # to it here:
    import userSetup
    userSetup.main()

import maya.cmds as mc

def main(paths):
    """
    Launched in the gui version of Maya, manually, or via some other script.

    Parameters :
    paths : string\list : Path(s) to Maya files to batch over.
    """
    if not isinstance(paths, list):
        paths = [paths]
    args = ['mayapy', __file__, '-']
    args.extend(paths)
    # This fires off another version of Maya in 'batch' mode, calling back to
    # this code, executing the 'batch only' parts.  Luckily, the current version
    # of Maya calling it waits for the other version to complete doing it's thing
    # before continuing on in this code...
    subprocess.call(args)

def batchOperation():
    """
    The work done by the batch:  This has been called to while Maya is in batch
    mode, via the subprocess.call() func in the main() function:  Because of this,
    we capture the incoming args via sys.argv.
    A single instance of Maya is launched, and then all the files are batched over
    in that instance, and processed
    """
    # The sys.argv vals match the subprocess call above
    # sys.argv[0] : The path to this module ( __file__ )
    # sys.argv[1] : '-'
    # sys.argv[2] + : Path(s) to the files to batch over
    paths = sys.argv[2:]

    # If there is an error, the shell will just disappear.  So we wrap it in a
    # try\except, allowing it to stay open to help track down bugs.
    try:
        mc.file(prompt=False)
        for fil in paths:
            mc.file(fil, force=True, open=True)
            mc.group(empty=True, name='I_was_made_in_batch_mode', world=True)
            mc.file(force=True, save=True)
    except Exception, e:
        print "Exception:", e
        raw_input("Encountered an exception, see above.  Press Enter to exit...")
    finally:
        mc.file(prompt=True)

# When called to via batch mode, run this code.  This line must come after the
# function it's calling.
if __name__ == "__main__":
    batchOperation()
To run in Maya:
import batchTest
batchTest.main(['c:/temp/myFileA.ma', 'c:/temp/myFileB.ma'])
You should see a shell pop up for the new instance of Maya that is launched (via mayapy.exe), and then each path is opened and batch processed in that shell. The gui version of Maya will wait until completion of the batch to continue on with its code.

Method B

This snippet will launch a myModule.py file living in the same directory (per the special %~dp0 variable) as the bat script, using a pre-made env-var storing the path to the mayapy.exe file. It will also pass the name of the item dragged&dropped onto it via the "%1".
Note that either of these examples could then call to the code in Example A, above.
"%MAYA_PY_EXECUTABLE%""%~dp0\myModule.py""%1"
This (modified) example was given to me by Keir Rice. Thanks Keir!
Make a batch script: batchTest.bat . It runs mayapy.exe, which is Maya's version of Python.
REM Launcher batch file: batchTest.bat
"%ProgramFiles%\Autodesk\Maya2010\bin\mayapy.exe""c:\temp\test.py"
pause
  • Add pause to the end of the batch script if you want the shell to stay open upon completion.
Note that if mayapy is part of your Windows path, you can leave off the directory before it, and the .exe on the end of it.

Then make the python module it calls to:
# python script to run: c:\temp\test.py
import maya.cmds

def TestFunction():
    print maya.cmds.about(version=True)

if __name__ == "__main__":
    # Init Maya:
    import maya.standalone
    maya.standalone.initialize(name='python')
    # If you have one:
    import userSetup
    userSetup.main()

    # Run your code:
    TestFunction()
Finally, run the bat script. Results should be printed in the shell.

Method C:

This is one I came up with before I knew about Method A or B, above.
Key Components: (the file-names aren't important, just illustrating the example)
  • mainModule.py : This is the Python module that orchestrates the whole thing. It can be executed from Maya, or the command line.
  • melScript.mel : This is a 'wrapper' script that our batch operation will call to. It in turn, via the mel python command, will execute the Python code we want to have effect the scene files.
  • pythonModule.py : This is the Python module that our mel script calls to. In this example, it executes the main() function inside.

Here is a bit of code from mainModule.py. By calling to subprocess.call(), we're able to launch Maya in batch mode on a specific file, executing our wrapper mel command on it:
http://docs.python.org/library/subprocess.html
# mainModule.py
import subprocess
subprocess.call(['maya', '-batch', '-file', 'c:\\myFile.ma', '-command', 'melScript'])

This is the guts of our wrapper mel script. All it does is call to the Python code we care about:
// melScript.mel

global proc melScript(){
    python("import pythonModule");
    python("pythonModule.main()");
}

pythonModule.py and its main() function can prettymuch do whatever you'd like to that scene file:
# pythonModule.py
import maya.cmds as mc

def main():
    # do stuff!

API: How can I loop over component selections?

$
0
0
Pulled a bunch of below from this post:
http://nccastaff.bournemouth.ac.uk/jmacey/RobTheBloke/www/maya/MSelectionList2.html

The below example has all the variable names set to their object types. I did this just to illustrate how the objects were returned and used, don't recommend it for regular coding sessions...

The below example will loop over each object, and the components selected on that object. It will print the worlds-pace position of each point that is part of the component selection.

VERY INTERESTING : If you have multiple verts selected on multiple mesh, the api calls automatically lump them into 'vert mesh lists'. Meaning, the first MItSelectionList will loop over each mesh you have picked (via selecting the verts), and then the second MItGeometry loops over the selected verts on said mesh. This is different than say, picking a bunch of verts and listing them via ls.
# Python code
import maya.OpenMaya as om

# Make a MSelectionList container object:
MSelectionList = om.MSelectionList()
# Fill with selection, as MObjects
om.MGlobal.getActiveSelectionList(MSelectionList)
# Create an iterator to loop over our selection:
MItSelectionList = om.MItSelectionList(MSelectionList)

while not MItSelectionList.isDone():
    # The mesh node:
    MDagPath = om.MDagPath()
    # The components, if any:
    MObject = om.MObject()

    # Define the path to our object and components.
    MItSelectionList.getDagPath(MDagPath, MObject)

    # Create a function set for this MDagPath.  MDagPath.node() returns an MObject.
    MFnDependencyNode = om.MFnDependencyNode(MDagPath.node())
    # We can now do work on the mesh object if we want to.  Otherwise this can be removed, not used below.

    print MDagPath.fullPathName()
    # If we have components:
    if not MObject.isNull():
        # Make an iterator for them:
        MItGeometry = om.MItGeometry(MDagPath, MObject)
        while not MItGeometry.isDone():
            # Make a point object for the current loop:
            MPoint = MItGeometry.position(om.MSpace.kWorld)
            # And print its info:
            print "\t-vert index: %s   -pos: %s %s %s"%(MItGeometry.index(),
                                                        MPoint.x, MPoint.y, MPoint.z)
            MItGeometry.next()

    MItSelectionList.next()
Example print, regardless of the order the verts were picked in:
|myNodeA|myNodeAShape
	-vert index: 3380   -pos: 37.918586731 28.5343780518 132.385604858
	-vert index: 3394   -pos: 35.4213676453 27.519777298 135.702865601
|myNodeB|myNodeBShape
	-vert index: 308   -pos: 52.6544418335 -2.37073945999 103.18737793
	-vert index: 309   -pos: 52.5206260681 1.12697529793 103.657699585

API: Understanding component level looping, and MObjects

$
0
0
Initially pulled a bunch of data from this informative post:
http://nccastaff.bournemouth.ac.uk/jmacey/RobTheBloke/www/maya/MSelectionList2.html


VERY INTERESTING : If you have multiple components (verts, edges, cvs, etc) selected on multiple nodes (mesh, NURBS), the api calls automatically lump them into 'vert mesh lists'. Meaning, the first MItSelectionList will loop over each node you have picked (via selecting the components), and then the second MItGeometry loops over the selected components on said node. This is different than say, picking a bunch of verts and listing them via the ls command.
# Python code
import maya.OpenMaya as om

# First, select a bunch of components on one or more nodes.
# Make a MSelectionList container object:  These are "lists of MObject's"
objectList = om.MSelectionList()
# Fill with selection, as MObjects, enabling 'ordered selection' (if that is important):
om.MGlobal.getActiveSelectionList(objectList, True)
# Create an iterator to loop over our selection:
iterObjectList = om.MItSelectionList(objectList)
while not iterObjectList.isDone():
    # The selected node:
    nodeDagPath = om.MDagPath()
    # The selected components, if any:
    componentsObject = om.MObject()
    # Define the path to our object and components.
    iterObjectList.getDagPath(nodeDagPath, componentsObject)
    print nodeDagPath.fullPathName()
    if not componentsObject.isNull():
        # Make an iterator for them:
        iterGeo = om.MItGeometry(nodeDagPath, componentsObject)
        while not iterGeo.isDone():
            # Make a point object for the current loop:
            componentPos = iterGeo.position(om.MSpace.kWorld)
            # And print its info:
            print "\tcomponent -index: %s   -pos: %s %s %s"%(iterGeo.index(),
                                                             componentPos.x, componentPos.y, componentPos.z)
            iterGeo.next()
    iterObjectList.next()
Example print. Regardless what order we picked the components in across multiple objects, the always get lumped together:
|myNodeA|myNodeAShape
	component -index: 3380   -pos: 37.918586731 28.5343780518 132.385604858
	component -index: 3394   -pos: 35.4213676453 27.519777298 135.702865601
|myNodeB|myNodeBShape
	component -index: 308   -pos: 52.6544418335 -2.37073945999 103.18737793
	component -index: 309   -pos: 52.5206260681 1.12697529793 103.657699585

API : Understanding component level looping, and MObjects

$
0
0
Initially pulled a bunch of data from this informative post:
http://nccastaff.bournemouth.ac.uk/jmacey/RobTheBloke/www/maya/MSelectionList2.html

VERY INTERESTING : If you have multiple components (verts, edges, cvs, etc) selected on multiple nodes (mesh, NURBS), the api calls automatically lump them into 'vert mesh lists'. Meaning, the first MItSelectionList will loop over each node you have picked (via selecting the components), and then the second MItGeometry loops over the selected components on said node. This is different than say, picking a bunch of verts and listing them via the ls command.
# Python code
import maya.OpenMaya as om

# First, select a bunch of components on one or more nodes.
# Make a MSelectionList container object:  These are "lists of MObject's"
objectList = om.MSelectionList()
# Fill with selection, as MObjects, enabling 'ordered selection' (if that is important):
om.MGlobal.getActiveSelectionList(objectList, True)
# Create an iterator to loop over our selection:
iterObjectList = om.MItSelectionList(objectList)
while not iterObjectList.isDone():
    # The selected node:
    nodeDagPath = om.MDagPath()
    # The selected components, if any:
    componentsObject = om.MObject()
    # Define the path to our object and components.
    iterObjectList.getDagPath(nodeDagPath, componentsObject)
    print nodeDagPath.fullPathName()
    if not componentsObject.isNull():
        # Make an iterator for them:
        iterGeo = om.MItGeometry(nodeDagPath, componentsObject)
        while not iterGeo.isDone():
            # Make a point object for the current loop:
            componentPos = iterGeo.position(om.MSpace.kWorld)
            # And print its info:
            print "\tcomponent -index: %s   -pos: %s %s %s"%(iterGeo.index(),
                                                             componentPos.x, componentPos.y, componentPos.z)
            iterGeo.next()
    iterObjectList.next()
Example print. Regardless what order we picked the components in across multiple objects, the always get lumped together:
|myNodeA|myNodeAShape
	component -index: 3380   -pos: 37.918586731 28.5343780518 132.385604858
	component -index: 3394   -pos: 35.4213676453 27.519777298 135.702865601
|myNodeB|myNodeBShape
	component -index: 308   -pos: 52.6544418335 -2.37073945999 103.18737793
	component -index: 309   -pos: 52.5206260681 1.12697529793 103.657699585

Also see:

API : Understanding MIterators

$
0
0
If you want to loop over items in the API, the MIt classes help you do that. High level notes below.
These are all part of the OpenMaya module, unless otherwise noted.
EXAMPLES BELOW

MSelectionLists (lists of MObjects):

All Nodes:

  • MItDependencyNodes : Use the dependency node iterator to traverse all the nodes in Maya's Dependency Graph.

Node Hierarchies:

  • MItDag : Use the DAG iterator to traverse the DAG (parent/child relationships)

Node Connections:

  • MItDependencyGraph : Iterate over Dependency Graph (DG) Nodes or Plugs starting at a specified root Node or Plug.

Animation:

  • OpenMayaAnim.MItKeyframe : Iterate over the keyframes of a particular Anim Curve Node, and query and edit the keyframe to which the iterator points.

Components:

  • MItGeometry : This class is the iterator class for geometry data, and can be used to loop over the CVs of NURBS, the points of subds & lattices, and the vertices of polygonal meshes. Generic/higher level iteration over components.
    • These aren't necessarily subclasses, but they go into finer detail over components. Left out all the 'MItSubd' classes, since I really never use them.
    • NURBS:
      • MItCurveCV : Iterator class for NURBS curve control vertices (CVs). The iteration can be for a given curve or for a group of CVs.
      • MItSurfaceCV : NURBS surface CV iterator.
    • Mesh:
      • MItMeshEdge : Edge iterator for polygonal surfaces.
      • MItMeshFaceVertex : The iterator for face vertices on polygonal surfaces
      • MItMeshPolygon : This class is the iterator for polygonal surfaces (meshes). It iterates over their faces.
      • MItMeshVertex : Class iterator for polygonal vertices.

References/Assemblies:

  • MItEdits : Use the edits iterator to traverse all the edits on a reference or assembly.

Particles:

  • MItInstancer : This class provides methods for iterating over all the dag paths to the shapes created in the scene by the replacement of particles by dag nodes.

Utilities:

  • MIteratorType : Thisclass is used on iterators where more than one type of filters can be specified. It also provides functionalities to set and get the filter list or individual types of filter. This class should be used in conjunction with DAG/DG/DependencyNodes iterators for using filter list (list of MFn::Type objects) on them, thus enabling faster traversal throgh iterators.

Examples

Iterate over the selected components on some node. In this example, I'll pick some verts on a couple different mesh.
Based on the selected components. we'll iterate over their parental mesh nodes via a MItSelectionList, and over the components via a MItGeometry.
Note that even though you only pick components (and not the mesh nodes directly), the MItSelectionList auto sorts them into 'categories' by their parental mesh.
Also see:
import maya.OpenMaya as om

# Select some components (verts, cvs) on one or more mesh:
selList = om.MSelectionList() # MSelectionList is a list of MObjects
om.MGlobal.getActiveSelectionList(selList)
iterSelList = om.MItSelectionList(selList)
while not iterSelList.isDone():
    # The node for the selected components:
    nodeDagPath = om.MDagPath()
    # The selected components, if any:
    componentsObject = om.MObject()
    # Define the path to our object and components.
    iterSelList.getDagPath(nodeDagPath, componentsObject)
    print nodeDagPath.fullPathName()
    if not componentsObject.isNull():
        # Make an iterator for the components:
        iterGeo = om.MItGeometry(nodeDagPath, componentsObject)
        while not iterGeo.isDone():
            # Make a point object for the current loop:
            componentPos = iterGeo.position(om.MSpace.kWorld)
            # And print its info:
            print "\tcomponent -index: %s   -pos: %s %s %s"%(iterGeo.index(),
                                                             componentPos.x, componentPos.y, componentPos.z)
            iterGeo.next()
    iterSelList.next()
Prints:
|pSphere1|pSphereShape1
	component -index: 261   -pos: 1.66245281696 1.20784258842 1.49297451973
	component -index: 262   -pos: 1.20784258842 1.66245269775 1.49297451973
	component -index: 280   -pos: 1.70814728737 0.555010676384 1.7960511446

|pCube1|pCubeShape1
	component -index: 0   -pos: 2.99528660484 -1.26999998093 1.26999998093
	component -index: 1   -pos: 5.53528656669 -1.26999998093 1.26999998093
	component -index: 2   -pos: 2.99528660484 1.26999998093 1.26999998093
	component -index: 3   -pos: 5.53528656669 1.26999998093 1.26999998093

How can I find the min and max keyframe values for all objects in the scene?

$
0
0
Will return back a float array with two items, the [start, end] frames:

Mel:

Will select the curves in the process:
global proc float[] returnFrameRange(){
	select -r `ls -type "animCurve"`;
	return {float(`findKeyframe -which first`), 
                float(`findKeyframe -which last`)};
}

Python

Not based on selection.
import maya.cmds as mc
def sceneFrameRange():
    animCurves = mc.ls(type='animCurve', recursive=True)
    minF = mc.findKeyframe(animCurves,  which="first")
    maxF = mc.findKeyframe(animCurves,  which="last")
    return minF, maxF
Note : I've seen bugs where referenced curves can cause it to always return 0,0 : You'll need to filter out any referenced curves first.

Also see:

How can I find the min and max keyframe range for the provided objects?

$
0
0
I seem to do this just not quite often enough to remember how to do it, so I'll make a note here.

Func returns a tuple containing the min and max frame range based on the list of nodes passed in.
# Python code
import maya.cmds as mc

def getMinMaxAnimRange(nodes):
    first = 0
    last = 0
    curves = mc.listConnections(nodes, source=True, destination=False, type='animCurve')
    if curves is not None:
        first = mc.findKeyframe(curves, which='first')
        last = mc.findKeyframe(curves, which='last')
    return (first, last)
Note A : I've seen bugs where the findKeyframe command fails on the passed in animCurves, and instead needs a passed in list of nodes. Car-azy.
Note B : I've seen other bugs where referenced curves can cause it to always return 0,0 : You'll need to filter out any referenced curves first.

Also see:

How can I trigger a callback whenever a keyframe is set?

$
0
0
I needed a way to know whenever a keyframe was set in Maya: There didn't seem to be a way to do this via a scriptJob, but the API to the rescue.

The below callback will print the names of the animCurve nodes modified whenever a keyframe is set.
However, even though the incoming argument to the editedCurves parameter is an MObjectArray, it only has a single item (based on testing), meaning if you have 10 nodes selected, this code will be executed 10 separate times using addAnimCurveEditedCallback:
import maya.OpenMaya as om
import maya.OpenMayaAnim as oma

def animFunc(editedCurves, *args):
    """
    editedCurves : MObjectArray
    """
    for i in range(editedCurves.length()):
        mFnDependNode = om.MFnDependencyNode(editedCurves[i])
        nodeName = mFnDependNode.name()
        print i,nodeName

cid = oma.MAnimMessage.addAnimCurveEditedCallback(animFunc)
# Delete the callback later:
om.MMessage.removeCallback(cid)

If you instead want a callback that iterates over all the channels keyed at once, you can use addAnimKeyframeEditedCallback:
import maya.OpenMaya as om
import maya.OpenMayaAnim as oma

def animFunc(editedKeys, *args):
    """
    editedKeys : MObjectArray
    """
    for i in range(editedKeys.length()):
        mFnKeyframeDelta  = oma.MFnKeyframeDelta(editedKeys[i])
        paramCurve = mFnKeyframeDelta.paramCurve()
        mFnDependNode = om.MFnDependencyNode(paramCurve)
        nodeName = mFnDependNode.name()
        print i,nodeName

cid = oma.MAnimMessage.addAnimKeyframeEditedCallback(animFunc)
Delete the callback later
om.MMessage.removeCallback(cid)

Where does HumanIK save its Skeletal Definition Templates?

$
0
0
When you use the HumanIK 'Character Controls' window's 'Save Skeletal Definition' option, it doesn't give you a a filebrowser dialog, it has a secret hard-coded path. Where does it go?
C:\Users\<USERNAME>\AppData\Roaming\Autodesk\HIKCharacterizationTool5\template
Just replace <USERNAME> with the current user name.

It should be noted that the Windows env var APPDATA stores this path:
import os
print os.getenv("APPDATA")
# C:\Users\<USERNAME>\AppData\Roaming\
And Maya just appends the rest to the end.


Welcome

Python & Qt versions in Maya

$
0
0
MayaPythonQtCompatible PyQtCompatible PySideWin CompilerLinux CompilerMac Compiler
8.52.4.3
20082.5.132bit & 64bit vc8.0 + SP1 + qtHotfix, Intel 9.1.03432bit & 64bit, gcc 4.1.2, Intel 9.1.03932bit XCode 2.4.1, gcc 4.0.1, Intel 9.1.037*
20092.5.132bit XP SP2 & 64bit XP x64 SP2, vc8.0+SP1+qtHotfix, Intel 10.1.01364bit RHEL4.4, gcc 4.1.2 Intel 9.1.03932bit Tiger 10.4.11, XCode 2.4.1, gcc 4.0.1, Intel 10.1.007*
20102.6.132bit Xp SP2 & 64bit Xp x64 SP2, Visual Studio 2008 SP1, Intel 10.1.02264bit RHEL5.1 gcc 4.1.2, Intel 11.0.08332bit & 64bit Leopard 10.5.6, XCode 3.0, gcc 4.0.1, Intel 11.0.064
20112.6.44.5.3 (it begins...)??32bit Xp SP2 & 64bit Xpx64 SP2, Visual Studio 2008 SP1, Intel 11.1.05164bit RHEL5.1, gcc 4.1.2, Intel 11.1.05932bit & 64bit Leopard 10.5.x, XCode 3.1.2, gcc 4.0.1, Intel 11.1.076
20122.6.44.7.1??32bit XP SP2 & 64bit XPx64 SP2, Visual Studio 2008 SP1 + ATL security update, Intel 11.1.06764bit RHEL5.1, gcc 4.1.2, Intel 11.1.07364bit Snow Leopard 10.6.4, XCode 3.2.1, gcc 4.2.1, Intel 11.1.089
20132.6.44.7.14.9.1?32bit Win7 & 64bit Win7x64, Visual Studio 2010 SP1, Intel 12.0.4.19664bit RHEL 6.0, FC14 gcc 4.1.2, Intel 11.1.07364bit SnowLeopard 10.6.8, Xcode3.2.1 gcc 4.2.1, Intel 11.1.089
20142.7.34.8.24.101.1.2 - Ships with Maya!64bit Win7x64, Visual Studio 2010 SP1, Intel Composer XE 201164bit RHEL 6.0, FC14, gcc 4.1.2, Intel Composer XE 2011 Update 1164bit Lion 10.7.4, Xcode 4.3.3 with SDK 10.6 (SnowLeopard), gcc 4.2.1, Intel Composer XE 2011 Update 11
20152.7.34.8.5?1.264bit Win7x64, Visual Studio 2012 Update 4, Intel Composer XE 2013 Update 5 (13.1.3.198)64bit RHEL/CentOS 6.2, FC14, gcc 4.1.2, Intel Composer XE 2013 SP1 Update 1 (14.0.1.106)64bit Mountain Lion 10.8.5, Xcode 5.0.2 with SDK 10.8 (Mountain Lion), clang with libstdc++, Intel Composer XE 2013 SP1 Update 1 (14.0.1.103)
20162.7.64.8.6?1.2Windows 64bit Win7x64, Visual Studio 2012 Update 4 + Win 8 SDK, .Net framework 4.5.1, Intel Composer XE 2015 Initial release (15.0.0.108)Linux 64bit RHEL/CentOS 6.5, FC20, gcc 4.8.2, Intel Composer XE 2015 Update 1 (15.0.1.133)Mac 64bit Mavericks 10.9.5, Xcode 6.1 or 6.1.1 with SDK 10.9 (Mavericks), clang with libstdc++, Intel Composer XE 2015 Update 1 (15.0.1.108)
20172.7.115.6.1"PyQt5"2.0Windows 64bit Win7x64, Visual Studio 2012 Update 4 + Win 8 SDK, .Net framework 4.5.1, Intel Composer XE 2015 Initial release (15.0.0.108)Linux 64bit RHEL/CentOS 6.5, FC20, gcc 4.8.2, Intel Composer XE 2015 Update 1 (15.0.1.133)Mac 64bit Mavericks 10.9.5, Xcode 6.1 or 6.1.1 with SDK 10.9 (Mavericks), clang with libc++, Intel Composer XE 2015 Update 1 (15.0.1.108)
2018?5.6.1"PyQt5"2.0Visual Studio 2015?Xcode 7.3.1 SDK 10.11

Starting in 2011, Maya's entire ui back-end was converted to Qt. You still use the same Maya commands to author UI's, but behind the scenes Qt is appearing on your screen.
Starting in 2017, Maya migrated to Qt5 / PyQt5 / PySide2, which broke a bunch of backwards compatibility. See notes here on this.

This is not to be confused with PyQt or PySide, which are Python (not Maya) implementations of Qt. You can also get PyQt& PySide working in Maya, if you jump through some hoops, if using versions before 2014: Starting in 2014, PySide started shipping with Maya: No more needing to compile PyQt.

Also see:

Qt & PySide: Docs & reference

$
0
0
For Qt itself, look here:

Other tutorials from the web:

PySide docs for Maya:

PyQt docs for Maya:
PyQt specific:

How can I project a 2d texture in 3d space

$
0
0
I always forget how to do this, and I feel like Maya keeps moving this option around.
In Maya 2016 at least, in the Hypershade -> Create -> 2D Textures -> Enable '2D Projection'.

You can also change it by modifying the optionVar Maya uses to store it. Valid string values are:
normal 
projection 
stencil
For example:
import pymel.core as pm
pm.optionVar['create2dTextureType'] = 'projection'



How can I add a new node/index/layer to a layeredTexture?

$
0
0
Adding a new index to a layeredTexture node takes a lot of work: Multiple nodes are created and connected together. I found the mel global proc createRenderNodeCB living in the createRenderNode.mel script, that actually does all the heaving lifting for you. You just need to pass in the layeredTexture node to update, and which index you're adding to.
You'll note in the string formatting that a '%node' is being passed in: That's actually part of the mel syntax, but since it includes a percent sight, Python thinks its string formatting, if left in the main string. So, we actually use Python's string formatting to add it in, to avoid the error. Wacky.

If you check the print in the Script Editor after you execute this, you'll see all the work it did.
If you want it to add a 2d texture projected into 3d space, check this out: How can I project a 2d texture in 3d space : And run that code first.
import pymel.core as pm

layeredTex = "layeredTexture1"
index = 0
mel = 'source createRenderNode; createRenderNodeCB -as2DTexture "" file "defaultNavigation -force true -connectToExisting -source %s -destination %s.inputs[%s].color; ";'%('%node', layeredTex, index)
pm.mel.eval(mel)

Understanding Layered Textures

$
0
0
For some reason my brain has a hard time remembering how layered textures work whenever I use them:
  • Layered texture, in the Attribute Editor, stack from left to right, in order. If a real stack, this would be top to bottom.
  • The Blend Mode for a given texture dictates how it will react with the texture to its right (or, under it) -> The Blend Mode for the right (bottom) most texture has no impact, since there is nothing for it to blend with.
  • Setting a blend mode to "None" will not display any textures to the right of that one.
  • Values can go over 255 if you use "Add". Use "Lighten" to keep them at 255 max.

How can I convert a shader/material into a texture on disk?

$
0
0
The convertSolidTx command.
Also see this script: copyConvertSolidTx.mel

This command can be execute from the Hypershade by selecting a material + a mesh it's assigned to, and 'Edit -> Convert To File Texture []'

PyMel : UV access

$
0
0
The PyMel Mesh class has a number of methods for interacting with UVs:
  • .assignUV : Maps a texture coordinate to a specified vertex of a polygon.
  • .assignUVs : This method maps all texture coordinates for the mesh.
  • .clearUVs : This method clears out all texture coordinates for the mesh, and leaves behind an empty UVset.
  • .createUVSet : Create a new empty uv set for this mesh.
  • .deleteUVSet : Deletes a named uv set from the object.
  • .getAssignedUVs : This method finds all texture coordinates for the mesh that have been mapped, and returns them in the same format as the assignUVs.
  • .getAssociatedUVSetTextures : Get a list of texture nodes which are using a given uv set.
  • .getCurrentUVSetName : Get the name of the “current” uv set. The “current” uv set is the uv set which is used for uv operations when no uv set is explicitly specified.
  • .getFaceUVSetNames : returns the list of UV sets mapped to a face
  • .getPolygonUV : Get the value of the specified texture coordinate for a vertex in a polygon.
  • .getPolygonUVid : Get the id of the specified texture coordinate for a vertex in a polygon.
  • .getUV : Get the value of the specified texture coordinate from this mesh’s uv list.
  • .getUVAtPoint : Find the point closet to the given point, and return the UV value at that point.
  • .getUVSetFamilyNames : Get the names of all of the uv set families on this object.
  • .getUVSetNames : Get the names of all of the uv sets on this object.
  • .getUVSetsInFamily : Get the names of the uv sets that belong to this set family.
  • .getUVs : This method copies the texture coordinate list for this mesh into the given uv arrays.
  • .getUvShellsIds : Constructs an array of unique integer for each UV shell.
  • .isUVSetPerInstance : Return true if this set is per-instance, and false if it is shared across all instances.
  • .numUVSets : Returns the number of uv sets for an object.
  • .numUVs : Returns the number of texture (uv) coordinates for this mesh.
  • .renameUVSet : Renames a uv set from one name to another for this mesh.
  • .setCurrentUVSetName : Set the “current” uv set for this object.
  • .setSomeUVs : Sets the specified texture coordinates (UV’s) for this mesh.
  • .setUV : Sets the specified texture coordinate.
  • .setUVs : Sets all of the texture coordinates (uv’s) for this mesh.
Even though UVs are attributes, you can't use getAttr and setAttr on them. Instead:
myUv = "someMeshShape.map[2]"

# Get the UV val:
uvVal = pm.polyEditUV(myUv , query=True, uValue=True) # This returns a list of both U and V vals

# set the UV val.  Note here, you have to call to each value separately:
pm.polyEditUV(uvVal , uValue=.5, relative=False)
pm.polyEditUV(uvVal , vValue=.5, relative=False)
If you select a bunch of UV's, PyMel will tell you have MeshUVs instances picked, but the docs on that class are empty.

If you want to convert from a MeshUV to a MeshVertex, the only current way I've found is via polyListComponentConversion: However the PyMel wrapper returns strings, rather than PyNodes, so you need to wrapper it:
# select a UV:
myUv = pm.ls(selection=True)  # MeshUV
theVert = pm.PyNode(pm.polyListComponentConversion(myUv[0], toVertex=True)[0]) # MeshVertex
Modified example code from Mason Sheffield:
import pymel.core as pm

mesh = pm.ls(selection=True)[0]
print "Mesh:", mesh
print "\tNum uv sets:", mesh.numUVSets()
uvSets = mesh.getUVSetNames()
for uvSet in uvSets:
    print "\t", uvSet,
    mesh.setCurrentUVSetName(uvSet)
    print ": UVs :", mesh.numUVs()
Mesh: myAwesomeMesh
	Num uv sets: 2
	map1 : UVs : 204
	uvSet1 : UVs : 204

Also see:

Surface from point cloud

$
0
0
No actual Maya code yet, but a collection of theories behind how to do it.
Viewing all 610 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>