Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association

''WHAT IS IT?'' *This page is all about how to do things in Maya using its scripting language "mel" (Maya Embedded Language). And in addition to that "elf" (mel's "Extended Layer Format"), for UI creation. *This page mainly lists code samples, and "how-to's" with mel. There are no "scripts" to 'download'. The purpose of this page is to be a resource for creating mel procedures and scripts. *More info on Maya can be found at the new Autodesk [[web site|http://usa.autodesk.com]] (yes, they bought Alias) or [[Highend3D.com|http://www.highend3d.com/maya/]]. *//This page used to be called ''"How to find stuff using mel"'' on other Wiki's:// **{{{www.openwiki.com}}} (which appears to be dead) & {{{warpcat.pbwiki.com}}} are some past sites. ''WHAT IT ISN'T:'' *Instructions on how to script\program. I'm presuming you already know a bit of that. But since there are plenty of examples listed, they may help. ''HISTORY:'' *This page started years ago as a personal web page with a bunch of random thoughts as I learned mel. So a lot of these notes are from the gamut of versions... 1.0 through currently, 8.5. You will see some pretty simple things listed, and some more complex things as well. I've thought about nixing the simple stuff, but for others that are learning, that would be counterproductive. *I have posted it as a Wiki primarily because they're so easy to edit, I can add stuff very quickly while in development, from work, home, or off-site. I'm currently using [[TiddlyWiki|http://tiddlywiki.com/]] due to the fact it's so easy to search (based on the Tags), and update (since I only have to work on one tiddler at a time, rather than the whole page). ''DISCLAIMER'' *I can't be blamed for anything misrepresented on this page! If it doesn't work, no finger-waving my direction. *Since I work on a Windows system, the majority of the command line stuff I call out to is Win-centric. If you're using Lunix\Unix\OSX etc, I'm fairly confident those args won't work.... (replace with what is appropriate for your OS) ''CONTRIBUTE YOUR BRAIN:'' *If you'd like to add something to this page, please [[email me|WarpCat]] with your addition, and I'll add it in if appropriate, thanks! *I give credit to those I get info from, whenever possible. *If you want to be a full-time contributor/editor, that's an option too. Let me know if you have interest. ''TAKE IT WITH YOU'' *Since this is a tiddlywiki, it's a 'self contained' wiki. No servers required to run it, no other installs needed (other than a valid web browser). Using the //right column// you can download this file (it's only one file), and run it off any other location (memory-stick, cd, hard drive, another web site, etc). Of course it won't update if you do that, so keep checking back on a regular basis. ---- And if you like how this TiddlyWiki works, check out the home page: *http://tiddlywiki.com/ -- download TiddlyWiki *http://tiddlyspot.com/ -- Get your TiddlyWiki hosted online for free (what you're using right now) ---- [[wiki help]]

While reading a book on the [[Processing|http://www.processing.org/]] language, they had a different take on the standard Maya {{{for}}} loop. A normal {{{for}}} loop has this format: {{{ for (initialization; condition; change of condition){ statement; statement; ... } }}} So a simple example: {{{ for($i=0;$i<5;$i++){ print($i + " "); }; 0 1 2 3 4 }}} I learned that you can actually have //multiple// __initialization__ parameters, along with multiple __conditions__, and multiple __change of conditions__: {{{ for($i=0, $j=5; $i<$j, $j<10; $i++, $j++){ print($i + " " + $j + "

"); } 0 5 1 6 2 7 3 8 4 9 }}} I'm really not too sure what I'm going to do with this info yet, but... I think it's good to know! Talking with other programmers, their reply was "oh yeh, //many// other languages do that". So, I guess I've been left out of the.... //loop//. (so bad, but so good).

Retrospective blog entry. mel wiki is created!

''Happy New Year!'' I added this new blog section. I figured out how to move the "mel wiki" icon to the SiteTitle (very exciting). I also added my first bit of Python tagging, and setup a main [[PYTHON]] category. Still stuck on Maya 7 though... Finally, made the 'Tags' tab always be visible in the right hand column, which should make it easier for users to navigate the site by default.

Man, there is a pile of rain coming down here in the San Francisco area! Tiddlyspot.com is down for some reason, so all the latest updates are being made offline...

Tiddlywiki is back up again... I wonder what was going on... Robots! Not directly related to mel, but I made my first couple of solar powered robots: The Symet [img[http://farm3.static.flickr.com/2232/2170294205_36506d0c98_m.jpg][http://www.flickr.com/photos/8064698@N03/sets/72157603647631805/]] The Hexpummer [img[http://farm3.static.flickr.com/2129/2174047884_2b66e455ea_m.jpg][http://www.flickr.com/photos/8064698@N03/sets/72157603656270159/]]

Added a new helpful section, the [[Visual Guide of UI Controls]]. Will be updating it slowly over time, in alphabetical order. Lets the user see the type of UI control before they build it... so you can make your UI's much faster!

Added the new [[All Subjects]] tiddler in the main menu (on the left) of the screen: It will show ALL the subjects (tiddlers) in the wiki. Now you can search through the categories, or just __one big page__ of subjects.

I recently got turned onto ''Processing'' through the ''Make'' blogs: [img[http://processing.org/reference/environment/images/ide.gif]] *Processing: http://www.processing.org/ *Make: http://www.makezine.com/ (which you should read all the time, FYI) It's a cool (free) language that sort of 'wrappers up' Java. From their site: <<< "Processing is an open source programming language and environment for people who want to program images, animation, and interactions. It is used by students, artists, designers, researchers, and hobbyists for learning, prototyping, and production. It is created to teach fundamentals of computer programming within a visual context and to serve as a software sketchbook and professional production tool. Processing is developed by artists and designers as an alternative to proprietary software tools in the same domain." <<< ---- Here's some fantastic examples by [[Jared Tarbell|http://www.complexification.net/programmer.html]]. One of the coolest things: He also gives the ''Processing'' source code away for each of them. That is awesome. Share the knowledge! *http://www.complexification.net/gallery/ [img[http://www.complexification.net/timeline/WTsubstrate.jpg]] [img[http://www.complexification.net/timeline/WThappyPlaceWideB.jpg]] [img[http://www.complexification.net/timeline/WTintersectionMomentary.jpg]] [img[http://www.complexification.net/timeline/WTboxFittingImg.jpg]] (many more in the above link)

I added a new category (on the left) called [[TROUBLESHOOTING]]. It will take some time to organize other stuff into it, but it's a start.

Added a new section called [[Other Links]]. Thought I'd share some of the other web sites that I enjoy, that have some correlation to brains that enjoy Maya and mel.

[[A month or so ago|2008 02 18]] I talked about [[Processing|http://www.processing.org]]. Since then I've started to learn it, and have been posting some of my first sketches on [[Flickr|http://www.flickr.com/photos/8064698@N03/collections/72157604136742471/]]. Enjoy.

I've FINALLY gotten around to re-learning Python. In lite of that, I've made a new Python Wiki: http://pythonwiki.tiddlyspot.com/ While there is still Maya-centric Python stuff on this page, non-Maya related Python stuff I"ll start posting over there. I'm still a Python noob, so there's nothing too amazing over there yet. It's like how this wiki started yeaaaars ago.

Finally got around to updating to tiddlywiki v2.4. No one will really care but me. But it's the new hottness.

I've finally made a blog to tie together my various wiki's and projects. It can be found here: http://warpcat.blogspot.com/

A buddy of mine has started his own mel tiddlywiki as he learns the languange. Everyone should! ;) http://brac.tiddlyspot.com/

I thought I'd try and experiment, and create a [[Guest Book|GuestBook]]. I really have no idea how many people use my wiki, how often it is viewed, etc. I do get an occasional email telling me how someone has used it, which gives me the warm-fuzzies. If you'd like to 'sign' the [[Guest Book|GuestBook]], go to that link, and follow the directions. Since his wiki isn't open for public editing (one of the reasons I set it up that way: I used to get spammed all the time when anyone could edit it), you'll need to //email [[me|WarpCat]] your guest book comment. That can be a departure from regular website guest book signing, so I could see a reluctance on the part of some users. As I said, this is an //experiment// ;-)

I've done some retagging when it comes to Python subjects: I already have an upper-case '[[PYTHON]]' category on the left-column. Before, //all// subjects that were either about Python specifically, or others that had Python code in their examples received that tag. I've now made a 'lowercase' '[[python]]' tag as well to help differentiate: *Subjects that are //specifically related to Python features// will get the upper-case //category// tag. *Subjects that have example Python code in them (or call to the {{{python}}} //mel// command), but aren't 'about' Python specifically, will get the 'lowercase tag'. I think this will help make searching for //Python-specific// issues easier, and not clutter it with code simply written //in// Python.

Since I'm forcing myself to learn the API (very slowly), I added an [[API]] category. I'm mainly learning the API via Python, since I don't know much of c++ at all.

Added the [[INFO]] category. Haven't yet fully populated it, but it was missing: A place on subjects about querying information about things.

Added the [[HARDWARE]] category. Currently only has one item. But it's a cool item. I'm not sure how I'd use it, but I think it deserves its own category ;)

Below are simple {{{lambda}}} wrappers for converting sequences (like API/~PyMel {{{Points}}} or {{{Vectors}}}) from Maya's 'internal units' (cm) to the current 'ui units' (could be cm, could be... something else) and back again. {{{ # Using API 2.0, but works just as well with maya.OpenMaya from maya.api.OpenMaya import MDistance internalToUi = lambda x:[MDistance.internalToUI(item) for item in x] uiToInternal = lambda x:[MDistance.uiToInternal(item) for item in x] }}} For example: {{{ import pymel.core as pm nodeA = pm.PyNode("coneA") nodeB = pm.PyNode("coneB") # This returns internal units: pt_nodeA_rotPiv = nodeA.getRotatePivot(worldSpace=True).cartesian() v_nodeA_rotPiv = pm.dt.Vector(pt_nodeA_rotPiv) # This expects a vector (or list of 3 vals) of *ui units*, so we convert: nodeB.setTranslation(internalToUi(v_nodeA_rotPiv), space='world') }}}

Good blog post here: http://around-the-corner.typepad.com/adn/2012/09/custom-shapes-in-the-maya-api-1.html

Maya has a whole bunch of both c++ & Python API plugin \ scripted plugin example stuff online [[here|http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/index.html?url=cpp_ref/examples.html,topicNumber=cpp_ref_examples_html]] (Maya 2013)

There are edge-cases where certain API calls will want a c++ [[struct|http://www.cplusplus.com/doc/tutorial/structures/]] passed in. For example, the [[OpenMayaRender.MRenderView|http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/index.html?url=cpp_ref/class_m_render_view.html]] class's {{{updatePixels}}} method expects a pointer to a [[RV_PIXELS|http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/cpp_ref/struct_r_v___p_i_x_e_l.html]] struct. How can you do this via the Python API? As it turns out (in this case at least) they've wrappered that struct for you: {{{ import maya.OpenMayaRender as omr rvp = omr.RV_PIXEL() }}} I'd be interested to know how many more there are?

This post by Kristine Middlemiss breaks it down very nicely: *http://around-the-corner.typepad.com/adn/2012/07/setting-a-user-event-within-maya.html Transcribed from that post for prosperity: {{{ # Here's how you would register a new user event type called 'myEvent': import maya.OpenMaya as om om.MUserEventMessage.registerUserEvent('myEvent') # To have a function called 'myFunc' execute whenever the event occurs: def myFunc(data): print('Got a myEvent event!') callbackId = om.MUserEventMessage.addUserEventCallback('myEvent', myFunc) #To send a 'myEvent' event: om.MUserEventMessage.postUserEvent('myEvent') #To remove the callback function when done: om.MUserEventMessage.removeCallback(callbackId) }}} ---- Also see: *[[API: How can I author callbacks for Maya events?]]

# http://help.autodesk.com/view/MAYAUL/2017/ENU/?guid=__py_ref_class_open_maya_1_1_m_fn_mesh_html ~MFnMesh.closestIntersection Note, I'e been unable to get this to work via maya.~OpenMaya, but I have got it to work via maya.api.~OpenMaya Also note the points it reruns are always in internal units (cm) so you may need to convert them to your UI units.

Often times I'll have an MObject, and I want to know what it is exactly. In normal commands you can use a call to {{{objectType}}}. But how about in the API. Below is a round about way to do it. In a nutshell, you check to see if a given MObject has a given function set. The list of available function sets is here: http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_fn_html But it's often easier to just query which function sets are available for the MObject itself: The {{{getFunctionSets}}} function below returns a list of them. Armed with that info, you can then query them. Also see [[these notes|API: How can I query what function sets are available for an MObject?]]. {{{ import maya.OpenMaya as om def getMObjectByStr(strName): selList = om.MSelectionList() selList.add(strName) mObject = om.MObject() selList.getDependNode(0, mObject) return mObject def getFunctionSets(mObject): funcSets = [] om.MGlobal.getFunctionSetList(mObject, funcSets) return funcSets def isApiType(mObject, apiType): if mObject.hasFn(apiType): return True else: return False }}} So to use it: {{{ strName = "myAwesomeMeshShape" mObject = getMObjectByStr(strName) print getFunctionSets(mObject) # [u'kBase', u'kNamedObject', u'kDependencyNode', u'kDagNode', u'kShape', u'kGeometric', u'kSurface', u'kMesh'] # AH, so I can use 'kMesh' : apiType = om.MFn.kMesh print isApiType(mObject, apiType) # True }}}

When making custom node types via scripted-plugins (or regular 'ol compiled plugins), they need a [[MTypeId|http://download.autodesk.com/us/maya/2011help/api/class_m_type_id.html]] set to a specific value, so that custom node types won't clash: {{{ import maya.OpenMaya as om kPluginNodeId = om.MTypeId(0x00113) }}} Autodesk divvies-out ranges of addresses to developers, but how do you get these addresses assigned? Via this web site: * http://mayaid.autodesk.io ---- This blog post does a great job covering all aspects of these id's, how they're used, and how you can register for them: http://around-the-corner.typepad.com/adn/2012/09/maya-and-node-types.html

{{{ import maya.OpenMaya as om import maya.OpenMayaUI as omui activeView = omui.M3dView.active3dView() om.MGlobal.selectFromScreen(0, 0, activeView.portWidth(), activeView.portHeight(), om.MGlobal.kReplaceList) }}} From this post here: https://groups.google.com/d/msg/python_inside_maya/FxnZzCntpp0/F7Sb4udwLK8J

All of the api (~OpenMaya) work I do is via the Python bindings. And plugins authored that way don't need to be 'compiled', since they're considered 'scripted plugins'. Sometimes however I'll run into legacy plugins that need recompiled to the latest version of Maya, and Maya itself comes with many examples of c++ authored plugins that //do// need compiled (living here: {{{C:\Program Files\Autodesk\Maya20XX\devkit\plug-ins}}}). Also see: [[Compiling Python Libraries for Maya]] This is a short overview: #Install [[Visual Studio|http://www.microsoft.com/visualstudio/en-us]]. ##The version of Visual Studio is very important, based on which Maya you are going to compile for. Check out this subject to understand which version you need installed: [[Maya compiler versions]] & [[Python & Qt versions in Maya]] ##When you first launch Visual Studio, configure it to 'C++'. #Launch Visual Studio and: File -> Open {{{C:\path\to\my\plugin\myPlugin.sln}}}. ##{{{.sln}}} are Visual Studio 'solution' files. #Select the 'Release' build configuration, from the drop-down in the 'standard toolbar'. #Press F7 to build the plug-in (Build -> Build Solution): Watch the magic happen in the Output window. #The newly compiled plugin is output to {{{C:\path\to\my\plugin\myPlugin.mll}}} And that's really all there is to it. ---- Questions: *Can you use [[Visual Studio Express|http://www.microsoft.com/express]]? **Looks like there is evidence [[on the web|http://www.creativecrash.com/tutorials/build-plugins-with-visual-c-express-edition]] that [[this is possible|http://www.daisukemaki.com/projects_maya_api_cplusplus.php]]. *Can you use other compliers other than Visual Studio? **I've read of Codeblocks, Xcode, and possibly even Eclipse working. ---- ''OR'' Here's a video tutorial by Chad Vernon on how to do it using [[CMake|http://www.cmake.org/]], for Mac & Linux support. http://www.chadvernon.com/blog/maya/compiling-maya-plug-ins-with-cmake/ ---- Also see: *[[Remote debugging with Visual Studio]]

Starting with Maya 2012 Hotfix 1, enhancements were made to Python scripting with the new 'Maya Python API 2.0'. [[Maya 2015 Docs|http://help.autodesk.com/view/MAYAUL/2015/ENU/?guid=__py_ref_index_html]] The new api modules are found in the {{{maya.api}}} package. For example, here is the 'old way' to import {{{OpenMaya}}}: {{{ import maya.OpenMaya as om print type(om.MDagPath()) # <class 'maya.OpenMaya.MDagPath'> }}} And the new 'api' way: {{{ import maya.api.OpenMaya as om2 print type(om2.MDagPath()) # <type 'OpenMaya.MDagPath'> }}} As you can see, the 'old way' typed instances as objects, but the new way types them as physical new types. I've also noticed that it looks like the api objects are no longer being wrappered via ''swig'' objects: Calls to {{{someSwigObject.disown()}}} that worked in 2010 will fail on 2012 raising a nice exception: {{{ # AttributeError: 'PyCObject' object has no attribute 'disown' # }}} This isn't necessarily a result of API 2.0, but it does have a coincidence in timing.... It should be noted that in 2012 the whole API hadn't been ported over, but is much more robust in 2015. Here are the list of advantages they post: *Array types are full Python sequences, including slice support. *Methods which take Maya array parameters will usually also take native Python sequences, such as arrays and tuples. *Exceptions are made in some case for performance reasons. *The outputs of methods are usually returned in their return values, not through their parameter lists. Exceptions are made in some cases for performance reasons. *Methods which return multiple values (e.g. ~MFnFluid.getResolution) return them as a tuple or list, eliminating the need for ~MScriptUtil. *Object attributes are preferred over rather than set/get methods. For example you can now write {{{array.sizeIncrement=64}}}. *There are more types of exceptions used when methods fail. Not everything is a ~RuntimeError, as was the case in the old API. *The new API is generally faster than the old. Up to three times faster in some cases.

Nice informative overview: http://discourse.techart.online/t/maya-api-file-translators-openmaya-vs-c-speeds/10293

I recently ran into the problem of trying to query a 'double array' attr via the API. In the below example, I create a "doubleArray" attr via commands on a node, then try to query it via the API. {{{ import maya.cmds as mc import maya.OpenMaya as om node = 'pSphere1' attr = "doubleArrayTest" #--------------------------- # Via cmds, add the attr to our node: mc.addAttr(node, longName=attr, dataType='doubleArray') mc.setAttr('%s.%s'%(node,attr), (2, 3.14159, 2.782), type="doubleArray") print mc.getAttr('%s.%s'%(node,attr)) # [2.0, 3.14159, 2.782] print mc.getAttr("%s.%s"%(node,attr), type=True) # doubleArray #----------------------- # Now, in the API: selList = om.MSelectionList() selList.add(node) mObject = om.MObject() selList.getDependNode(0, mObject) plug = om.MFnDependencyNode(mObject).findPlug(attr) print plug.name() # pSphere1.doubleArrayTest # So, the API is getting confused: print plug.isArray() # False print plug.numElements() # // Error: Encountered exception: (kFailure): Data type is not valid here // indexArray = om.MIntArray() plug.getExistingArrayAttributeIndices(indexArray) # // Error: Encountered exception: (kFailure): Object does not exist // # Let's try something else: # Get val as an MObject (say whaaa?!) plugValObj = plug.asMObject() # Create a function to act on that object: fnDoubleArray = om.MFnDoubleArrayData(plugValObj) # Get just the array data: doubleArray = fnDoubleArray.array() print doubleArray #[2.0, 3.14159, 2.782] # Finally! }}} ---- Docs: *[[MFnDoubleArrayData|http://docs.autodesk.com/MAYAUL/2014/ENU/Maya-API-Documentation/index.html?url=cpp_ref/class_m_fn_double_array_data.html,topicNumber=cpp_ref_class_m_fn_double_array_data_html]] *[[MFnDependencyNode|http://docs.autodesk.com/MAYAUL/2014/ENU/Maya-API-Documentation/index.html?url=cpp_ref/class_m_fn_dependency_node.html,topicNumber=cpp_ref_class_m_fn_dependency_node_html]] *[[MPlug|http://docs.autodesk.com/MAYAUL/2014/ENU/Maya-API-Documentation/index.html?url=cpp_ref/class_m_plug.html,topicNumber=cpp_ref_class_m_plug_html]] ---- Also see: *[[API: Attribute Creation & Usage]] *[[API: How can I query and set an attribute?]]

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): * [[MItSelectionList|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_selection_list_html]] : Iterate over the items in the selection list. !!!All Nodes: * [[MItDependencyNodes|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_dependency_nodes_html]] : Use the dependency node iterator to traverse all the nodes in Maya's Dependency Graph. !!!Node Hierarchies: *[[MItDag|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_dag_html]] : Use the DAG iterator to traverse the DAG (parent/child relationships) !!!Node Connections: *[[MItDependencyGraph|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_dependency_graph_html]] : Iterate over Dependency Graph (DG) Nodes or Plugs starting at a specified root Node or Plug. !!!Animation: * ~OpenMayaAnim.[[MItKeyframe|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_keyframe_html]] : Iterate over the keyframes of a particular Anim Curve Node, and query and edit the keyframe to which the iterator points. !!!Components: *[[MItGeometry|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_geometry_html]] : 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|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_curve_c_v_html]] : Iterator class for NURBS curve control vertices (~CVs). The iteration can be for a given curve or for a group of ~CVs. *** [[MItSurfaceCV|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_surface_c_v_html]] : NURBS surface CV iterator. ** Mesh: *** [[MItMeshEdge|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_mesh_edge_html]] : Edge iterator for polygonal surfaces. *** [[MItMeshFaceVertex|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_mesh_face_vertex_html]] : The iterator for face vertices on polygonal surfaces *** [[MItMeshPolygon|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_mesh_polygon_html]] : This class is the iterator for polygonal surfaces (meshes). It iterates over their //faces//. *** [[MItMeshVertex|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_mesh_vertex_html]] : Class iterator for polygonal vertices. !!!References/Assemblies: * [[MItEdits|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_edits_html]] : Use the edits iterator to traverse all the edits on a reference or assembly. !!!Particles: *[[MItInstancer|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_it_instancer_html]] : 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|http://help.autodesk.com/view/MAYAUL/2016/ENU/?guid=__cpp_ref_class_m_iterator_type_html]] : 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: * [[API : Understanding component level looping, and MObjects]] {{{ 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 }}}

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]]

{{{ # Python code import maya.OpenMaya as om import maya.OpenMayaAnim as oma def getSkinCluster(shape): """ shape : string : name of shape node to query skincluster on return : MFnSkinCluster : MFnSkinCluster node assigned to the mesh, or None. """ # Create an MDagPath for our shape node: selList = om.MSelectionList() selList.add(shape) mDagPath = om.MDagPath() selList.getDagPath(0, mDagPath) # Make a dependency graph iterator, passing in our MDagPath as the root of the # system. Set the Direction to 'From source to destination' and Level to be # 'Visit each Plug at most once' mItDependencyGraph = om.MItDependencyGraph(mDagPath.node(), om.MItDependencyGraph.kDownstream, om.MItDependencyGraph.kPlugLevel) # Start walking through our shape node's dependency graph: while not mItDependencyGraph.isDone(): # Get an MObject for the current item in the graph: mObject = mItDependencyGraph.currentItem() # If the MObject can have a MFnSkinCluster function applied, then it must # be a skincluster: if mObject.hasFn(om.MFn.kSkinClusterFilter): # return the MFnSkinCluster object for our MObject: return oma.MFnSkinCluster(mObject) mItDependencyGraph.next() }}} {{{ shape = 'someNodesShape' sCluster = getSkinCluster(shape) # Print the name of the skincluster: print sCluster.name() # skinCluster14 }}} The above example is based on info I found in this thread: http://groups.google.com/group/python_inside_maya/browse_thread/thread/1b865f8c3c0c81c2 And did a re-write on.

''~OpenMaya Python'': {{{ import maya.OpenMaya as om # Make a MSelectionList container object: selList = om.MSelectionList() # Fill our container object with the active selection: om.MGlobal.getActiveSelectionList(selList) # Make a list to gather the results: sel = [] # Fill the result list with strings of the selection: selList.getSelectionStrings(sel) print sel }}} Man, that is clunky! :-P Compared to: ''Python'': {{{ import maya.cmds as mc sel = mc.ls(selection=True) print sel }}} ''MEL'': {{{ string $sel[] = `ls - selection`; print $sel; }}}

When dealing with the API, all linear '//internal units//' are held in cm (unless overridden, but I've never seen this happen). But if you're passing that data to mel/Python commands, they expect the values to be in whatever '//ui unit//' has been set. By default, the ui unit is cm as well, but many studios will change this value to something else. In my case, it's currently inches... If these two values line up you won't notice any problems in your code. But if you author code that expects the ui units to be cm and they're not, chaos will ensue. In the below example, we grab the center-point of the bounding-box of a node, then convert that position into the current ui-units: {{{ import maya.OpenMaya as om node = 'pSphere1' # Get the MDagPath for a node: selList = om.MSelectionList() # MSelectionList selList.add(node) mDagPath = om.MDagPath() # MDagPath selList.getDagPath(0, mDagPath) # Find the centerpoint based on bounding box, this will be in cm: dagNodeFunc = om.MFnDagNode(mDagPath) # MFnDagNode boundingBox = dagNodeFunc.boundingBox() # MBoundingBox centerPoint = boundingBox.center() # MPoint #----------------------- # Now that we have some data, convert it from internal to ui units: # Convert from cm to current units: center = [] unitType = om.MDistance.uiUnit() # Get the current UI unit: for i in range(3): distance = om.MDistance(centerPoint[i]) # MDistance, as cm converted = distance.asUnits(unitType) # double, converted center.append(converted) print center }}} ---- Also see: *[[API: How can I find the working units?]] *[[API : Converting from internal units to ui (and back again)]]

The below classes compare with the mel {{{currentUnit}}} command. The below classes have the ability to query both the //internal// units, and the //ui// units (except {{{MTime}}}). The internal units, while they can be changed, usually shouldn't be. Defaults for internal units are: *Linear : Centimeters *Angular : ? Mine comes up as {{{kInvalid}}}, which is odd. I'd expect it to be Radians though. *Time : Has no differentiation between internal\ui: There is only ui units. I think when Maya installs this is 24fps (film). UI units are the ones you can change via Maya's prefs, or via mel. !!!Linear: [[OpenMaya.MDistance|http://download.autodesk.com/us/maya/2010help/api/class_m_distance.html]] {{{ import maya.OpenMaya as om uiLinearUnit = om.MDistance.uiUnit() }}} This returns an int value that corresponds to the {{{Unit}}} enum on the {{{MDistance}}} class. Which corresponds to these constants: | 1 | kInches | | 2 | kFeet | | 3 | kYards | | 4 | kMiles | | 5 | kMillimeters | | 6 | kCentimeters | | 7 | kKilometers | | 8 | kMeters | !!!Angular: [[OpenMaya.MAngle|http://download.autodesk.com/us/maya/2010help/API/class_m_angle.html]] {{{ import maya.OpenMaya as om uiAngularUnit = om.MAngle.uiUnit() }}} This returns an int value that corresponds to the {{{Unit}}} enum on the {{{MAngle}}} class. Which corresponds to these constants: | 1 | kInvalid | | 2 | kRadians | | 3 | kDegrees | | 4 | kAngMinutes | | 5 | kAngSeconds | | 6 | kLast | !!!Time: [[OpenMaya.MTime|http://download.autodesk.com/us/maya/2010help/api/class_m_time.html]] {{{ import maya.OpenMaya as om uiTimeUnit = om.MTime.uiUnit() }}} This returns an int value that corresponds to the {{{Unit}}} enum on the {{{MTime}}} class. There are a lot of constant values, check the [[docs|http://download.autodesk.com/us/maya/2010help/api/class_m_time.html#ffadecde942c8f44b9ec1ce62aa9da51]] for the specifics. ---- Also see: *[[API : Converting from internal units to ui (and back again)]] *[[API: How can I convert from linear internal units to ui units?]]

(Referenced from 'Complete Maya Programming') Waaaay exciting! It should be noted that any time you use API calls outside of a plugin to modify the DG, you can't undo the operation. {{{ # Python code import maya.OpenMaya as om }}} {{{ # optionA: transFn = om.MFnTransform() transObj = transFn.create() name = transFn.name() }}} {{{ # optionB: transFn = om.MFnTransform() transObj = transFn.create() # Illustrating inheritance: dagFn = om.MFnDagNode(transObj) name = dagFn.name() }}} {{{ print name # transform1 }}} Class hierarchy: *{{{MFnBase}}} **{{{MFnDependencyNode}}} ***{{{MFnDagNode}}} ****{{{MFnTransform}}}

Newer docs here: *[[PySide : Access Qt .ui widget data in Maya]] *[[PySide : Convert a Maya control into a widget]] ---- Starting with Maya 2011 they introduced a new API class [[MQtUtil|http://download.autodesk.com/global/docs/mayasdk2012/en_us/cpp_ref/class_m_qt_util.html]]. Notes from the docs: <<< The safest way to use the Qt API from within Maya is to create your own Qt window and populate it with your own controls. While it is possible to use the Qt API to modify existing Maya UI elements, such as those created using Maya commands from MEL or Python, such modifications are not supported by Autodesk and could lead to Maya becoming unstable or inoperable. In practice, you will likely find a number of modifications which appear safe, such as changing a control's text or reorganizing the items on a menu. However, Autodesk provides no guarantees that the underlying implementations of those UI elements won't change from one release of Maya to another, potentially in ways that may make formerly safe usage become unsafe. So if you choose to incorporate such actions into your plug-in be aware that you may have to modify your code in future versions of Maya. <<< Here is a very simple example using it: {{{ import maya.cmds as mc import maya.OpenMayaUI as omui # Create the window: class App(object): def __init__(self): self.name = "tempWin" if mc.window(self.name, exists=True): mc.deleteUI(self.name) self.window = mc.window(self.name, resizeToFitChildren=True) self.rootLayout = mc.columnLayout(adjustableColumn=True, columnAttach=('both', 5)) self.button = mc.button("awesomeButton", label="this is an awesome button") mc.showWindow() # Display window, capture an instance: app = App() butQtClasses = mc.objectTypeUI(app.button, superClasses=True) qwidget = omui.MQtUtil.findControl(app.button) print app.button, butQtClasses print qwidget, type(qwidget) }}} prints: {{{ tempWin|columnLayout6|awesomeButton [u'QPushButton', u'QAbstractButton', u'QWidget', u'QObject'] _b056e53200000000_p_QWidget <type 'PySwigObject'> }}} From here, you can see that the Qt widget has been wrapped in a Python 'swig' object.

Notes, notes notes... window data via the API. ---- from {{{maya.OpenMayaUI}}}: *{{{M3dView}}} : Main class used to access window info. *{{{MDrawInfo}}} : used in the draw methods of {{{MPxSurfaceShapeUI}}} **{{{MSelectInfo}}} : used in {{{MPxSurfaceShapeUI::select}}} ---- from {{{maya.OpenMayaMPx}}} *{{{MPx3dModelView}}} : Creates {{{modelEditor}}}s. *{{{MPxModelEditorCommand}}} : Creates commands for {{{modelEditors}}}. *{{{MPxControlCommand}}} *{{{MPxUIControl}}} **{{{MPxUITableControl}}} *{{{MPxSurfaceShapeU}}} *{{{MPxGlBuffer}}} ---- Query the current camera for the active view, top left corner of viewport, and viewport width\height. Similar stuff to what you can do with the window mel command. {{{ import maya.OpenMayaUI as omui import maya.OpenMaya as om camPath = om.MDagPath() activeView = omui.M3dView.active3dView() activeView.getCamera(camPath) camName = camPath.fullPathName() # c++ pointer hoop-jumping: xUtil = om.MScriptUtil() xUtil.createFromInt(0) xPtr = xUtil.asIntPtr() yUtil = om.MScriptUtil() yUtil.createFromInt(0) yPtr = yUtil.asIntPtr() activeView.getScreenPosition(xPtr, yPtr) x = om.MScriptUtil.getInt(xPtr) y = om.MScriptUtil.getInt(yPtr) pw = activeView.portWidth() ph = activeView.portHeight() print camName, "- Top Left:", x, y," - width/height:", pw, ph # |persp|perspShape - Top Left: 405 45 - width/height: 701 1060 }}}

Mel has the {{{polyColorPerVertex}}} command, that will change the color of one vertex at a time. This works fine you're doing it on less than 100 verts at a time. But on more than 1000, it really starts to slow down. Enter the API. The {{{MFnMesh}}} class has a {{{setVertexColors}}} method which allows you to set multiple colors at once. And it is //much// faster. Pseudo code to use it: {{{ import maya.OpenMaya as om # Build an empty vertex ID array: idArray = om.MIntArray() # Now fill it with the vert ID's on the object to color. # Could be some, or all of them. # Build an empty color array: colorArray = om.MColorArray() # Now fill it with the colors for each of the vert ID's # defined above. # Get a MDagPath for the object we're coloring: selList = om.MSelectionList() selList.add(myObject) mDagPath = om.MDagPath() selList.getDagPath(0, mDagPath) # Get a MFnMesh for our object: mFnMesh = om.MFnMesh(mDagPath) # Apply the colors: mFnMesh.setVertexColors(colorArray, idArray) }}} It should be noted that since you're using the API to modify the scene graph, there is no undo available. To get undo, you'd need to author this as a scripted plugin command.

Several subjects below, here's what we have: #Overview of API ~Attribute-Related Concepts #Attribute Property Defaults #Overview of API attribute creation classes #Creation #Example Usage #Differences between 'compound' and 'array' #Understanding Array Indices (physical & logical) #Networked and non-networked plugs #Additional examples ---- ''Important note'': In Maya, the term 'attribute' can mean two different things based on where it's used: either the 'user side' or the 'programmer side': *On the user side, they interact with attributes on nodes, querying\setting their values, keyframing them, etc. The only point of entry is "the attribute". The attribute 'has a value', for example. The value and the attribute go hand in hand. *On the programmer side, an 'attribute' is: **Quoted from 'Complete Maya Programming': "...a template or blueprint for how a piece of data in the node should be //created//. The important distinction from the user's perspective is that the attribute doesn't actually hold any data. It simply provides a specification for the data. Given this specification, the actual data is created.". **Basically, it's a description for the type of data that can be stored, but that's only part of the equation (one of four main parts). The next section describes the four areas that are required for data storage\retrieval on a node in the API. !!!Overview of API ~Attribute-Related Concepts: Sort of in order of data-flow (presuming you're doing value assignment, rather than query): *''Plugs'': **A plug is an instance of an attribute on a node. **They allow you to get and set data, make connections, lock attributes, etc. **Following the house analogy from above, a plug is like a gate-keeper: It can lock the gate, pass data from outside the gate to inside the gate (and vice-versa), and even connect gates between two different houses together. **They are represented as [[MPlug|http://download.autodesk.com/us/maya/2010help/API/class_m_plug.html]] and [[MPlugArray|http://download.autodesk.com/us/maya/2010help/API/class_m_plug_array.html]] objects. **They can be created & queried via [[MFnDependencyNode|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_dependency_node.html]] (& its descendants), queried via [[MAnimUtil|http://download.autodesk.com/us/maya/2010help/API/class_m_anim_util.html]], are passed as an argument to {{{MPxNode.compute()}}}, and additionally manipulated via [[MDgModifier|http://download.autodesk.com/us/maya/2010help/API/class_m_d_g_modifier.html]]. *''Attributes'': **Attributes in the API define the name and type of data a node can store. **Attributes themselves don't store data, they define what type of data can be stored. **Analogies help: Picture a house as a representation of a node. Each attribute is represented as a gate around the house: Only if a package can 'fit through a certain gate' can it be allowed into the house. Each gate defines access to one type of 'package', but it itself doesn't store the package. **API attributes differ from user-interaction in Maya on a node. When in Maya you execute "{{{setAttr sphere02.translsateX 3;}}}" it feels like you've set the {{{translateX}}} attribute to the value of {{{3}}}. But behind the scenes, it's not being stored that way: The {{{translateX}}} attribute is simply the gate through which you've squeezed your numeric package. Where that value actually lives is discussed below. **They are represented as [[MObject|http://download.autodesk.com/us/maya/2010help/API/class_m_object.html]] objects, and created\manipulated (at time of creation) via [[MFnAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_attribute.html]] and descendant classes. *''Data Handles'': **When a node is computing data (in its {{{compute()}}} method) and needs to access data in its data block, it gains that access through a 'data handle'. **Data handles allow you to query and set data living in a data block, as defined by a given attribute. **Data handles can't make connections between attributes or lock them (for example), they only query\set data. But because of this they can operate much faster than plugs. In addition, they can query a 'dirty' attribute without forcing a recompute of the DG which can allow for even greater optimization. **Following the analogy, a data handle is like a butler who can put data in storage (received from the plug), and take data out of storage, passing it to the plug. **They are represented as [[MDataHandle|http://download.autodesk.com/us/maya/2010help/API/class_m_data_handle.html]] and [[MArrayDataHandle|http://download.autodesk.com/us/maya/2010help/API/class_m_array_data_handle.html]] objects. They are created via [[MDataBlock|http://download.autodesk.com/us/maya/2010help/API/class_m_data_block.html]]s. *''Data Blocks'': **The data block is the location in the node where the attribute values are stored. **Whenever a new instance of a node is created, a new data block is created for it. **Using the house analogy, the data block is the store-room of the house where all the packages are stored. The butler can put stuff in and take it out. **They are represented as [[MDataBlock|http://download.autodesk.com/us/maya/2010help/API/class_m_data_block.html]] objects, and passed to the {{{MPxNode.compute()}}} method as an argument: That's the only way (I'm aware of) you can access them. Another way to visualize the analogy: | Plug | Attribute | Data Handle | Data Block | | Gate Keeper | The Gate | Butler | Storeroom | *Imagine that a node is a house. *The gate keeper (plug) receives packages (data), can lock\unlock the gate, let the packages pass through the gate (if they fit) to the butler, magically connect this gate to the gate on another house (so that they share packages), or get packages from the butler. *The gate itself (attribute) limits what type of packages are allowed into the house (or what type of package is retrieved from it). If the package doesn't fit, an alarm (error) goes off. *Presuming the package (data) fits through the gate (attribute), if the gatekeeper wants the package put in the house (or wants to get a packaged stored in the house), he needs to have the butler (data handle) do it for him. *All packages are kept in the storeroom of the home (data block), which the butler knows a quick path to. *Finally, the gate keeper can have direct access to the storeroom if he's tricky (but he's slower than the butler), and if you slip the butler a $20 (and you sneak in via {{{compute()}}}) you can access the storeroom directly. So you could say: *A package (data) is given to the gatekeeper (plug). Since it fits through the gate (attribute), the gatekeeper passes it to the butler (data handle). The butler than puts it in the storeroom (data block). ---- ---- ---- !!!Attribute Property Defaults When a new attribute is created, these are the default states of its various properties. They are modifiable via [[MFnAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_attribute.html]] (attribute superclass). *Readable. *Writable. *Connectable. *Storable. *Cached. *Not arrays. *Have indices that matter. *Do not use an array builder. *Not keyable. *Not hidden. *Not used as colors. *Not indeterminant. *Set to disconnect behavior kNothing. !!!Overview of API attribute creation classes: All of these inherit from [[MFnBase|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_base.html]] *[[MFnAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_attribute.html]] : Used for changing the attribute defaults listed above (among others). **[[MFnCompoundAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_compound_attribute.html]] : For the creation of 'compound' attributes: Attributes that can store multiple different data types. **[[MFnEnumAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_enum_attribute.html]] : For the creation of 'enum' attribute types. **[[MFnGenericAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_generic_attribute.html]] : Creation of attrs that can accept specific data types as defined by [[MFnData|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_data.html]]. Similar but different from {{{MFnTypedAttribute}}}, see docs [[here|http://download.autodesk.com/global/docs/mayasdk2012/en_us/index.html?url=files/Technical_Notes_Generic_Attributes.htm,topicNumber=d28e16031]] **[[MFnLightDataAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_light_data_attribute.html]] : For the creation of 'light data' attribute types. **[[MFnMatrixAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_matrix_attribute.html]] : For the creation of 'matrix' attribute types. **[[MFnMessageAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_message_attribute.html]] : For the creation of 'message' attribute types. **[[MFnNumricAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_numeric_attribute.html]] : For all 'numric' attribute types as defined by [[MFnNumricData|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_numeric_data.html]]. These include boolean, byte, character, short 2short, 3short, int, 2int, 3int, long, 2long, 3long, float, 2float, 3float, double, 2double, 3double, 4double, and finally 'color' and 'point'. **[[MFnTypedAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_typed_attribute.html]] : Creation of attrs that can accept specific data types as defined by [[MFnData|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_data.html]]. These include: numeric (based on [[MFnNumricData|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_numeric_data.html]]), plugin, pluginGeometry, string, matrix, stringArray, doubleArray, intArray, pointArray, vectorArray, componentList, mesh, lattice, nurbsCurve, nurbsSurface, sphere, dynArrayAttrs, dynSweptGeometry, subdSurface, nObject. **[[MFnUnitAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_unit_attribute.html]] : For creation of attributes that store angle, distance, and time. [img[http://download.autodesk.com/us/maya/2010help/API/class_m_fn_attribute__inherit__graph.gif]] !!!Creation: Placeholders for the node's attributes are initially added as a class-attribute for easy access later. At this point, then can be filled with {{{MObject}}}s (since that's what they'll be ultimately), or just be filled with {{{None}}} since at this point they're not used. {{{ import maya.OpenMaya as ompx class Foo(ompx.MPxNode): attr_someInput = om.MObject() # or None attr_someOutput = om.MObject() # or None }}} They are actually created and added to the node inside the plugin's 'initializer' classmethod (or external function. We'll use classmethod below). For each attr, they go through one or more of these steps: #Creation : An attribute is created. You can imagine it just floating in space... #Modification : After creation, you configure how it should behave. #Attach to node : Take it from floating in space, and actually attach it to a specific node. #Defining affects relationship : Set if it affects any other attribute. ''Special note'': This step must occur after any affected attributes have already been attached to the node (via {{{MPxNode.addAttribute()}}}). {{{ @classmethod def nodeInitializer(cls): # Create the function object that will create the attributes: mfnNumericAttribute = om.MFnNumericAttribute() # 1. Creation: cls.attr_someInput = mfnNumericAttribute.create("someInput", "si", om.MFnNumericData.kFloat) # 2. Modification: mfnNumericAttribute.setChannelBox(True) # default is False mfnNumericAttribute.setKeyable(True) # default is False # 3. Attach to node: cls.addAttribute(cls.attr_someInput) # 1. Creation: cls.attr_someOutput = mfnNumericAttribute.create("someOutput", "so", om.MFnNumericData.kFloat) # 2. Modification: mfnNumericAttribute.setWritable(False) # Default is True. This is an output, can't write to it. mfnNumericAttribute.setStorable(False) # Default is True. Do not save value with scene, since it's an output. # 3. Attach to node: cls.addAttribute(cls.attr_someOutput) # 4. Affects relationships for "someInput" attr. This needs to be executed after # the "someOutput" attr was added to the node. cls.attributeAffects(cls.attr_someInput, cls.attr_someOutput) # 4. Affects relationships for "someOutput": # None, this is an output }}} ---- Another attribute type to make is a numric type with children. A transforms {{{.translate}}} attribute illustrates this: There is a root 'translate' attribute you can set, connect to, etc. But in addition, you can set\connect to its individual children as well: {{{ translate : float 3 --> translateX : float --> translateY : float --> translateZ : float }}} How can you set this up in the API? You first create each of the child attributes, and then, when creating the parent, you pass them as a creation argument. Here's a simple example snippet: {{{ @classmethod def nodeInitializer(cls): mfnNumericAttribute = om.MFnNumericAttribute() # Create the children attrs: cls.attr_transX = mfnNumericAttribute.create("translateX", "tx", om.MFnNumericData.kFloat) cls.attr_transY = mfnNumericAttribute.create("translateY", "ty", om.MFnNumericData.kFloat) cls.attr_transZ = mfnNumericAttribute.create("translateZ", "tz", om.MFnNumericData.kFloat) # Now create the parent attr by passing in the children: cls.attr_trans = mfnNumericAttribute.create("translate", "t", cls.attr_transX, cls.attr_transY, cls.attr_transZ) mfnNumericAttribute.setChannelBox(True) mfnNumericAttribute.setKeyable(True) cls.addAttribute(cls.attr_trans) }}} Some things to note: *The {{{MFnAttribute}}} docs say "This form of the create method allows the creation of compound attributes out of numeric attributes." So, even though we build using a {{{MFnAttribute}}}, it ends up being {{{MFnCompoundAttribute}}}? (I've yet to figure out what's going on here). **When making compound attrs, their children all need to be added to to the class via {{{cls.addAttribute()}}}. However, in the examples I've seen, when making 'child array attrs', they //don't// need to be added that way: only their parent does (like in the above example). *You modify the parents parameters ({{{setChannelBox}}}, etc) not the children, since the children inherit the parameters. *By passing in three {{{kFloat}}} children, it implies that the {{{someInput}}} attr is now a {{{k3float}}}. If you didn't care about the child attributes, you could simply create the attribute this way: {{{ @classmethod def nodeInitializer(cls): mfnNumericAttribute = om.MFnNumericAttribute() cls.attr_trans = mfnNumericAttribute.create("translate", "t", om.MFnNumericData.k3Float) mfnNumericAttribute.setChannelBox(True) mfnNumericAttribute.setKeyable(True) cls.addAttribute(cls.attr_trans) }}} So you can still manipulate {{{translate}}} as you're used to, but you no longer gain gain access to the children, like {{{translateX}}}. !!!Example Usage: The attrs are accessed inside the {{{compute()}}} method. Take note of a few things: #First there is a query if the given input plug is an instance of the attribute that needs computing. #Next, a data handle based on that instanced attribute is generated pointing inside of the data block. #Work is done on the data. #Finally, another data handle is created pointing to the data defined by the instanced output attribute, the output data is updated, and the input plug is set to clean. {{{ def compute(self, plug, dataBlock): """ This is an overridden method of the MPxNode class. Does the "work" the node is to perform. Parameters: plug : MPlug : http://download.autodesk.com/us/maya/2010help/API/class_m_plug.html dataBlock : MDataBlock : http://download.autodesk.com/us/maya/2010help/API/class_m_data_block.html """ # Check that the requested recompute is our output value if (plug == Foo.attr_someOutput): # Read the input values, returns a MDataHandle, which is a smart pointer # back into the MDataBlock (dataBlock) # http://download.autodesk.com/us/maya/2010help/API/class_m_data_handle.html dataHandle = dataBlock.inputValue(Foo.attr_someInput) # Compute the output values. In this case, it is a simple mult operation: outVal = dataHandle.asFloat() * 10 # Get a handle to the output value and store the new value. handle = dataBlock.outputValue(Foo.attr_someOutput) handle.setFloat(outVal) # From the docs: Tells the dependency graph that the given attribute # has been updated and is now clean. This should be called after the # data in the plug has been recalculated from the inputs of the node. dataBlock.setClean(plug) else: # c++ requires this return, it seems that the Python API doesn't # based on my experiments. Doesn't hurt to leave it though. return om.MStatus.kUnknownParameter }}} !!!Differences between 'compound' and 'array' *''compound'' is an *attribute type*, like float, string, double etc. You can't have a "compound float" attribute in the same way you can't have a "string double". But you can have a compound attr that has child string, double, and float attributes. Compound attributes themselves store no values: They are simply parents of other attribute types. **Compound attributes are considered 'parents', while they contain 'child' attributes. **The child of a compound attribute can be any other attribute type, including another compound attribute, which has children (which could be compound attributes, etc). Examples of this are the mesh node's {{{colorPerVertex}}} compound attribute. It has a child compound attribute {{{vertexColor}}}, which has a child compound attribute {{{vertexFaceColor}}}. *''array'' (also known as 'multi' when being created via mel, I think...) is a *property of an attribute*, like being readable, writable, keyable, etc. In theory any attribute type can be made array, *including compound attrs*. **An example of this is a mesh node's {{{uvSet}}} attr: It is a compound attr, but is //also an array//, which gets confusing fast when trying to access it and its children. **Array attributes contain multiple 'element attributes', one for each index in the array. These in turn can be any type, including compound, which in turn could also be array, etc. **Array elements are not 'children attributes', since only compound attrs have official 'children'. Array attributes are a single attr, that holds multiple values in a list. !!!Understanding Array Indices (physical & logical) Given an attribute that is also array, you can reference its elements two different ways, via the "physical indices" and the "logical indices". *''Physical index'' : Range from 0 -> {{{numElements()}}}-1. Given four plugs for elements A, B, C, and D, A is index 0, B1, C2, D3. If plug B was deleted, now: A0, C1, D2: As you can see, the physical index for a given plug can change based on creation and deletion. *''Logical index'' : For a given element, this is an assigned\fixed\absolute index that will never change regardless of creation or deletion of other indices. You can use the plugs {{{getExistingArrayAttributeIndices()}}} method to populate a {{{MIntArray}}} with the existing indices. **Referring to an array element in MEL uses the logical index. MEL can't get the physical index. **Connections between attributes are based on their *logical indices*. This is needed since the logical indices don't change (and you don't want connections to change after they've been made...). You can query these indices via {{{MPlug}}}. Below is some example code and results showing the differences between them. When calling to {{{elementByLogicalIndex()}}}, if the given index doesn't yet exist (it is a 'sparse array'), it is created and populated with a default value for that attribute. {{{ plg = myPlg.elementByLogicalIndex(2) plg.setDouble(11) plg = myPlg.elementByLogicalIndex(10) plg.setDouble(27) plg = myPlg.elementByLogicalIndex(0) plg.setDouble(100) }}} This would be the result of the physical \ logical indices: {{{ Physical 0 \ Logical 0 : 100 Physical 1 \ Logical 2 : 11 Physical 2 \ Logical 10 : 27 }}} !!!Networked and non-networked plugs I'll be honest, I really don't understand the ins and outs of these yet. But some notes: *''non-networked plug'' : user created plugs used to establish new connections to an attr, get or set a value on an attr. When one of these is used, a networked version of the plug is created and added to the dependency node network. A non-networked plug contains an array of array indices that plot the path from the root plug to this plug. *''networked plug'' : Dependency node plugs, can't be explicitely created: only referenced by users. They also describe the 'tree' of plugs indicating connections made to the attributes of the node. !!!Additional Examples *[[API: Simple scripted plugin node]] : A working overview of a bunch of what the above covers. *[[API: Find all child attributes under a compound attribute]] *[[API: Find all attributes & plugs on a node]]

Just some early notes... See a working example here: [[API: Simple scripted plugin argument passing]] Docs: *[[MSyntax|http://download.autodesk.com/us/maya/2010help/API/class_m_syntax.html]] *[[MArgParser|http://download.autodesk.com/us/maya/2010help/API/class_m_arg_parser.html]] **[[MArgDatabase|http://download.autodesk.com/us/maya/2010help/API/class_m_arg_database.html]] *[[MArgList|http://download.autodesk.com/us/maya/2010help/API/class_m_arg_list.html]] ---- A major issue I've ran into is the (apparent) lack of ability to pass array data into an argument. A thread here discusses it pretty well: http://forums.cgsociety.org/archive/index.php/t-701733.html It appears that the main hack is to pass in a single string you can then later split into the array items of your choice, which is //terrible//... From that form post: ''"MEL commands //don't// have the ability to accept a string array as a single flag argument."'', which seems to be true based on experimentation. ---- When authoring a scripted plugin command to accept arguments, you do this by by authoring a 'syntax' function that is passed to the {{{OpenMayaMPx.MFnPlugin.registerCommand()}}} method inside the {{{initializePlugin()}}} function. The syntax function can look something like this: {{{ import maya.OpenMaya as om def newSyntax(): syntax = om.MSyntax() # Start adding flags and whatnot here to pass your arguments to. }}} And the snippet for registering the command, which includes passing of the syntax ({{{cmdName}}} & {{{cmdCreator}}} being authored elsewhere): {{{ import maya.OpenMayaMPx as ompx def initializePlugin(mobject): mfnPlugin = ompx.MFnPlugin(mobject) mfnPlugin.registerCommand(cmdName, cmdCreator, newSyntax) }}} You can then capture the argument data in the {{{doIt()}}} method of the scripted plugin: {{{ import maya.OpenMayaMPx as ompx class MyCmd(ompx.MPxCommand): def __init__(self): ompx.MPxCommand.__init__(self) def doIt(self, argList): argData = om.MArgDatabase(newSyntax(), argList) }}} The {{{argList}}} parameter recieves an {{{MArgList}}} argument. You can then pass this arg into a {{{MArgDatabase}}} object, which is a subclass of {{{MArgParser}}}, or start accessing data in the {{{MArgList}}} directly.

Scratch-pad as I become more familiar with the various API classes. Also see: [[API: class organization]] ---- Starting with Maya 2013, they offered a [[API Class Taxonomy|http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/index.html?url=cpp_ref/_maya.html,topicNumber=cpp_ref__maya_html]] online, which is all classes arranged according to subject/concept. ---- This is mainly a place where I can note classes I've used, there are obviously more than what is listed here. !M Notes: *Maya's base utility classes. !!![[M3dView|http://download.autodesk.com/us/maya/2010help/API/class_m3d_view.html]] "provides methods for working with 3D model views. 3D views are based on OpenGL drawing areas" !!![[MAnimControl|http://download.autodesk.com/us/maya/2010help/API/class_m_anim_control.html]] "Control over animation playback and values" !!![[MAnimUtil|http://download.autodesk.com/us/maya/2010help/API/class_m_anim_util.html]] "...a static class which provides methods which determine if an object is being animated, which attributes are animated for a given object and which animation curves are used to animate a given attribute." *Methods include {{{isAnimated}}}, {{{findAnimatedPlugs}}}, {{{findAnimation}}} !!![[MBoundingBox|http://download.autodesk.com/us/maya/2010help/API/class_m_bounding_box.html]] "Implementation of a 3D bounding box" !!![[MColor|http://download.autodesk.com/us/maya/2010help/API/class_m_color.html]] "... used to store values of color attribute." !!![[MDagPath|http://download.autodesk.com/us/maya/2010help/API/class_m_dag_path.html]] "Provides methods for obtaining one or all Paths to a specified DAG Node..." *{{{node()}}} : returns an {{{MObject}}} *{{{fullPathName()}}} : Returns string of the full path to the node. *{{{isInstanced()}}} : Returns True\False. Use [[MFnDagNode|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_dag_node.html]] function set to operate on this type. See: *[[API: MObject and MDagPath]] !!![[MDGModifier|http://download.autodesk.com/us/maya/2010help/API/class_m_d_g_modifier.html]] "...is used to change the structure of the //dependency graph// (DG). This includes adding nodes, making new connections, and removing existing connections." *Only usable in scripted plugins. If you call to API commands and want to be able to undo them, you need execute those operations through this class. See this example [[API: undoing commands]]. *Used for node creation, deletion, attribute connection, disconnection, attribute addition, attribute removal, node renaming, mel execution, etc. >''[[MDagModifier|http://download.autodesk.com/us/maya/2010help/API/class_m_dag_modifier.html]]'' >Inherits from {{{MDGModifier}}} >"...used to change the structure of the DAG (subset of the DG, focusing on transforms\shapes). This includes adding nodes, making new connections, and removing existing connections. !!![[MDistance|http://download.autodesk.com/us/maya/2010help/API/class_m_distance.html]] "... provides a fundamental type for the Maya API to hold and manipulate linear data. All API methods that require or return distance information do so through variables of this type." *Great for converting from ui units to system units and vice-versa. !!![[MEulerRotation|http://download.autodesk.com/us/maya/2010help/API/class_m_euler_rotation.html]] "This class provides methods for working with euler angle rotations." !!![[MFileIO|http://download.autodesk.com/us/maya/2010help/API/class_m_file_i_o.html]] "Methods for opening, saving, importing, exporting, and referencing files." Also gives query methods for many data items as well (like the scene name, for example). *Closely mirrors functionality found in the mel {{{file}}} command. !!![[MGLFunctionTable|http://download.autodesk.com/us/maya/2010help/API/class_m_g_l_function_table.html]] "...is a utility class which provides wrappers for the basic functions in the OpenGL API" *An instance of this class can be obtained from [[MHardwareRenderer.glFunctionTable()| http://download.autodesk.com/us/maya/2010help/API/class_m_hardware_renderer.html]] !!![[MGlobal|http://download.autodesk.com/us/maya/2010help/API/class_m_global.html]] "Provide methods for selection, 3D-views, time, model manipulation and MEL commands." Many, many usable methods in here. *{{{deleteNode(MObject)}}} : Delete the given node. *{{{executeCommand(...)}}} : Has a variety of parameter signatures, executes a mel command. *{{{getActiveSelectionList(MSelectionList)}}} : Fill a {{{MSelectionList}}} with what is currently selected ({{{MObject}}}s). *{{{getFunctionSetList (MObject, MStringArray)}}} : Get a list of strings representing the function sets that will accept this object *{{{select(MObject)}}} : Put the given object on the active selection list. *{{{select(MDagPath, MObject) : Put the given object ({{{MDagPath}}}) and components ({{{MObject}}}) on the active selection list. *{{{selectByName(string)}}} : Puts objects that match the give name on the active selection list, can use regular expressions. *{{{setOptionVarValue(string, int)}}} : Set an optionVar with an int value. More similar commands for setting other data types. *{{{sourceFile(string)}}} : Sources a mel script. *{{{viewFrame(double)}}} : Sets the current frame. !!![[MImage|http://download.autodesk.com/us/maya/2010help/API/class_m_image.html]] "...provides access to some of Maya's image manipulation functionality." !!![[MImageFileInfo|http://download.autodesk.com/us/maya/2010help/API/class_m_image_file_info.html]] "...used to describe the characteristics of an image file, such as dimensions, channel count, and pixel format." !!![[MObject|http://download.autodesk.com/us/maya/2010help/API/class_m_object.html]] "The generic class for accessing all Maya internal modelling, animation and rendering Objects, collectively referred to as Model Objects, through the API. This includes all Dependency Graph (DG) Nodes, of which Directed Acyclic Graph (DAG) Nodes are a subset." *{{{isNull()}}} : Returns True\False on whether it is a valid {{{MObject}}} or not. *{{{hasFn(MFn.kSomeConstant)}}} : Query to determine if the {{{MObject}}} is comaptible with a given Function Set.function. Use [[MFnDependencyNode|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_dependency_node.html]] function set to operate on this type. See: *[[API: MObject and MDagPath]] !!![[MMatrix|http://download.autodesk.com/us/maya/2010help/API/class_m_matrix.html]] "A matrix math class for 4x4 matrices of doubles." !!![[MPlug|http://download.autodesk.com/us/maya/2010help/API/class_m_plug.html]] "A plug is a point on a dependency node where a particular attribute can be connected." *Similar to the mel commands {{{connectionInfo}}}, {{{isConnected}}}, {{{getAttr}}}, {{{setAttr}}} !!![[MPoint|http://download.autodesk.com/us/maya/2010help/API/class_m_point.html]] "This class provides an implementation of a point. Numerous convienence operators are provided to help with the manipulation of points. This includes operators that work with the {{{MVector}}} and {{{MMatrix}}} classes." !!![[MProgressWindow|http://download.autodesk.com/us/maya/2010help/API/class_m_progress_window.html]] "...manages a window containing a status message, a graphical progress gauge, and optionally a "Hit ESC to Cancel" label for interruptable operations." *This is like the mel {{{progressWindow}}} command. !!![[MQuaternion|http://download.autodesk.com/us/maya/2010help/API/class_m_quaternion.html]] "...provides methods for working with Quaternions" !!![[MScriptUtil|http://download.autodesk.com/us/maya/2010help/API/class_m_script_util.html]] "Utility class for working with pointers to basic types such as int, float and arrays of these types." *Used heavily by Python scripting in the API to make it jive with c++ syntax. *Some good notes [[HERE|http://www.chadvernon.com/blog/resources/maya-api-programming/mscriptutil/]]. !!![[MSelectionList|http://download.autodesk.com/us/maya/2010help/API/class_m_selection_list.html]] "A list of {{{MObject}}}s." *{{{add()}}} : Accepts strings (using wildcards), {{{MObject}}}, {{{MDagPath}}}, and {{{MPlug}}}. *{{{clear()}}} : Empty the selection list. *{{{getDagPath(int, MDagPath, MObject)}}} : For the given index, get the dag path {{{MDagPath}}} and component {{{MObject}}} (if present). *{{{getDependNode(int, MObject)}}} : Get the {{{MObject}}} at the given index. *{{{getPlug (int, MPlug)}}} : Get the plug (attribute) at the given index). *{{{getSelectionStrings(MStringArray)}}} : Gets the string representations of the items in the selection list. *{{{getSelectionStrings(int, MStringArray)}}} : Gets the string representations of the items in the selection list at the given index. *{{{length()}}} Returns the length of the list. !!![[MTime|http://download.autodesk.com/us/maya/2010help/API/class_m_time.html]] "Set and retrieve animation time values in various unit systems." !!![[MTransformationMatrix|http://download.autodesk.com/us/maya/2010help/API/class_m_transformation_matrix.html]] "...allows the manipulation of the individual transformation components (eg scale, rotation, shear, etc) of a four by four transformation matrix." !!![[MVector|http://download.autodesk.com/us/maya/2010help/API/class_m_vector.html]] "A vector math class for vectors of doubles." !~MFn Notes: *Wrappers to make accessing common object easier. 'Fn' = 'Function'. They wrapper "functionality". Any class with this prefix is a function set used to operate on {{{MObject}}}s of a particular type. *All {{{MFn}}} classes (except for {{{MFn}}} itself) inherit from [[MFnBase|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_base.html]]. The below hierarchy illustrates the class inheritance tree. *The //mel// command {{{nodeType}}}, via it's {{{apiType}}} flag can be used to query the {{{MFn}}} type of a DAG node, which can then be used to find what type of function set to use. *Bit of craziness: Since Maya stores the Python API in different packages (see [[API: class organization]]), it's possible that this inheritance can span multiple packages. For example, this is the inheritance tree for {{{MFnSkinCluster}}}, which as you'll see inherits from two different packages; {{{OpenMaya}}} and {{{OpenMayaAnim}}}: **{{{OpenMaya.MFnBase}}} (superclass) ***{{{OpenMaya.MFnDependencyNode}}} ****{{{OpenMayaAnim.MFnGeometryFilter}}} *****{{{OpenMayaAnim.MFnSkinCluster}}} (subclass) !!![[MFn|http://download.autodesk.com/us/maya/2010help/API/class_m_fn.html]] "{{{MFn}}} encapsulates all API Function Set type identifiers used for RTTI in the API." Meaning, the {{{MFn}}} class holds the constants ({{{MFn.k*}}}) that can be tested against to determine what type function objects can be attached to an {{{MObject}}}. Used with {{{MObject.hasFn()}}} !!![[MFnBase|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_base.html]] It has two useful methods: *{{{setObject(MObject)}}} that allows for an {{{MObject}}} to be assigned to the function set after it was created. *{{{object()}}}, which returns the {{{MObject}}} assigned to the function set. ---- >[[MFnAttribute|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_attribute.html]] >"Dependency node attribute function set." ---- >[[MFnComponent|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_component.html]] >"This is the base class for all function sets which deal with component objects. Components are [[MObjects|API: MObject and MDagPath]] which hold index information for shapes. Examples of these types are mesh vertices (single indexed), nurbs surface CVs (double indexed), and lattice points (triple indexed)." ---- >>[[MFnSingleIndexedComponent|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_single_indexed_component.html]] >>[[MFnDoubleIndexedComponent |http://download.autodesk.com/us/maya/2010help/API/class_m_fn_double_indexed_component.html]] >>[[MFnTripleIndexedComponent |http://download.autodesk.com/us/maya/2010help/API/class_m_fn_triple_indexed_component.html]] ---- >[[MFnDependencyNode|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_dependency_node.html]] >"...allows the creation and manipulation of dependency graph nodes ({{{MObject}}}). Traversal of the dependency graph is possible using the getConnections method." >* {{{MFnDependencyNode()}}} : Creation, no passed in object. >* {{{MFnDependencyNode(MObject)}}} : Creation, passing in an {{{MObject}}}. >* {{{create(string)}}} : (has other signatures, but this one is easiest) : ''Creates a new dependency node with the given type''. The new node is placed into the dependency graph. >* Many methods for node creation, getting connections, name setting, plug (attr) finding, attribute addition and removal, locking & unlocking, query if referenced, query parent namepace, query if name is unique, query if made via plug-in, and more... ---- >>[[MFnAnimCurve|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_anim_curve.html]] >>"Create, query and edit Anim Curve Nodes and the keys internal to those Nodes." >>*Many, many methods for interacting with animCurves. ---- >>[[MFnExpression|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_expression.html]] >>"...used to create, edit, and query expression nodes" ---- >>[[MFnGeometryFilter|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_geometry_filter.html]] >>"...the function set for geometry filters, the node that is the base class for deformers. Geometry filter nodes include ''clusters, ffds, nonlinears, user-defined deformers, sculpts, wires and blendShapes''. The purpose of the geometry filter is to connect to the geometry that is deformed. The geometry filter is independent of any algorithm that calculates the deformation." ---- >>>[[MFnSkinCluster|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_skin_cluster.html]] >>>"...the function set for skinClusters" ---- >>[[MFnDagNode|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_dag_node.html]] >>"Provides methods for attaching Function Sets to, querying, and adding children to DAG Nodes ({{{MDagPath}}}). Particularly useful when used in conjunction with the DAG Iterator class ({{{MItDag}}})." >>* {{{MFnDagNode()}}} : Creation with no dag path. >>* {{{MFnDagNode(MDagPath)}}} : Creation based on a dag path. >>*Many methods for querying parents, querying children, duplication, node creation, parenting, unparenting, etc. ---- >>>[[MFnMesh|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_mesh.html]] >>>"...provides access to polygonal meshes" ---- >>>[[MFnTransform|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_transform.html]] >>>"... provides access to transformation DAG nodes called transforms." >>>* Creation, transformation, value query, etc. ---- >>>>[[MFnIkHandle|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_ik_handle.html]] >>>>"This is the function set for inverse kinematics (IK) handles. An ik handle specifies the joints in a skeleton that are effected by an attached ik solver." ---- >>>>[[MFnIkJoint|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_ik_joint.html]] >>>>"...function set for joints." ---- >[[MFnData|http://download.autodesk.com/us/maya/2010help/api/class_m_fn_data.html]] >* "... is the parent class for all dependency graph data function sets. Conceptually, data objects are what flow through the connections in the dependency graph. Each node in the dependency graph has a data block associated with it. The data block holds the data objects for all of the node's attributes (see {{{MDataBlock}}}). The data block is only available during the compute method of a node. A data handle ({{{MDataHandle}}}) can be created to access a particular attribute's data inside of the data block." ---- >>[[MFnMatrixData|http://download.autodesk.com/us/maya/2010help/api/class_m_fn_matrix_data.html]] >>*"...allows the creation and manipulation of {{{MMatrix}}} data objects for use in the dependency graph." >>*This can be used //within user-created// nodes to access matrix data. !~MIt Notes: *Used for iterating though data (for looping through things). 'It' = 'Iterator'. They wrapper "iteration". These classes are iterators and work on {{{MObject}}}s similar to the way a function set ({{{MFn}}} classes) does. !!![[MItDag|http://download.autodesk.com/us/maya/2010help/API/class_m_it_dag.html]] "Use the DAG iterator to traverse the DAG either depth first or breadth first, visiting each node and, if desired, retrieving the node (as an {{{MObject}}})." See: *[[API: OpenMaya.MItDag]] !!![[MItDependencyGraph|http://download.autodesk.com/us/maya/2010help/API/class_m_it_dependency_graph.html]] "Iterate over Dependency Graph (DG) Nodes or Plugs starting at a specified root Node or Plug." See: *[[API: OpenMaya.MItDependencyGraph]] !!![[MItDependencyNodes|http://download.autodesk.com/us/maya/2010help/API/class_m_it_dependency_nodes.html]] "Use the dependency node iterator to traverse all the nodes in Maya's Dependency Graph." See: *[[API: OpenMaya.MItDependencyNodes]] !!![[MItGeometry|http://download.autodesk.com/us/maya/2010help/API/class_m_it_geometry.html]] "... 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." *{{{MItGeometry(MDagPath, MObject)}}} : Create a new object, passing in the path to the active node ({{{MDagPath}}}) and an {{{MObject}}} of the components to iterate over. *{{{index()}}} : Get the index of the current component. *{{{position(OpenMaya.MSpace.kWorld)}}} : Get the position of the current component as a {{{MPoint}}}. *{{{setPosition(MPoing)}}} : Set the position of the current point. !!![[MitMeshEdge|http://download.autodesk.com/us/maya/2010help/API/class_m_it_mesh_edge.html]] "...is the edge iterator for polygonal surfaces" !!![[MItMeshFaceVertex|http://download.autodesk.com/us/maya/2010help/API/class_m_it_mesh_face_vertex.html]] "...is the iterator for face vertices on polygonal surfaces." !!![[MItMeshPolygon|http://download.autodesk.com/us/maya/2010help/API/class_m_it_mesh_polygon.html]] "... is the iterator for polygonal surfaces (meshes)." *Good for querying or setting all verts on a mesh at once (for example) !!![[MItMeshVertex|http://download.autodesk.com/us/maya/2010help/API/class_m_it_mesh_vertex.html]] "...is the iterator for polygonal vertices." !!![[MItSelectionList|http://download.autodesk.com/us/maya/2010help/API/class_m_it_selection_list.html]] "Iterate over the items in the selection list." *{{{MItSelectionList(MSelectionList)}}} : Creation, based on a pre-existing {{{MSelectionList}}} *{{{getDagPath(MDagPath, MObject)}}} : Get the path to the current object ({{{MDagPath}}}) and a {{{MObject}}} representing any selected components. !!![[MItKeyframe|http://download.autodesk.com/us/maya/2010help/API/class_m_it_keyframe.html]] "Iterate over the keyframes of a particular Anim Curve Node..." !~MPx Notes: *Used for creating custom plugins. 'Px' = 'Proxy'. They are API classes designed for you to derive from and create your own object types. !!![[MPxCommand|http://download.autodesk.com/us/maya/2010help/API/class_m_px_command.html]] "This is the proxy class for creating MEL commands through the API." !!![[MPxNode|http://download.autodesk.com/us/maya/2010help/API/class_m_px_node.html]] "Base class for user defined dependency nodes."

Nice simple example copied from here: https://forums.autodesk.com/t5/maya-programming/create-mesh-from-list/td-p/7575371 {{{ # using Python API 2.0 for Maya import maya.api.OpenMaya as om2 meshFn = om2.MFnMesh() # list of vertex points vertices = [om2.MPoint(-0.5, -0.5, 0.5), om2.MPoint(0.5, -0.5, 0.5), om2.MPoint(0.5, 0.5, 0.5), om2.MPoint(-0.5, 0.5, 0.5), om2.MPoint(-0.5, 0.5, -0.5), om2.MPoint(0.5, 0.5, -0.5), om2.MPoint(0.5, -0.5, -0.5), om2.MPoint(-0.5, -0.5, -0.5)] # list of number of vertices per polygon # A cube has 6 faces of 4 vertices each polygonFaces = [4] * 6 # list of vertex indices that make the # the polygons in our mesh polygonConnects = [0,1,2,3,1,6,5,2,7,6,5,4,3,2,5,4,3,0,7,4,0,1,6,7] # create the mesh meshFn.create(vertices, polygonFaces, polygonConnects ) }}}

If you've authored a custom scripted-plugin [[MPxNode|http://download.autodesk.com/us/maya/2010help/API/class_m_px_node.html]] (or a derived class, like [[MPxLocatorNode|http://download.autodesk.com/us/maya/2010help/API/class_m_px_locator_node.html]]), via ~OpenGL you can draw text to the screen that follows it. Below is a code snippet showing parts of the class that you can use to implement this functionality. I pulled the concepts of this from [[this example|http://download.autodesk.com/us/maya/2010help/API/foot_print_manip_8py-example.html]] I should note that I've encountered a bug where the text seems to translate 1.5x greater than that of the node... and I have yet to find a solution :( {{{ import maya.OpenMaya as om import maya.OpenMayaUI as omui import maya.OpenMayaMPx as ompx class Foo(ompx.MPxLocatorNode): def __init__(self): """ Superclass override. """ ompx.MPxLocatorNode.__init__(self) # Save an empty MDagPath that will later be the path to our node. self.mDagPath = om.MDagPath() def draw(self, view, path, style, status): """ Superclass override, where the text drawing happens. """ view.beginGL() # M3dView view.drawText("TestText!", self.nodeTranslation(), omui.M3dView.kLeft) view.endGL() def nodeTranslation(self): """ Custom method that returns a MPoint object based on the worldspace position of our locator node. """ # Get the dag path to this object: om.MDagPath.getAPathTo(self.thisMObject(), self.mDagPath) # Pop from the shape to the transform self.mDagPath.pop() # Find the translation of the node in worldspace: transformFn = om.MFnTransform(self.mDagPath) # MFnTransform vec = transformFn.getTranslation(om.MSpace.kWorld) # MVector # Convert from internal units (cm) to whatever the UI is using: return om.MPoint(om.MDistance.internalToUI(vec.x), om.MDistance.internalToUI(vec.y), om.MDistance.internalToUI(vec.z)) }}} Docs: *[[M3dView|http://download.autodesk.com/us/maya/2011help/API/class_m3d_view.html]] *[[MFnTransform|http://download.autodesk.com/us/maya/2010help/API/class_m_fn_transform.html]] *[[MPxLocatorNode|http://download.autodesk.com/us/maya/2010help/API/class_m_px_locator_node.html]] *[[MPxNode|http://download.autodesk.com/us/maya/2010help/API/class_m_px_node.html]] *[[MDagPath|http://download.autodesk.com/us/maya/2010help/API/class_m_dag_path.html]] *[[MDistance|http://download.autodesk.com/us/maya/2010help/API/class_m_distance.html]] *[[MPoint|http://download.autodesk.com/us/maya/2011help/API/class_m_point.html]]

The below code is something I came up with to list all the attributes on a node via the API, the values stored in their plugs, and the API attribute type. It seems //really// clunky, and maybe in six months I'll find some function that does this in two lines. But it seems like the API makes you test against which function set the attribute belongs to, and then have to query for a very specific type of data. After I authored this I cam across Bryan Ewerts post [[here|http://ewertb.soundlinker.com/api/api.029.php]], which uses a very similar system, so I'm guessing I'm on the right track. Some notes: *I had to wrap every query in a try\except clause, since some data would return None even though it was defined as a given type. *I have yet to figure out how to query string data. It just fails :( *As noted below, the code ''fails to trace array attribute element plug data''. It shows a weird {{{[-1]}}} for the index, and won't dig any deeper. However, a link to a solution is provided at the end of this topic. Some helper functions: {{{ import maya.OpenMaya as om def nameToMObject(name): """ return an MObject based on the provided string node name. """ selectionList = om.MSelectionList() selectionList.add(name) node = om.MObject() selectionList.getDependNode( 0, node ) return node def getAllPlugs(mObject): """ return a list of all the plugs for all the attributes on the given MObject. """ ret = [] depNodeFn = om.MFnDependencyNode(mObject) attrCount = depNodeFn.attributeCount() for i in range(attrCount): attrObject = depNodeFn.attribute(i) mPlug = depNodeFn.findPlug(attrObject) ret.append(mPlug) return ret }}} Main code: {{{ objectName = 'pPlaneShape1' mObject = nameToMObject(objectName) plugs = getAllPlugs(mObject) # Query\print values: for plug in plugs: attr = plug.attribute() # MObject for the coresponding attribute val = [] #-------------------------------------------------------- # Now test to see what type of attr it is! # Is it numeric? if attr.hasFn(om.MFn.kNumericAttribute): fnAttr = om.MFnNumericAttribute(attr) unitType = fnAttr.unitType() if unitType == om.MFnNumericData.kBoolean: try: val = plug.asBool() except: pass elif unitType == om.MFnNumericData.kChar: try: val = plug.asChar() except: pass elif unitType == om.MFnNumericData.kShort: try: val = plug.asShort() except: pass elif unitType == om.MFnNumericData.k2Short: for i in range(2): try: val.append(plug.child(i).asShort()) except: pass elif unitType == om.MFnNumericData.k3Short: for i in range(3): try: val.append(plug.child(i).asShort()) except: pass elif unitType == om.MFnNumericData.kLong or unitType == om.MFnNumericData.kInt: try: val = plug.asInt() except: pass elif unitType == om.MFnNumericData.k2Long or unitType == om.MFnNumericData.k2Int: for i in range(2): try: val.append(plug.child(i).asInt()) except: pass elif unitType == om.MFnNumericData.k3Long or unitType == om.MFnNumericData.k3Int: for i in range(3): try: val.append(plug.child(i).asInt()) except: pass elif unitType == om.MFnNumericData.kFloat: try: val = plug.asFloat() except: pass elif unitType == om.MFnNumericData.k2Float: for i in range(2): try: val.append(plug.child(i).asFloat()) except: pass elif unitType == om.MFnNumericData.k3Float: for i in range(3): try: val.append(plug.child(i).asFloat()) except: pass elif unitType == om.MFnNumericData.kDouble: try: val = plug.asDouble() except: pass elif unitType == om.MFnNumericData.k2Double: for i in range(2): try: val.append(plug.child(i).asDouble()) except: pass elif unitType == om.MFnNumericData.k3Double: for i in range(3): try: val.append(plug.child(i).asDouble()) except: pass # Is it 'typed'? elif attr.hasFn(om.MFn.kTypedAttribute): # These can be string attrs attrType = om.MFnTypedAttribute(attr).attrType() if attrType == om.MFnData.kString: # NEITHER SOLUTION HERE IS WORKING! #stringData = om.MFnStringData(plug.asMObject()) #val = stringData.string() #val = plug.asString() # This cause it to break! :( val = "<string: can't query>" elif attrType == om.MFnData.kMatrix: try: matrixData = om.MFnMatrixData(plug.asMObject()) matrix = matrixData.matrix() val = [matrix(i,j) for i in range(4) for j in range(4)] except: pass # Is it angle, time, unit (distance), or enum? elif attr.hasFn(om.MFn.kDoubleAngleAttribute): mAngle = plug.asMAngle() val = mAngle.value() elif attr.hasFn(om.MFn.kTimeAttribute): mTime = plug.asMTime() val = mTime.value() elif attr.hasFn(om.MFn.kUnitAttribute): mDist = plug.asMDistance() val = mDist.value() elif attr.hasFn(om.MFn.kEnumAttribute): val = plug.asInt() # Could add more code for Generic, Light, & Message. Compound is a type as # well, but only holds other attrs (has no 'value'), and the previous code # extracts all the child plugs from any compounds that exist. if isinstance(val, list): if not len(val): val = None print plug.name(), val, attr.apiTypeStr() }}} Prints a lot of stuff: {{{ pPlaneShape1.message None kMessageAttribute pPlaneShape1.caching False kNumericAttribute pPlaneShape1.isHistoricallyInteresting None kNumericAttribute pPlaneShape1.nodeState 0 kEnumAttribute etc... }}} Furthermore, it won't print out the values for any //array attrs//. For example, presuming you have a poly mesh and you've modified the UV's, you'd have multiple UV attrs being tweaked on. But the above code will only print this: {{{ pPlaneShape1.uvSet None kCompoundAttribute pPlaneShape1.uvSet[-1].uvSetName <string: can't query> kTypedAttribute pPlaneShape1.uvSet[-1].uvSetPoints [0.0, 0.0] kAttribute2Float pPlaneShape1.uvSet[-1].uvSetPoints[-1].uvSetPointsU 0.0 kNumericAttribute pPlaneShape1.uvSet[-1].uvSetPoints[-1].uvSetPointsV 0.0 kNumericAttribute pPlaneShape1.uvSet[-1].uvSetTweakLocation None kTypedAttribute }}} Which I guess tells you that these are array attributes, but doesn't tell you how many of each there are, or the element plug values (other than the default vals listed). I have a solution for compound\array attrs here: [[API: Find all child attributes under a compound attribute]]

After much trial and error, I've whipped up the below code to query all the child attributes under a given compound attribute, and print their names \ types. This was complicated by a variety of factors: #It took me a while to realize that compound attrs can also be array. I hadn't quite grasped the differences between them: Compound is a type, like float or string. Array is a property of an attribute, like keyable, locked, hidden, etc. #I was able to query compound children, but I wasn't understanding how to query an array of compound attrs children. This was further messed up by the fact the {{{MPlug.getExistingArrayAttributeIndices()}}} method will return negative index values, which cause all sorts of problems. Not sure why it does that, but skipping over them solves the problem. #Understanding the differences between logical and physical index arrays. In a nutshell, you want to use logical most of the time... For more info on those topics, please see this subject: [[API: Attribute Creation & Usage]] In our example we use a polygonal plane with four verts, called {{{pPlane1}}} (but make reference to its shape node, {{{pPlaneShape1}}}). {{{ import maya.OpenMaya as om # The node name, and attribute name, to query: node = "pPlaneShape1" attr = "uvSet" # Get an MObject by string name: selList = om.MSelectionList() selList.add(node) mObject = om.MObject() selList.getDependNode(0, mObject) # Attach a function set to the shape and get the plug to start querying: mFnDependencyNode = om.MFnDependencyNode(mObject) rootPlug = mFnDependencyNode.findPlug(attr) # Get all child plugs for our root, presuming it is a compound attr, since they're # the only type that have 'children': plugs = [rootPlug] for plug in plugs: # If the type is compound, and it is also set to array: if plug.isCompound() and plug.isArray(): # Find the logical indices of the array: logicalIndices = om.MIntArray() plug.getExistingArrayAttributeIndices(logicalIndices) for i in range(logicalIndices.length()): # getExistingArrayAttributeIndices() can return negative index values # for some reason, so we need to be sure to *not* deal with those, # since obviously bad things would happen.... if logicalIndices[i] >= 0: # Now find the element plug of that index, which is a compound # type attribute: elementPlug = plug.elementByLogicalIndex(logicalIndices[i]) # And query the children of that compound attr: for j in range(elementPlug.numChildren()): plugs.append(elementPlug.child(j)) # If it is compound, but not array: elif plug.isCompound(): # Just get the children of that compound attr: for i in range(plug.numChildren()): plugs.append(plug.child(i)) for plug in plugs: attrObj = plug.attribute() # MObject print plug.name(), attrObj.apiTypeStr() }}} Gives us this result: {{{ pPlaneShape1.uvSet kCompoundAttribute pPlaneShape1.uvSet[0].uvSetName kTypedAttribute pPlaneShape1.uvSet[0].uvSetPoints kAttribute2Float pPlaneShape1.uvSet[0].uvSetTweakLocation kTypedAttribute pPlaneShape1.uvSet[0].uvSetPoints[0].uvSetPointsU kNumericAttribute pPlaneShape1.uvSet[0].uvSetPoints[0].uvSetPointsV kNumericAttribute pPlaneShape1.uvSet[0].uvSetPoints[1].uvSetPointsU kNumericAttribute pPlaneShape1.uvSet[0].uvSetPoints[1].uvSetPointsV kNumericAttribute pPlaneShape1.uvSet[0].uvSetPoints[2].uvSetPointsU kNumericAttribute pPlaneShape1.uvSet[0].uvSetPoints[2].uvSetPointsV kNumericAttribute pPlaneShape1.uvSet[0].uvSetPoints[3].uvSetPointsU kNumericAttribute pPlaneShape1.uvSet[0].uvSetPoints[3].uvSetPointsV kNumericAttribute }}} It should be noted that not all attrs are so verbose. For example, if you set this and re-run it: {{{ attr = "pnts" }}} All it prints is: {{{ pPlaneShape1.pnts kAttribute3Float }}} Even though we know there is more than one point in the plane. If you grab all the verts and component level, manually move them with the translate manip, and re-run it, it prints: {{{ pPlaneShape1.pnts kAttribute3Float pPlaneShape1.pnts[0].pntx kFloatLinearAttribute pPlaneShape1.pnts[0].pnty kFloatLinearAttribute pPlaneShape1.pnts[0].pntz kFloatLinearAttribute pPlaneShape1.pnts[1].pntx kFloatLinearAttribute pPlaneShape1.pnts[1].pnty kFloatLinearAttribute pPlaneShape1.pnts[1].pntz kFloatLinearAttribute pPlaneShape1.pnts[2].pntx kFloatLinearAttribute pPlaneShape1.pnts[2].pnty kFloatLinearAttribute pPlaneShape1.pnts[2].pntz kFloatLinearAttribute pPlaneShape1.pnts[3].pntx kFloatLinearAttribute pPlaneShape1.pnts[3].pnty kFloatLinearAttribute pPlaneShape1.pnts[3].pntz kFloatLinearAttribute }}} Which tells me that in some cases, the plugs don't exist until some type of user interaction. Something even crazier I've found: If instead of grabbing all the verts by hand and deleting them, if I instead run the command: {{{ delete -constructionHistory; }}} On the mesh, the attrs will appear as well. It must be triggering some kind of massive "you are dirty" flag on all the plugs so they suddenly show up.... or something.... I have yet to find a more elegant solution for this :( ---- Also see: *[[API: Find all attributes & plugs on a node]] *[[How can I get a list of all the child multi-attrs, of a given attr name?]] (using the command engine, rather than the API) * [[Find child attributes]]

''API Code Snippet'' In this example, I set all variable names to be the type of object they are, to make it easier to understand how objects are returned and used. I don't recommend doing this in regular code, just using it as an explanation tool __Highlights:__ *Create {{{MItDag}}} 'DAG iterator object' to loop over all mesh. *Create {{{MDagPath}}} 'DAG path object' for each mesh, giving access to it's path/name. *Create {{{MFnMesh}}} 'polygonal surface function set' object, allowing for actions to be performed on the current {{{MDagPath}}} object. {{{ # Print the name of all the mesh in the scene & their vert counts. import maya.OpenMaya as om # Make a MItDag iterator object, for mesh only: MItDag = om.MItDag(om.MItDag.kDepthFirst, om.MFn.kMesh) # Start looping over each mesh: while not MItDag.isDone(): # Make a MDagPath object that will store the path of # the mesh: MDagPath = om.MDagPath() # Set the MDagPath object to the path of the current mesh # as defined by the current loop of the iterator: MItDag.getPath(MDagPath) # Create a new MFnMesh object, set to the current dag path. # We can now do operations on that mesh via that object. MFnMesh = om.MFnMesh(MDagPath) # As an example, find the number of verts on the mesh # from the MFnMesh object: numVerts = MFnMesh.numVertices() # get the name of our node from the MDagPath object: name = MDagPath.fullPathName() # Print results: print name, numVerts # Advance to the next mesh in our iterator: MItDag.next() }}}

Example via the ~OpenMaya Python API of finding the closest vertex on a polygonal mesh to a given transform. I've not tried it, but it may be worth checking out a solution using [[MMeshIntersector|http://docs.autodesk.com/MAYAUL/2013/ENU/Maya-API-Documentation/cpp_ref/class_m_mesh_intersector.html]