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

API : Converting from internal units to ui units (and back again)

$
0
0
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')

Instructions For Use

$
0
0
This is a TiddlyWiki. To really get a grasp on how to navigate it, check out their homepage. Quick directions below:

Conceptually, each 'subject' I post in the wiki is put in a 'tiddler' (based on how "Tiddlywiki's" work). The Instructions For Use section you're in now is a 'tiddler'. Welcome is a tiddler. Tiddlers are like individual blog posts. I tag each tiddler with keywords relevant to the subject of said tiddler, and you can see those tags on a small box on the top right of each tiddler. Clicking on a tag will display a list of every other subject with that tag. Subjects (tiddlers) are also categorized on the left menu-bar under larger subject-headings. ALL the tags from every tiddler are in the 'Tags tab', which is on the right most column of the page.

Mainly, you come to the page looking for an answer, and to find it, you search for tags using keywords that may exist in your problem. When you find a tag, click on it, and see the resultant subjects... see if one matches what you're looking for.

SEARCHING FOR DATA

  1. Browse the "Tags" tab in the right column for mel-ish key-words.
    • Inside the Tags tab, major Categories are all in caps, like "ATTRIBUTES".
    • When picking a 'Tag' with more than one link, you can either:
      1. 'Open all' the topics in that Tag (meaning, fully expand all the topics listed in the middle of that pop-up menu).
      2. Open a single topic by picking its heading.
      3. Show all the headings in the Tag by picking: Open tag 'tagname'.
  2. Use your web browsers screen-search ability ('Ctrl+F' in both Firefox & Internet Explorer) to find key-words you're after (good if 'Tags' tab is open).
  3. Or start browsing from the Categories section in the left column. This will open each of their major headings in a new tiddler.
If things get too crowded, use the "close all" from the right column to clean up the page. Or, you can use "close others" from an individual tiddler (This block called "Instructions For Use" is a tiddler, for example).

COPYING DATA FROM WIKI, TO MAYA

  • The way the text has been entered into this wiki, copying code from the source-boxes should work:
string $source = "source-code in a box"; 
  • Other times it's not in a box, but is still safe for copy:
string $source = "source-code not in a box, but still safe to copy";
  • If you copy any code outside of a box that's 'not safe', Maya may have a hard time with it's formatting and be angered. Weird

COPYING A LINK FOR A TIDDLER

If you want to copy a link to a specific tiddler (post) on this wiki:
  • Open the tiddler in question
  • In the top-right corner of the tiddler, press the 'close others' button: It should be the only tiddler visible now.
  • In the top-right corner of the wiki, press the 'permaview' button.
  • The full path to this specific tiddler will now be in the address bar: You can copy\paste it.

Copyright Information

$
0
0
Much of this I have learned from others, we all ride on shoulders of giants. But for what I present as my own work, it's under the below licence:

All information on this wiki is under the Apache Licence, v 2.0:
Copyright 2015 Eric Pavey

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
To understand how this licence works see this overview.
But it pretty much means you can use the information on this wiki however you want, but I always appreciate credit where applicable.

Maya Links

$
0
0
NOTE: This isn't maintained very often.

Quality links you should know about, having to do with Maya, and mel:

'Official':
These sites appear to be down, or lost to the Autodesk takeover.

'Unofficial':

'Books'

Got any other suggestions? Let me know...

Welcome

MainMenu

Compute a new local axis matrix from a single vector

$
0
0
The below PyMel code will generate a completely new local axis matrix by providing a single vector. The code is very simple, and only works a fixed way: You provide a vector that specifies the 'x leg' of the new local axis, and it will compute the corresponding vectors for the y & z legs: The z leg will attempt to match the world z, and the new y leg will be the cross product of the new x & z. This is basically what an aimConstraint is doing, and the code could be expanded to be far more robust, emulating similar features of an animConstraint.
import pymel.core as pm

def computeLocalAxis(newX):
    """
    By providing a newX Vector leg for the new local axis, this will compute the Y & Z legs.
    The Z leg will be most closely aligned with the worldZ, Y leg will be a cross of the X & Z legs.

    Return is a PyMel Matrix of the new local axis, with the position zeroed:
    [newX,
     computedY,
     computedZ,
     [0,0,0,1]]
    """
    worldZ = pm.dt.Vector.zAxis
    newY = newX.cross(worldZ).normal()
    newZ = newX.cross(newY).normal()
    # Make sure Z is aligned correctly:
    if worldZ.dot(newZ) < 0:
        newZ *= -1
        newY *= -1
    return pm.dt.Matrix(newX, newY, newZ)
