Your First Plug-in

As an introduction to the Maya API, we will create a simple command plug-in.  This will show you template code that is common in all plug-ins as well as display various Maya API concepts discussed earlier.  The command will simply print text into the script editor.

In all plug-ins, you need to implement 3 common functions:

  • initializePlugin – Called when the plug-in is loaded.  Used to register new commands, tools, nodes, etc with Maya.
  • uninitializePlugin – Called when the plug-in is unloaded.  Used to de-register whatever was registered in initializedPlugin.
  • creator – Maya calls this to create a new instance of the object, such as when createNode is called or the command is called.

These functions look like the following in our HelloWorld command:

void* HelloWorld::creator() { return new HelloWorld; }

MStatus initializePlugin(MObject obj) {
  MFnPlugin plugin(obj, "Chad Vernon", "1.0", "Any");
  MStatus status = plugin.registerCommand("helloWorld", HelloWorld::creator);
  CHECK_MSTATUS_AND_RETURN_IT(status);
  return status;
}

MStatus uninitializePlugin(MObject obj) {
  MFnPlugin plugin(obj);
  MStatus status = plugin.deregisterCommand("helloWorld");
  CHECK_MSTATUS_AND_RETURN_IT(status);
  return status;
}

This is boiler plate code that is usually copied and pasted into all of my plug-ins and altered just slightly to include all the nodes/commands/deformers included in the plug-in.  The code simply registers and deregisters any new nodes, commands, etc. that our plug-in contains.  This is also where we tell Maya what type of node we are creating, such as if it is a normal dependency node, a deformer, a custom locator, an ik solver, a constraint, etc.

You can read about the specifics of these functions in the documentation, but this is where we can specify a plug-in version number, a required Maya version, plug-in author, etc.

Since we are implementing a new command, we need to create a class that inherits from the proxy class, MPxCommand:

#ifndef HELLOWORLD_H
#define HELLOWORLD_H

#include <maya/MArgList.h>
#include <maya/MObject.h>
#include <maya/MGlobal.h>
#include <maya/MPxCommand.h>

class HelloWorld : public MPxCommand {
 public:
  HelloWorld() {};
  virtual MStatus doIt(const MArgList&);
  static void* creator();
};
#endif

The above code shows the header declaration for our HelloWorld command.  We begin by including the necessary header files.  Each class in Maya has its own header file, so if you use a specific class in your plug-in, you need to include its header file in order to use it.

The documentation for MPxCommand lists many different functions that we can choose to implement. Since this is our first plug-in, we will only implement the one necessary function for commands: the doIt function.  When we end up calling our new command in Maya, Maya will create our new HelloWorld object and then call the doIt function of that object.  The doIt function looks like this:

MStatus HelloWorld::doIt(const MArgList&) {
  MGlobal::displayInfo("Hello World!");
  return MS::kSuccess;
}

MPxCommand::doIt accepts an MArgList object, which is used for passing in command arguments.  We will learn how to use that in a later section.  The only line of interest in this function is the MGlobal::displayInfo call.  MGlobal is a class that provides lots of useful functionality such as printing text and selecting objects.  Here, we are simply printing some text.

Once the plug-in is compiled and loaded, we can call the command with:

import maya.cmds as cmds
cmds.helloWorld()

The entire plug-in looks like this:

#ifndef HELLOWORLD_H
#define HELLOWORLD_H

#include <maya/MArgList.h>
#include <maya/MObject.h>
#include <maya/MGlobal.h>
#include <maya/MPxCommand.h>

class HelloWorld : public MPxCommand {
 public:
  HelloWorld() {};
  virtual MStatus doIt(const MArgList& argList);
  static void* creator();
};
#endif
#include "include/HelloWorldCmd.h"
#include <maya/MFnPlugin.h>

void* HelloWorld::creator() { return new HelloWorld; }

MStatus HelloWorld::doIt(const MArgList& argList) {
  MGlobal::displayInfo("Hello World!");
  return MS::kSuccess;
}

MStatus initializePlugin(MObject obj) {
  MFnPlugin plugin(obj, "Chad Vernon", "1.0", "Any");
  MStatus status = plugin.registerCommand("helloWorld", HelloWorld::creator);
  CHECK_MSTATUS_AND_RETURN_IT(status);
  return status;
}

MStatus uninitializePlugin(MObject obj) {
  MFnPlugin plugin(obj);
  MStatus status = plugin.deregisterCommand("helloWorld");
  CHECK_MSTATUS_AND_RETURN_IT(status);
  return status;
}

One thing to keep in mind is that maya/MFnPlugin.h should only be included once in your plug-in.  This header file is necessary to register your plug-in with Maya.  If you include it in multiple source files in your plug-in, you’ll get an error.  If your plug-in has multiple nodes and commands, you’ll probably put the initializePlugin and uninitializePlugin functions in a separate file, so just include MFnPlugin in that file.

The identical Python implementation of the command is:

import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx

class HelloWorld(OpenMayaMPx.MPxCommand):
    def __init__(self):
        OpenMayaMPx.MPxCommand.__init__(self)

    def doIt(self, argList):
        print 'Hello World!'

def creator():
    return OpenMayaMPx.asMPxPtr( HelloWorld() )

def initializePlugin(obj):
    plugin = OpenMayaMPx.MFnPlugin(obj, 'Chad Vernon', '1.0', 'Any')
    try:
        plugin.registerCommand('helloWorld', creator)
    except:
        raise RuntimeError, 'Failed to register command'

def uninitializePlugin(obj):
    plugin = OpenMayaMPx.MFnPlugin(obj)
    try:
        plugin.deregisterCommand('helloWorld')
    except:
        raise RuntimeError, 'Failed to unregister command'

In Python, we can either use the MGlobal class to print text or we can just use the built-in Python print command.

Now that we have introduced the Maya API, we can start learning how to implement more interesting and useful plug-ins.

8 thoughts on “Your First Plug-in”

Jiri September 27, 2011 at 10:16 am

Thank you very much for this tutorial, its really helpful 🙂 … love your work!

Dariusz September 15, 2013 at 4:32 am

Heya

Right so I’m very new to C++ which is probably why I’m failing in any case I made the 2 files HelloWorldCmd.h HelloWorldCmd.cpp I put in the same stuff you did. Now when I try to execute it I get bunch of errors one of which is “Error C1083: Cannot open include file: ‘include/HelloWorldCmd.h’: No such file or directory. I guess he somehow cant see file in his own project directory soo how can I fix that ?

Natt M. September 25, 2013 at 10:27 am

Chad,
Great explanation, you do such an amazing job of clarifying things by example. Please keep up the good work!
All the best.

HGH October 12, 2013 at 3:09 pm

Do you have any idea how to reload a python plugin that spans multiple files without restarting Maya?
I’ve looked in several solutions and none of them worked for me.

Chad October 18, 2013 at 5:22 pm

Unless you have reloads in all your scripts (not recommended), you will need to restart Maya.

Rachel February 9, 2015 at 8:54 am

This is great, BUT it looks like Syntax Highlighter has interpreted the #include directives as some kind of HTML tag or similar, on Chrome at least. I thought I was looking at some weird C++ syntax I’d never seen before.

Chad February 11, 2015 at 8:59 am

Yeah looks like some weird bug. I’ll need to wait for an update to the plug-in for a fix.

Leave A Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

<code> For inline code.
[sourcecode] For multiline code.