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

The hidden Marking Menus


API : Custom Shapes

MATH: Area of a polygon

$
0
0
2d recipe:

http://code.activestate.com/recipes/578275/
def poly_area2D(poly):
    total = 0.0
    N = len(poly)
    for i in range(N):
        v1 = poly[i]
        v2 = poly[(i+1) % N]
        total += v1[0]*v2[1] - v1[1]*v2[0]
    return abs(total/2)
poly = [[0,0], [0,1], [1,1]]
print poly_area2D(poly)
.5

The original code requires a numpy install. I've re-authored it below to use Maya's OpenMaya.MVector class
http://code.activestate.com/recipes/578276/
import math
from maya.OpenMaya import MVector

def normal(p1, p2, p3):
    va = MVector(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z)
    vb = MVector(p3.x - p2.x, p3.y - p2.y, p3.z - p2.z)
    n = va^vb # cross
    return n

#area of 3d polygon
def poly_area3D(poly):
    if len(poly) < 3: # not a plane - no area
        return 0
    total = [0, 0, 0]
    N = len(poly)
    vecs = [MVector(points[0], points[1], points[2]) for points in poly]
    for i in range(N):
        vi1 = vecs[i]
        vi2 = vecs[(i+1) % N]
        prod = vi1^vi2 # cross
        total[0] += prod.x
        total[1] += prod.y
        total[2] += prod.z
    nVec = normal(vecs[0], vecs[1], vecs[2])
    tVec = MVector(total[0], total[1], total[2])
    dot = abs(tVec*nVec) # dot
    return math.sqrt(dot)/2
poly = [[0,0,0], [0,4,0], [4,0,0]]
print poly_area3D(poly)
# 8

Accessing the Paint Skin Weights Tool code

$
0
0
When you access the Maya menu command here:
  • Skin -> Edit Smooth Skin -> Paint Skin Weights Tool [Options]
What code does it execute?

That menu command calls to this runTimeCommand:
ArtPaintSkinWeightsToolOptions;
Which in turn is a wrapper for this command:
artAttrSkinToolScript 3;
Which is a global procedure called to in this script (on Vista 64):
C:\Program Files\Autodesk\Maya<version>\scripts\others\artAttrSkinToolScript.mel

The code that generates the tool options in the Attribute Editor lives here:
C:\Program Files\Autodesk\Maya2013\scripts\others\artAttrSkinProperties.mel

How can I append to the Graph Editor's RMB menu?

$
0
0
When you RMB in the Graph Editor, a context sensitive menu pops up. How can you append your own items to this?
Actually, I have yet to figure out how, and here's why:
The script
C:\Program Files\Autodesk\Maya20XX\scripts\others\graphEditorPanel.mel
Holds all the code the creating these menus. The proc buildGraphEditorPopupMenuGeneral() specifically is what creates the menu items, and the parental menu's name is graphEditor1GraphEdanimCurveEditorMenu. The issue is, the proc buildGraphEditorPopupMenu() is called whenever the RMB is clicked in the Graph Editor, and it firsts deletes all the menu items, then rebuilds them.
So even if you write some code like this to add your own menu item:
setParent -menu graphEditor1GraphEdanimCurveEditorMenu;
menuItem -divider true;
menuItem -label "AWESOME";
You'll never actually see it, since it will be deleted before the menu is rebuilt for display.

The proc defineGraphEditorPopupMenu() physically creates the actual popupMenu that houses the various menu items. In theory this proc could be overridden to point to your own popupMenu creation code.

API: Manipulators

$
0
0

How can I launch WordPad and view a text file?

$
0
0
  • In Windows, if you write your own files to disk using Maya using commands like fprint, using Notepad in Windows, which is the default viewer for text documents, doesn't interpret the 'newline\return' characters correctly (\n, \r).
  • Problem is, "Notepad.exe" is in the Windows PATH, so it's really easy to call to to view text files. WordPad, isn't in the windows path, but it will interpret the 'newline\return' character properly.
  • So what is the best way to call to it? Below is a good example. You'd want to do error checking to make sure your $file actually exists first:
string $file = "c:/temp/myFile.txt";
string $programFiles = `getenv "ProgramFiles"`;
string $wordPad = ($programFiles + "/Windows NT/Accessories/WORDPAD.EXE");
if(`filetest -f $wordPad`)
	system("start " + $wordPad + " " + $file);