Here's an example of it in action: Two cones are created, A and B. B is translated and rotated differently from A. The localX axis vector from A is assigned to B:
import pymel.core as pm

# Get PyNode Transforms for our two nodes:
nodeA = pm.PyNode("coneA")
nodeB = pm.PyNode("coneB")

# Get the worldspace matrix for nodeA
m_world_nodeA = nodeA.getMatrix(worldSpace=True)
# Extract its localX vector:
newX = pm.dt.Vector(m_world_nodeA[0][:3])

# Compute the new local axis:
newMtx = computeLocalAxis(newX)
# Get the position of nodeB
v_nodeB_rotPiv = pm.dt.Vector(nodeB.getRotatePivot(worldSpace=True).cartesian())
# Insert that position into our matrix:
newMtx[3] = v_nodeB_rotPiv
# Set nodeB to this new matrix:
nodeB.setTransformation(newMtx)
PyMel Docs (2015):

PyMel : File command access

$
0
0
PyMel took the file command and split it apart into its own package, pymel.core.system. Cheat sheet for where all the functionality has gone:
For the below examples:
import maya.cmds as mc
import pymel.core as pm

Referencing

File Reference Querying:

With Python, you can query top-level file references via:
topFileRefs = mc.file(query=True, reference=True)
In PyMel:
topFileRefs = pm.getReferences()
allFileRefs = pm.getReferences(recursive=True)
Which has the added advantage of recursively searching through all sub-refs as well. It returns back a dict, which this key:value pairing: {"namespace":FileReference, ...}
You can also use the iterReferences or listReferences commands that have even more robust return values.
Note, that if you want to get just the string names of the references, you need to jump through some hoops:
topFileRefs = [str(pm.getReferences()[key].path) for key in pm.getReferences()]
print topFileRefs 
Since the FileReference class houses it's path data in a Path class.

Reference Creation:

Python:
mc.file(fullPathToTheFile, reference=True)
PyMel:
pm.createReference(fullPathToTheFile)

Reference Removal:

Python:
mc.file(fullPathToTheReference, removeReference=True)
PyMel:
ref = pm.FileReference(fullPathToTheReference)
ref.remove()

Dependencies:

All Dependency Querying:

The above command will give all the (Maya) file references in the scene. This Python command will include them, plus all other dependencies, like textures, sounds, etc:
allDependencies = mc.file(query=True, list=True)
I have yet to be able to track down the PyMel equivalent. But you can do it via mel, in PyMel of course:
allDependencies = pm.mel.eval("file -query -list")

Scene Access:

Scene Opening:

Python:
mc.file(filePath, open=True, force=True)
PyMel:
pm.openFile(filePath, force=True)

New Scene Creation:

Python:
mc.file(newFile=True, force=True)
PyMel:
pm.newFile(force=True)
pymel.core.system.newFile

Scene Renaming

Python:
mc.file(rename="c:/temp/spam.ma")
PyMel:
pm.renameFile("c:/temp/spam.ma")
pymel.core.system.renameFile

Scene Type Changing

It Python, even if the scene isn't saved, you can set it's 'type', like so:
mc.file(type="mayaAscii")
In PyMel, the scene first must have a name assigned (see Scene Renaming, above). Then you can execute:
pm.saveFile(type="mayaAscii")
Which will both change its type, and save it at the same time.
pymel.core.system.saveFile

Scene Name querying:

Python:
sceneName = mc.file(query=True, sceneName=True)
PyMel
sceneName = pm.sceneName()
pymel.core.system.sceneName

Scene Saving:

With both Python and PyMel, a scene needs to have a name assigned first, before it is saved.
Python:
mc.file(save=True)
PyMel:
pm.saveFile()
pymel.core.system.saveFile

Save As:

To my knowledge, you can't do a 'save as' via the file command: You first need to name the scene (via Scene Renaming, above), then do a save (as shown above). However in PyMel, they have this convenience function that does the scene name assignment and save all in one line:
pm.saveAs("c:/temp/eggs.ma")
(no docs)

Import/Export

File Import:

Python:
mc.file(pathToFileToImport, i=True)
PyMel:
pm.importFile(pathToFileToImport)
pymel.core.system.importFile

Export Selected:

Python:
mc.file(pathToExportedFile, exportSelected=True, type='mayaAscii')
PyMel:
pm.exportSelected(pathToExportedFile, type='mayaAscii')
pymel.core.system.exportSelected

Export All:

Python:
mc.file(pathToExportedFile, exportAll=True, type='mayaAscii')
PyMel:
pm.exportAll(pathToExportedFile, type='mayaAscii')
pymel.core.system.exportAll

.anim Export:

Maya has its own .anim file format for exporting animation curves. The options arg is generally a very long string of values that is passed to the export plugin (executing an export from mel will give you a string that can be used in your code).
Python:
mc.file(pathToAnimExportFile, exportSelected=True, type='animExport',
        options=longStringOfExportOptions)
PyMel:
pm.exportSelected(pathToAnimExportFile,, type="animExport", 
                  options=longStringOfExportOptions)

.anim Import

Python:
mc.file(pathToAnimFile, i=True, type="animImport", options=longStringOfImportOptions)
PyMel:
pm.importFile(pathToAnimFile, type="animImport", options=longStringOfImportOptions)

Unsupported?:

Disabling file prompting

Via Python, you can disable the prompt dialogs that appear when scenes have errors, like so:
mc.file(prompt=False)
I've searched through the PyMel documentation, and can't come up with any leads on how to disable this via PyMel. You can of course do it via mel, in PyMel:
pm.mel.eval('file -prompt 0')

Querying Unsaved Changes

The Python wrapper for this is:
needsSaving = mc.file(query=True, modified=True)
But I can't find the PyMel equivalent. So, wrapper the mel:
needsSaving  = pm.mel.eval('file -query -modified')

Open fcheck to view an image

$
0
0
PyMel makes it pretty easy:
import pymel.core as pm
pm.fcheck("path to my image")
2015 Docs

PySide : Access Qt .ui widget data in Maya

$
0
0
Say you've made a snazzy window in Qt Designer: After you've created it, you want to access its internals in Maya, and muck with them. Some Qt widgets, like QPushButton have a direct relation to some Maya control, like button. But others don't, like say, the QSpinBox (see Using Qt Designer).

If there is a 1:1 correspondence, you can query the Qt widget directly via the corresponding Maya command. For example, if you've made a QPushButton named "myPushButton" in Qt Designer (by setting the QObject's 'objectName' property to a valid string), you can then later directly access it in Maya:
import pymel.core as pm
print pm.button("myPushButton", query=True, command=True)
But what if there is no correspondence, like in the case of a QSpinBox? As long as you have given it 's MObject a valid 'objectName' in Qt Designer, you can access it directly via PySide in Maya:
import maya.OpenMayaUI as omui
from shiboken import wrapInstance
from PySide.QtGui import *

def getQtType(strName, qtType):
    """
    strName : The string assigned to the QObject's 'objectName' property.
    qtType : some Q* class : Like QSpinBox, QPushButton, etc.
    
    return : The instance define by qtType.
    """
    ptr = omui.MQtUtil.findControl(strName)
    return wrapInstance(long(ptr), qtType)
spinBox =  getQtType("mySpinBox", QSpinBox)
print spinBox
# <PySide.QtGui.QSpinBox object at 0x000000004597F788>
Once you have that instance, you can start hooking up signals\slots, or do any other work you need to have it interact with Maya.

Here is a very simple example using the above ideas: The user has authored some elaborate ui in Qt Designer. They've added a QSpinBox for which there is no Maya equivalent, yet want access to the widget in Maya. Note at the bottom of the code example the window instance is captured in a variable. This is very important, see the notes below.
import pymel.core as pm
import maya.OpenMayaUI as omui
from shiboken import wrapInstance
from PySide.QtGui import QSpinBox

class MyQtWin(object):

    uiFile = "C:/Users/epavey/Documents/maya/python/test02.ui"
    # This is the 'objectName' of the QDialog:
    dialogName = "MyDialog"

    def __init__(self):
        if pm.window(MyQtWin.dialogName, query=True, exists=True):
            pm.deleteUI(MyQtWin.dialogName)
        pm.loadUI(uiFile=MyQtWin.uiFile)

        # Get access to the Qt widget:
        ptr = omui.MQtUtil.findControl("spinBox")
        self.spinBox = wrapInstance(long(ptr), QSpinBox)
        # Connect signal to slot:
        self.spinBox.valueChanged.connect(self.spinBoxCmd)

        # Show window, and make sure the title-bar isn't off-screen:
        pm.showWindow(MyQtWin.dialogName)
        pm.window(MyQtWin.dialogName, edit=True, topEdge=32)
        pm.window(MyQtWin.dialogName, edit=True, leftEdge=32)

    def spinBoxCmd(self, val):
        print self.spinBox, val

# Very Important!  Must capture this instance, or Python will
# garbage collect, and the signal/slot won't work.
qtWin = MyQtWin()

Also see:

Loading Qt .ui files

$
0
0
The Qt Designer app gives you a wysiwyg window authoring environment. Maya provides a loadUI command to ease the process of loading them. The below example is a big wrapper around that: It both loads the UI, and then provides the user the option to either have them be their own window, or a dock (which could be floating as well). Below I use PyMel, but you can just as easily use regular Maya Python.
import pymel.core as pm

def loadQtUi(path, mode="window", dockFloat=False, docArea="right", dockWidth=256):
    """
    Parameters:
    path : string : Full path on disk to .ui file.
    mode : string : Default "window".  Supports "window" and "dock".
    dockFloat : bool : Default False.  If mode == "dock", floating == True will
        create the doc in a floating window.  Otherwise it will be docked.
    docArea : string : Default "right" : If mode == "dock" and floating == False,
        the part of the ui to dock in.  Supports "top", "left", "bottom", & "right".

    return : string : Name of the Qt window created.
    """
    qtWin = pm.loadUI(uiFile=path)
    if mode == "window":
        pm.showWindow(qtWin)
        # Sometimes the tital-bar is off the top of the screen.  If so, move in:
        if pm.window(qtWin, query=True, topEdge=True) < 1:
            pm.window(qtWin, edit=True, topEdge=32)
        if pm.window(qtWin, query=True, leftEdge=True) < 1:
            pm.window(qtWin, edit=True, leftEdge=32)

    elif mode == "dock":
        # Just like windows, docs need to be named \ removed if they already exist:
        docName = "myCustomDoc"
        if pm.dockControl(docName, query=True, exists=True):
            pm.deleteUI(docName)
        pm.dockControl(docName, allowedArea="all", area=docArea, width=dockWidth,
                       floating=dockFloat, content=qtWin, label="My Custom Dock")

    return qtWin
In this example, we load the ui as a pane docked on the right side of Maya.
path = "C:/path/to/my/window/test01.ui"
qtWin = loadQtUi(path, mode='dock', dockFloat=False, docArea="right")
Note that I believe when authroing windows in Qt Designer, you sould use one of the "Dialog" templates, not the "Main Window" template, since Maya is the 'main window'.
Also, in the designer when you select the "Dialog" object, it's "objectName" field translates to the window name in Maya.

Also see:

SOuP: Basics

PyMel : UI Access

$
0
0
The same way you can wrapper the string name of a node with a PyNode instance, you can do the same with a PyUI instance:
// Mel:
window -title awesome awesomeWin;
columnLayout awesomeCol;
button -label awesomeButton awesomeBut;
showWindow;
# PyMel
import pymel.core as pm

win = pm.ui.PyUI("awesomeWin")
col = pm.ui.PyUI("awesomeCol")
but = pm.ui.PyUI("awesomeBut")

print `win`
print `col`
print `but`

ui.Window('awesomeWin')
ui.ColumnLayout('awesomeWin|awesomeCol')
ui.Button('awesomeWin|awesomeCol|awesomeBut')
All PyMel UI types inheirt from one of the below classes.
pymel.core.uitypes
  • PyUI
    • Methods:
      • asQtObject, delete, getParent, name, parent, rename, shortName, type, window
    • Class Methods:
      • exists
    • Inheritance:
      • Layout
        • Methods:
          • addChild, asQtObject, children, clear, findChild, getChildren, makeDefault, pop, walkChildren
      • Panel
        • Methods
          • copy, getControl, getDockTag, getIsUnique, getLabel, getMenuBarVisible, getNeedsInit, getPopulateMenuProcedure, getTearOff, init, replacePanel, setDocTag, setLabel, setMenuBarVisible, setNeedsInit, setPopupMenuProcedure, setTearOff, unParent.

How can I have Wing send Python or mel code to Maya?

$
0
0
Note: Wing can interact with Maya in three different ways. This is one of the three. See an overview here on the whole system: Interaction between Wing and Maya
The below examples I've gotten to work repeatedly on Windows and Mac.


I use Wing IDE when authoring Python and mel code for Maya, and have come up with a solution (presuming you have the 'Professional' version of Wing) to have the code (Python or mel) you highlight in Wingexecute in Maya (aka 'evaluate selection'). Also known as REPL. This lets me completely replace the Script Editor when authoring Python or mel.
Note that you can have Wing recognize .mel files, with some (not full) context sensitive highlighting, correct indentation, scope hilighting, etc: Under Wing 'Prefs -> Files -> File Types', 'insert' a new file type as mel and set its 'Mime Type' to be C++ Source.

There are a number of steps involved to get this working. I should point out again this only works with the 'Professional' version of Wing, and you'll need Maya v8.5 or newer: when Maya started supporting Python (below this section I list some old code, for version of Maya8.5 and earlier.)

Important Starting Notes