Doing the same thing with Notepad is easier (since it's in the Windows PATH), but the formatting usually looks screwed up :-(
string $file = "c:/temp/myFile.txt";
system("start notepad " + $file);

How can I update the custom marking menu that appears when you RMB over a DAG object?

$
0
0

Old Bad Way:

Edit the Maya script: \Maya20XX\scripts\others\dagMenuProc.mel Yuck.
In the procedure dagMenuProc(), 'string $shortName' is the name of the object under the curser, which you can then write an "if" statement for allowing you to run other procedures based on that name.

New Good Way:

With some help from the undocumented dagObjectHit command, and this great forum post (authored way back in 2008). Big kudo's to Roger Klado for figuring this stuff out and posting about it!

I took the guts of what was in that post, modified and re-authored it in Python, with a lot of descriptive text explaining what's going on: When you run the below code, when you Alt+RMB on a node, a custom popupMenu will be created displaying the name of the node. Plus, if you have a component highlighted, it will add an item for that component name.

What's going on?
  • makePopup() creates a popupMenu that will execute when something is Alt+RMB-clicked.
  • It in turn has a 'postMenuCommand' parameter that executes the postMenuCommand() function each time the popupMenu is created and made visible.
  • The postMenuCommand() function is what physically builds the new custom popupMenu. However, to start this process, it actually calls the overrideDagMenuProc() function:
    • Via trickery with the (undocumented) dagObjectHit command, it (behind the scenes) uses the mel procedure dagMenuProc() to re-create that menuing system, inside our new menu. This has the advantage of including the object name as the first item in the menu, which is the data we care about.
    • That menu is completely cleared of all items (since we want to build our own menu), and the object name is returned back to postMenuCommand().
  • postMenuCommand() can then start re-building the empty menu with whatever you want, based on the name of the object Alt+RMB'd on.
    • In the example below, it generates a menuItem with the object name Alt+RMB'd on, and if any component level items were highlighted, will make another menuItem for the one under the cursor.
# Python code
import maya.cmds as mc

# The name to give our custom, context-sensitive, Alt+RMB popupMenu:
POP_NAME = 'myCustomPopupMenu'

def overrideDagMenuProc():
    """
    This function will override the RMB-menu created by dagMenuProc().
    It returns the name of the object Alt+RMB'd on:
    """
    # This creates a new menu, for the object Alt+RMB'd on, populated with the
    # guts of what dagMenuProc() would normally build:
    mc.dagObjectHit(menu=POP_NAME)
    # Get a list of all the children in that menu:
    popChildren = mc.popupMenu(POP_NAME, query=True, itemArray=True)
    # The menu item's name is the leaf name of the node:  If there are duplicate
    # names in the scene, this is always the leaf.  To get the full path, we
    # need to query the select command embedded in the menuItem:
    command = mc.menuItem(popChildren[0], query=True, command=True)
    fullName = command.split(' ')[-1]
    # Now delete the menu items created by dagMenuProc(), giving us an empty menu:
    mc.popupMenu(POP_NAME, edit=True, deleteAllItems=True)
    # Finally return the name of our node, which will be used by postMenuCommand
    # to build the top label in the empty menu:
    return fullName

def postMenuCommand(*args):
    """
    This function is passed to, and executed by the menu created via makePopup()
    whenever the popupMenu is shown.  It's what you'd update to have custom menu
    items appear based on what's selected.
    """
    # Delete all the items from any pre-existing menus:
    if mc.popupMenu(POP_NAME, exists=True):
        mc.popupMenu(POP_NAME, edit=True, deleteAllItems=True)

    # Make our menu the current menu for any new children:
    mc.setParent(POP_NAME, menu=True)
    if mc.dagObjectHit():  # undocumented command!
        # If the user has Alt+RMB'd over a node, capture the return of the
        # function that overrides the dagMenuProc's popupMenu.  The return is
        # the full name of the node that has been Alt+RMB'd over... and use it as
        # the label for the menu.  Extract the leaf name from the full path:
        fullObjectName = eval('overrideDagMenuProc()')
        leafObjectName = fullObjectName.split("|")[-1]
        mc.menuItem(label=leafObjectName)

        # Here, any custom code can be authored that is based on the object name
        # For example, track if there are any highlighted components:
        componentPreSelect = mc.ls(preSelectHilite=True)
        if len(componentPreSelect):
            mc.menuItem(divider=True)
            mc.menuItem(label=componentPreSelect[0])
    else:
        # Otherwise, no thing Alt+RMB'd on:
        mc.menuItem(label="No object under cursor")

def makePopup():
    """
    Will create the custom, context-sensitive, popupMenu displayed by Alt+RMB'ing
    on a node.
    """
    # Delete the popupMenu if it already exists:
    if mc.popupMenu(POP_NAME, exists=True):
        mc.deleteUI(POP_NAME)

    # Build the popupMenu, envoking a postMenuCommand when it is shown:
    mc.popupMenu(POP_NAME,
                 button=3,
                 altModifier=True,
                 markingMenu=True,
                 parent='viewPanes',
                 postMenuCommand=postMenuCommand)
# And execute...
makePopup()
On a side-note: After several tries, the safest bet is Ctrl+MMB: Ctrl+RMB is used for zoom.


2008 02 18

$
0
0
I recently got turned onto Processing through the Make blogs:

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. One of the coolest things: He also gives the Processing source code away for each of them. That is awesome. Share the knowledge!




(many more in the above link)

How can I find all reference edits, and remove them?

$
0
0
Note, this can print a LOT of stuff depending on what's changed in the reference:
# Python Code
import maya.cmds as mc

allRefs = mc.file(query=True, reference=True)
for ref in allRefs:
    refNode = mc.file(ref, query=True, referenceNode=True)

    print refNode, ref
    editStrings = mc.referenceQuery(ref, topReference=True, editStrings=True, successfulEdits=True)
    for es in editStrings:
        print "\t", es

    # Remove all edits:
    mc.file(unloadReference=refNode)
    mc.file(cleanReference=refNode)
    mc.file(loadReference=refNode)

This tip comes from over at the Maya Station blog:
If you have made changes to your reference file which has then caused incorrect results, For example making changes to an expression then saving the reference file causes you to lose your expression information; simply reloading the reference file will not be enough to get the original data back.

You will need to remove the wrong edits. In order to do this you need to unload your reference from the Reference Editor, and then go to Reference Editor ->List Reference Edits. In the window that pops up select the wrong edits and click on Remove Selected Edits. Once this is done you can Reload you reference, through the reference editor.

How can I create a RMB popup menu?

Understanding and creating hotkeys

$
0
0
Notes on the below info:
  • The top section shows two different ways for authoring hotkey commands. I've only had success using runTimeCommand: using namedCommand just doesn't seem to work.
  • When authoring a new runTimeCommand via code (as described below), it will immediately be available for usage in the Hotkey Editor.
  • When authoring a new hotkey via the namedCommand command (as described below), I've not had the best luck: When accessing the Hotkey Editor, it shows the hotkey as existing, but they key-combo I assigned to it isn't shown. When I reassign the key-combo, it says it's already assigned, but still won't work. Either I'm doing something wrong, or it's a bug.

To make a hotkey (all via code), you first must author the 'command' it will execute via either a runTimeCommand or nameCommand, then create the key binding via hotkey command.

Command Authoring

runTimeCommand

The runtTimeCommand command will, from the docs: "Create a MEL command given the specified name. Once the command is created you can invoke it like any other MEL command."
Note that for some reason there are only mel docs for it, even though it is exposed in Python.
If coding the command, if the 'category' flag is set to "User" (and it probably should), the commands will be saved in this mel script:
\Documents\maya\<version>\prefs\userRunTimeCommands.mel
In the Hotkey Editor, when the user interactively creates a command in the 'User' category, they are saved via this method in the above mel script as well.

nameCommand

Note: I couldn't get this way to work. I'd recommend using the runTimeCommand solution above.
nameCommand is a command that from the docs "...creates a nameCommand object. Each nameCommand object can be connected to a hotkey."
When the user creates one of these from mel or Python, they are saved in this mel script:
\Documents\maya\<version>\prefs\userNamedCommands.mel
It should be noted that the command can accept either a mel or Python command to execute via it's -sourceType and -command flags. That being said, when I pass in Python commands, I get errors. However, if I define the -sourceType to be mel, then call to my Python code via the python mel command, the errors go away. Go figure.

Hotkey Creation

hotkey

The hotkey command will, from the docs "...sets the single-key hotkeys for the entire application."
When the user creates a hotkey in the Hotkey Editor, or via this command, they are stored in this mel script:
\Documents\maya\<version>\prefs\userHotkeys.mel
After the hotkey has been created, you'll need to call to the command separately to save it (via autoSave=True).

How can I get a list of all connecting sets?

$
0
0
I like to make a lot of subsets while working, to help organize things. While sets are DG nodes, and have no real hierarchy, by adding sets to one another, it sort of mirrors the child\parent DAG transform hierarchy, and the Outliner displays them this way. However, since they aren't in a hierarchy, you can't use commands like listRelatives to get a list of all of their 'children'. They have no 'children', since they aren't in a hierarchy. But you still may want to get a list of their 'pseudo-chilld sets' anyway.

This code will recursively search a parental sets for all objectSets connected too it, and all sets connected to them, etc.
# Python code
import maya.cmds as mc

sets = ["DZS_TORSO"]   
for s in sets:
    subSets = mc.listConnections(s, source=True, destination=False, type='objectSet')
    if subSets is not None:    
        for ss in subSets:
            sets.append(ss)
print sets

Why does my motionPath have a different length than reported by my curve?

$
0
0
A motionPath node can report a different 'length' than other curve querying nodes like nearestPointOnCurve, or even the curve itself. Here is a breakdown of what I've found:
  • nurbsCurve.minValue, nurbsCurve.maxValue : 'internal units'
  • motionPath.uValue : If motionPath.fractionMode is True (in the Attribute Editor, this is the 'Parametric Length' field), the uValue is the 'ui unit' equivalent of the curveShape.maxValue attr (which is stored in 'internal units'). If fractionMode is False, uValue is some smaller value, I have yet to figure out how this relates.
  • curveInfo.arcLength : 'ui units'
  • nearestPointOnCurve.parameter : 'internal units' (cm) - This is based on the nurbsCurve shape's maxValue attr, which also appears to be stored in internal units.
  • nearestPointOnCurve.position : 'ui units'
Chaos.

How can I query if a reference is loaded or unloaded?

$
0
0
int $unloaded = `file -query -deferReference $refFilePath`;
Will return 1 if unloaded, 0 if loaded.

How can I track the mouse's position in realtime?

$
0
0
A couple different solutions I've come up with:

autoPlace running in a Python Thread:

The autoPlace command can return the mouse's current 3d worldspace position (always in cm). If you execute that in a thread in Maya, it can execute constantly in the scene in the background, reporting the position, and executing any other code you need at the same time.
# loopMousePos.py

import threading

import maya.cmds as mc
import maya.utils as mu

running = False

def mouseEvent(*args):
    """
    The code to evaluate in the thread.  In this case, it prints the mouse position.
    """
    # This is printing cm values no matter your working unit.  You may need to
    # do some conversion...
    print mc.autoPlace(useMouse=True)

def looper(*args):
    """
    Wrapper for the code that should be evaluated:  This code evaulates in the
    Python thread, but it executes the results in Maya.
    """
    while True:
        # When running in a Python Thread, If you don't evaluate you Maya code 
        # via this function, Maya *will* crash...
        mu.executeInMainThreadWithResult(mouseEvent)

def main():
    """
    Create and start the Python Thread.  Main point of execution.
    """
    global running
    if not running:
        threading.Thread(target=looper).start()
        running = True

Query a draggerContext's 'dragPoint':

You can create a custom draggerContext so that when you enter it and LMB-drag around the view, it will print the 2d screen-space position of the mouse, and execute any other code you need:
# mousePosCtx.py

import maya.cmds as mc

CTX = 'mousePosCtx'

def mousePosDragFunc(*args):
    """
    Function called on drag.
    """
    dragPosition = mc.draggerContext(CTX, query=True, dragPoint=True)
    print dragPosition

def main():
    """ 
    Create and enter the conext.
    """
    if mc.contextInfo(CTX, query=True, exists=True):
        mc.deleteUI(CTX, toolContext=True)

    # Make the context:
    mc.draggerContext(CTX, cursor='hand', space='screen', dragCommand=mousePosDragFunc,
                      projection='viewPlane');

    # Set the tool to the context
    # Results can be observed by dragging mouse around main window
    mc.setToolTo(CTX)

How can I match the worldspace transformations of two objects?

$
0
0
We query the .worldMatrix of our source node, then via xform set our destination node to that worldspace transformation:
// mel
string $source = "pCube1";
string $destination = "pCube2";

float $m[16] = `getAttr ($source+".worldMatrix")`;
xform -worldSpace -matrix $m[0] $m[1] $m[2] $m[3] 
		$m[4] $m[5] $m[6] $m[7] 
		$m[8] $m[9] $m[10] $m[11] 
		$m[12]$m[13] $m[14] $m[15] $destination;
# Python
source = "pCube1"
destination = "pCube2"

m = mc.getAttr(source+".worldMatrix") 
mc.xform(destination, worldSpace=True, matrix=m)
Why is this cool? Because no matter what you have done to the parental hierarchy of either node, and despite the rotation orders of either node, the destination node will perfectly match the worldspace matrix of the source.

This also solves problems that other code (like the below example illustrates) will get tripped up on (which include the links at bottom) when dealing with matching orientations:
If the rotate order of the destination differs from the source, the below code will fail.
# Python:
import maya.cmds as mc
worldRot = mc.xform(source, rotation=True, query=True,  worldSpace=True)

# two different methods, will fail if differing rotate orders:
mc.xform(destination, rotation=worldRot, worldSpace=True)
mc.rotate(worldRot[0], worldRot[1], worldRot[2], destination, worldSpace=True)

Also see:

Welcome

API: Accessing window data

$
0
0
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 modelEditors.
  • 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

API: How can I make a transform?

$
0
0
(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

Viewing all 610 articles
Browse latest View live


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