When it comes to opening commandPorts, the port number is fairly arbitrary. In the below examples I use 6000, but you can use another number if you wish. Just make sure to update it in both locations: mayaWingServer.pyand the function send_to_maya() in wingHotkeys.py.

Overview of the below code:

  • Maya launches, creates a listener-server waiting for input from Wing.
  • In Wing, the user executes a hotkey that sends the highlighted text from Wing to a temp text file. At the same time, over a commandPort it pings Maya and tells it to evaluate the text file.
  • Maya's server receives the ping, processes the text file, and evaluates it in Maya, as if it was executed from the Script Editor

#1 - userSetup.py & mayaWingServer.py

Starting with Maya 2013, the only success I've had getting Wing to talk to Maya is over a 'server' connection, rather than a more simplistic commandPort connection.

The module mayaWingServer.py should be authored and placed in the same directory as the user userSetup.py file. When Maya starts up, it should be called to (via userSetup.py) thus launching a listener-server running in a separate thread that will wait for data incoming from Wing, and when it receives it, process the data.
"""
mayaWingServer.py
Author : Eric Pavey - 2012-10-23
"""
import sys
import socket
import threading

import maya.utils as mu
import maya.OpenMaya as om

import executeWingCode

#-----------------
PORT = 6000  # Needs to be the same value as authored in wingHotkeys.py below.
SIZE = 1024
BACKLOG = 5

def processDataInMaya(data):
    """
    This function is designed to be passed as the 'processFunc' arg of
    the mayaServer function.  It is mainly a try\except wrapper around the
    executeWingCode.main() function.

    data : string : The data passed from wing.  Currently this is 'python' or 'mel'.
    """
    try:
        # If we don't evaluate in maya.util.executeInMainThreadWithResult(),
        # Maya can crash, and that's no good.
        mu.executeInMainThreadWithResult(executeWingCode.main, data)
    except Exception, e:
        om.MGlobal.displayError("Encountered exception: %s"%e)

def server(processFunc=processDataInMaya, port=PORT, backlog=BACKLOG, size=SIZE):
    """
    Create a server that will listen for incoming data from Wing, and process it.

    Modified example taken from:
    http://ilab.cs.byu.edu/python/socket/echoserver.html

    The server will wait to recieve data from a single client.  When it receives
    data, it will 'process' it via the processFunc function.

    Parameters :
    processFunc : function : A function object that will
        process the data recieved by the client.  It should accept a single
        string argument.
    port : int : Default to global PORT.  The port to connect to.
    backlog : int : Default to global BACKLOG.  The number of connections the
        server can have waiting.
    size : int : Default to global SIZE.  The size in bytes to recieve back from
        the client.
    """
    host = ''
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.bind((host,port))
    except:
        print "Tried to open port %s, but failed:  It's probably already open\n"%port
        return

    s.listen(backlog)
    print "Starting Python server, listening on port %s...\n"%port
    while True:
        client, address = s.accept() # client is a socket object
        data = client.recv(size)
        if data:
            processFunc(data)
        client.close()

def startServer():
    """
    When Maya starts up, execute this to start the Wing listener server:
    """
    threading.Thread(target=server).start()
The userSetup.py file should import the above module, and call to startSever():
# userSetup.py

import maya.cmds as mc
# Need to defer the execution, or on Mac it can fail...
mc.evalDeferred("import mayaWingServer; mayaWingServer.startServer()", lowestPriority=True)
If you don't have a userSetup.py file, you can make a new one and stick it here (PC):
C:\Users\<USERNAME>\Documents\maya\python\userSetup.py
Or here (Mac):
/Users/<USERNAME>/Library/Preferences/Autodesk/maya/scripts/userSetup.py

Older notes:

Up until Maya 2013, the below code was all that was needed to get a commandPort opened and let Wing talk to Maya. But something happened in 2013 that broke all this, thus the above code was generated.
In Maya's userSetup.mel file, add this line to open a network socket. This will later let Wing talk with Maya.
// userSetup.mel
commandPort -name ":6000" -echoOutput;
It appears, if you're running Maya on Vista \ 64bit, or maybe it's a Maya2010 thing, you need to call to commandPort twice to get this working, otherwise your socket will later be refused:
// userSetup.mel
commandPort -name "127.0.0.1:6000" -echoOutput;
commandPort -name ":6000" -echoOutput;
For whatever reason, having your userSetup.py execute these commands instead won't let the below process work. This really confuses me, since Maya claims the port is open. But Wing says the port is refused....

#2 - wingHotkeys.py

The Wing Python module (wingHotkeys.py) and functions inside are authored to do a few things:
  1. Save the text selected in Wing as a temp file on disk.
  2. Ping Maya through the opened command port, and tell Maya to execute the contents of that file. Depending on the type of data sent, either Python or mel, the tool will tell Maya how to intercept it, and execute it.
Again, this code is tailored to Wing IDE's API, and saved as part of that program's own "scripts" directory.
Default location (on winXP) of that dir is here:
C:\Documents and Settings\<userName>\Application Data\Wing IDE 3\scripts\wingHotkeys.py
On Windows 7:
C:\Users\<userName>\AppData\Roaming\Wing IDE 4\scripts\wingHotkeys.py
On Mac:
/Users/<userName>/.wingide4/scripts/wingHotkeys.py
Note for Mac: The /.wingide4 directory seems to be hidden in Finder. To access it, open a Terminal, cd to that folder, and execute:
$ open .
To launch a Finder to that folder.
Functions:
  • send_to_maya() : Function that does the heavy lifting, and calls to executeWingCode.main() (discussed below).
  • python_to_maya() : Wrapper to send the code as Python to Maya. I have this mapped to ctrl+p. (Wing hotkeys don't allow args, so you need to author wrapper functions)
  • mel_to_maya() : Wrapper to send the code as mel to Maya. I have this mapped to ctrl+m.
The biggest hangup with this system is getting Maya to properly open a commandPort, getting a proper socket.socket() connection, and getting Maya to properly connect via maya.connect(). Based on the network settings of your machine, the below code may not work for you as-provided in all instances. Whenever I change machines I seem to have to modify one or more of these areas.
I've left code-examples (commented out) for other alternatives that I've used on various machines to get these working, so if something fails, you can try using those examples. Otherwise you'll need to strap on your networking programmer hat and dig into the docs a bit.

If you already have a wingHotkeys.py module for Wing, you can just add the below code to it:
# wingHotkeys.py
# Author:  Eric Pavey - warpcat@sbcglobal.net

import wingapi
import socket
import os
import tempfile

def getWingText():
   """
   Based on the Wing API, get the selected text, and return it
   """
   editor = wingapi.gApplication.GetActiveEditor()
   if editor is None:
      return
   doc = editor.GetDocument()
   start, end = editor.GetSelection()
   txt = doc.GetCharRange(start, end)
   return txt

def send_to_maya(language):
   """
   Send the selected code to be executed in Maya

   language : string : either 'mel' or 'python'
   """
   # The port the sever is listening on in mayaWingServer.py :
   commandPort = 6000

   if language != "mel" and language != "python":
      raise ValueError("Expecting either 'mel' or 'python'")

   # Save the text to a temp file.  If we're dealing with mel, make sure it
   # ends with a semicolon, or Maya could become angered!
   txt = getWingText()
   if language == 'mel':
      if not txt.endswith(';'):
         txt += ';'
   # Cross-platform way to get a temp dir:
   tempDir = tempfile.gettempdir()
   tempFile = os.path.join(tempDir, 'wingData.txt')
   f = open(tempFile, "w")
   f.write(txt)
   f.close()

   # Create the socket that will connect to Maya,  Opening a socket can vary from
   # machine to machine, so if one way doesn't work, try another... :-S
   mSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # works in 2013...
   #mSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
   # More generic code for socket creation thanks to Derek Crosby:
   #res = socket.getaddrinfo("localhost", commandPort, socket.AF_UNSPEC, socket.SOCK_STREAM)
   #af, socktype, proto, canonname, sa = res[0]
   #mSocket = socket.socket(af, socktype, proto)

   # Now ping Maya over the command-port
   try:
      # Make our socket-> Maya connection:   There are different connection ways
      # which vary between machines, so sometimes you need to try different
      # solutions to get it to work... :-S
      #mSocket.connect(("127.0.0.1", commandPort)) # works in 2013...
      #mSocket.connect(("::1",commandPort)) 
      mSocket.connect(("localhost", commandPort)) # 2016, mac

      # Send our code to Maya:
      # It is intercepted via the function processDataInMaya(), created via mayaWingServer.py
      mSocket.send(language)
   except Exception, e:
      print "Send to Maya fail:", e

   mSocket.close()

def python_to_maya():
   """Send the selected Python code to Maya"""
   send_to_maya('python')

def mel_to_maya():
   """Send the selected code to Maya as mel"""
   send_to_maya('mel')

#3 - executeWingCode.py

3. The Python module executeWingCode.py is the one Wing's send_to_maya() function (above, step 2) triggers via the Maya listener-sever. It is what physically evaluates the code executed in Wing, in Maya.
Be sure to save this in a location seen by Maya's Python path (probably same dir as userSetup.py).
"""
executeWingCode.py
Eric Pavey - 2011-03-23
Module that Maya calls to when Wing pings it through a socket, telling Maya
to execute the commands in the temp file as either Python or mel code.
"""
import __main__
import os
import tempfile

import maya.OpenMaya as om

def main(codeType):
    """
    Evaluate the temp file on disk, made by Wing, in Maya.

    codeType : string : Supports either 'python' or 'mel'
    """
    # Cross-platform way to get a temp dir:
    tempDir = tempfile.gettempdir()
    tempFile = os.path.join(tempDir, 'wingData.txt').replace("\\", "/")
    if os.access(tempFile , os.F_OK):
        # Print the lines from the file in Maya:
        with open(tempFile, "r") as f:
            for line in f.readlines():
                print line.rstrip()
        print "\n",

        if codeType == "python":
            # execute the file contents in Maya:
            with open(tempFile , "r") as f:
                exec(f, __main__.__dict__, __main__.__dict__)
        elif codeType == "mel":
            melCmd = 'source "%s"'%tempFile
            # This causes the "// Result: " line to show up in the Script Editor:
            om.MGlobal.executeCommand(melCmd, True, True)
    else:
        print "No Wing-generated temp file exists: " + tempFile
The key here for the Python execution, is the exec command updating the __main__.__dict__ dictionary with any defined variable names passed in from Wing. It is effectively adding them to the 'main', or 'builtin' scope of Python. If this doesn't happen, after the code is executed, you won't be able to access any variables created\changed from within Maya.

For mel, calling to OpenMaya.MGlobal.executeCommand allows for the result of the execution to be printed to the Script Editor, just like you had originally executed it there.

#4 - Finish

That's it: You can now highlight code in Wing (either Python or mel), and via a wing hotkey, have it execute directly in Maya. I use it every day...

Older methods:

  • For Maya versions 8 and earlier (Maya 8.5 has Python embedded, yah!)
  • Thanks to Hamish McKenzie "macaroniKazoo" on highend3d.com
  • First, in Maya, create an INET domain on the local host at the command port:
    • Win2000 syntax is "computerName:portNumber", I've wondered why you don't have to specify the computerName here?
commandPort -n ":5055";
  • Second, in Python:
import socket
maya = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
maya.connect(("127.0.0.1", 5055))
  • Then, to actually have Python talk to Maya:
maya.send('print "I am typing in Python, but I see it in Maya!\\n";')
  • Of course, you have to embed your mel commands in the Python syntax.
  • Python library docs on 'socket' HERE
  • What's so special about '127.0.0.1'? Check Wikipedia HERE

How can I make a shelf button via mel?

$
0
0
An easy way to do it is with the textToShelf script that ships with Maya. It lives here:
.../MayaX.X/scripts/startup/textToShelf.mel
Don't forget to save your shelves\prefs after this of course (usually don't when Maya exits, but not always).
Here's the guts of its code, for informative purposes:
global proc textToShelf (string $label, string $script) 
    {
    global string $gShelfTopLevel;
    if (`tabLayout -exists $gShelfTopLevel`) 
        {
        string $currentShelf = `tabLayout -query -selectTab $gShelfTopLevel`;
        setParent $currentShelf;

    //  Create the shelf button on the current shelf.
    //  Give it the default MEL script icon,
    //  and set the short label too.

        shelfButton 
            -command $script
            -label $label
            -annotation $script
            -imageOverlayLabel $label
            -image1 "commandButton.xpm"
            -style `shelfLayout -query -style $currentShelf`
            -width `shelfLayout -query -cellWidth $currentShelf`
            -height `shelfLayout -query -cellHeight $currentShelf`;
        }
    }

Also see:

How can I add Python code as a new shelf button?

$
0
0
Simple tool to add Python code as a button in the active shelf.
import pymel.core as pm

def addPyToShelf(label, pyCode, annotation=""):
    """
    Add the provided Python code as a shelf button, to the current shelf.

    Parameters:
    label : The 5-character label to display on the shelf icon.
    pyCode : string : The code to add to the shelf button.
    annotation : string : Default empty string : Any additional annotation to use
        as a tooltip popup.
    """
    gShelfTopLevel = pm.language.melGlobals['gShelfTopLevel']
    if pm.tabLayout(gShelfTopLevel, query=True, exists=True):
        currentShelf = pm.tabLayout(gShelfTopLevel, query=True, selectTab=True)
        pm.setParent(currentShelf)
        sBut = pm.shelfButton(label=label,
                              imageOverlayLabel=label,
                              command=pyCode,
                              image1='commandButton.png',
                              sourceType='python',
                              ann=annotation,
                              style=pm.shelfLayout(currentShelf, query=True, style=True),
                              width=pm.shelfLayout(currentShelf, query=True, width=True),
                              height=pm.shelfLayout(currentShelf, query=True, height=True))
    else:
        pm.displayWarning("The shelf doesn't appear to exist")
addPyToShelf("test", "import pymel.core as pm\nprint pm.ls(type='transform')",
             annotation="Print all the transforms in the scene")

Also see:

How can I save out all of Maya's icons?

$
0
0
Modified version from this post:
import pymel.core as pm
for item in pm.resourceManager(nameFilter="*.png"):
    pm.resourceManager(saveAs=(item, "C:/temp/maya/icons/{0}".format(item)))

How can I change the icon of a Maya window?

$
0
0
Maya windows have an iconName property that can be set and queried. However, I've never got it to actually change the icon that's in the top-left corner of the window.
Since Maya has adopted PySide, even if you create a window via the Maya window command, the end result is a Qt object. And because of that, we can use PySide to change the icon. Surprisingly easy actually:
import maya.OpenMayaUI as omui
from shiboken import wrapInstance
from PySide.QtGui import QWidget, QIcon

def setWindowIcon(winName, iconPath):
    """
    Convert from a Maya window string name to the QWidget window instance.
    Then set its icon.

    winName : string : The name of the maya 'window' control
    iconPath : string : Full path to icon.png file.
    """
    ptr = omui.MQtUtil.findWindow(winName)
    qwin = wrapInstance(long(ptr), QWidget)
    qwin.setWindowIcon(QIcon(iconPath))
winName = "myAwesomeWindowName"
iconPath = "C:/path/to/some/icon.png"
setWindowIcon(winName, iconPath)

How can I find the resolution of a texture from within Maya?

$
0
0
Via Maya's Python API 2.0, it's pretty easy via MImange:
import maya.api.OpenMaya as om2

def getResolution(imagePath):
    image = om2.MImage()
    image.readFromFile(imagePath)
    x,y = image.getSize()
    return [int(x), int(y)]

If you're using older API 1.0, it's a bit clunkier:
Using OpenMaya.MImage via Python:
# Python code:
import maya.OpenMaya as om

def getResolution(imagePath):

    image = om.MImage()
    image.readFromFile(imagePath)

    # MScriptUtil magic found here:
    # http://download.autodesk.com/us/maya/2010help/api/custom_image_plane_8py-example.html
    # But there was a bug in their code:  You need to make a unique MScriptUtil object
    # for each pointer:  They were sharing one, which caused the result to be the same
    # x,y resolutions, even on rectangular images
 
    # To get the width and height of the image an MScriptUtil is needed
    # to pass in a pointer to the MImage::getSize() method
    scriptUtilW = om.MScriptUtil()
    scriptUtilH = om.MScriptUtil()
    widthPtr = scriptUtilW.asUintPtr()
    heightPtr = scriptUtilH.asUintPtr()

    image.getSize( widthPtr, heightPtr )

    width = scriptUtilW.getUint(widthPtr)
    height = scriptUtilH.getUint(heightPtr)

    return (width, height)
imagePath = r'C:\temp\myImage.BMP'
print getResolution(imagePath)
# (64x64)


getAttr& the file node:

Presuming a texture has been assigned to a file texture node, you can use the .outSizeX and .outSizeY attrs on the file node to get the pixel dimensions.
string $xSize = `getAttr "file1.outSizeX"`;

How can I get a Python dictionary of every mel global variable?

$
0
0
With the invention of PyMel, this is now built in: The pm.language.melGlobals is a dict of exactly that data.
import pymel.core as pm
for key in pm.language.melGlobals.keys():
    val = pm.language.melGlobals[key]
    print key, val

Old docs, for doing it in Python:

mel has the command env() that returns back the name of every global variable in memory at the time. Via Python, this can be nicely wrappered in to a dictionary containing both the global var name, and its values. This really only falls down in regards to matrix (which are converted into lists of lists of floats) and vector data types (which are converted into 3-float tuples), since Python doesn't have those types (by default). But it still handles the conversion ok :)
# Python code
import maya.mel as mm

env = {}
allMelVars = mm.eval('env()')
for v in allMelVars:
    # Convert mel into Python by assigning it to a dummy var the same
    # name as the original var, but with an underscore added to the name.
    # This lets us get around mel global scope naming conflicts if the tool
    # is ran twice:
    pv = mm.eval('%s_ = %s'%(v,v))
    # strip off mel $ prefix:
    env[str(v[1:])] = pv
Now you can use all of Pythons dictionary tools on the env dict.
If you want to print them all nicely:
# Cool Python printing module:
from pprint import pprint
pprint(env)
Viewing all 610 articles
Browse latest View live


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