Maya Python API - Custom Node

I was wondering if anyone could point me in the correct direction for setting up a node similar to the extrude function in that exists in maya.

Currently I’m using an MPxNode, which I set the output to a custom attribute on the selected object. This works correctly (the custom node shows up in the channel box input area of the object selected) however, if I run this on a shape object it does not show up in the channel box under inputs even though the connections are set up the same way in the hypergraph.

I may be going in a completely wrong direction for something similar to the built-in extrude- if so please let me know!


import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.cmds as cmds
import math, sys, string, random

#TEMP use for debugging plugin in case of failure
def randomWord():
	string.letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
	wordLength = random.randint(4,8);
	word = ''
	for i in range(0,wordLength):
		word+=random.choice(string.letters)
	return str(word)
	
kNodeTypeName = randomWord()
kCmdName = "nodeTest"
kNodeId = OpenMaya.MTypeId((random.randint(224288,524288)))
#End TEMP 


# Command to create node, attach to object selected
class BasicCommandTest(OpenMayaMPx.MPxCommand):
	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)
	def doIt(self, args):
		obj = getNode() #Selected
		
		#Add the input attribute for the object you have selected
		nAttr = OpenMaya.MFnNumericAttribute()
		myattr = nAttr.create( "customAttr", "in", OpenMaya.MFnNumericData.kFloat,1.0);
		nAttr.setWritable(True)
		nAttr.setStorable(True)
		nAttr.setReadable(True)
		nAttr.setKeyable(True)
		obj.addAttribute(myattr)
		
		
		#MObject()
		customAttrOutputAttr = obj.attribute(obj.attributeCount()-1) #Just added this, it is last
		
		#MFnDependencyNode()
		cmds.createNode(kNodeTypeName)#This is the new node that is created, which will do everything for me.
		myNode = getNode();
		
		cmds.connectAttr(str(myNode.name())+'.output',str(obj.name())+'.customAttr')
		
def getNode():
	selList = OpenMaya.MSelectionList()
	OpenMaya.MGlobal.getActiveSelectionList(selList)
	parentObject = OpenMaya.MObject ()
	if selList.length():
		selList.getDependNode(0,parentObject)
		node =	OpenMaya.MFnDependencyNode(parentObject)
		return (node)




	
##Custom Node
class rCustomUtilNode(OpenMayaMPx.MPxNode):
	aOutput = OpenMaya.MObject()
	acustomAttr = OpenMaya.MObject()
	# class variables
	def __init__(self):
		OpenMayaMPx.MPxNode.__init__(self)
	def compute(self, plug, dataBlock):
		print "Computing"


def nodeInitializer():
	nAttr = OpenMaya.MFnNumericAttribute()
	cAttr = OpenMaya.MFnCompoundAttribute()

	#Set up for compute
	rCustomUtilNode.aOutput = nAttr.create('output', 'out', OpenMaya.MFnNumericData.kFloat)
	rCustomUtilNode.addAttribute(rCustomUtilNode.aOutput)
	
	#Create input for customAttr
	rCustomUtilNode.acustomAttr = nAttr.create("customAttr", "in", OpenMaya.MFnNumericData.kFloat, 0.0)
	nAttr.setWritable(True)
	nAttr.setStorable(True)
	nAttr.setReadable(True)
	nAttr.setKeyable(True)
	rCustomUtilNode.addAttribute( rCustomUtilNode.acustomAttr )
	rCustomUtilNode.attributeAffects(rCustomUtilNode.acustomAttr, rCustomUtilNode.aOutput) 
	

def cmdCreator():
	return OpenMayaMPx.asMPxPtr(BasicCommandTest())
def cmdSyntaxCreator():
	return OpenMaya.MSyntax()
def nodeCreator():
	return OpenMayaMPx.asMPxPtr( rCustomUtilNode() )



# initialize the script plug-in
def initializePlugin(mobject):
	mplugin = OpenMayaMPx.MFnPlugin(mobject, "Author", "1.0", "Any")
	try:
		mplugin.registerNode( kNodeTypeName, kNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode)
	except:
		sys.stderr.write( "Failed to register node: %s" % kNodeTypeName )
		raise
	try:
		mplugin.registerCommand(kCmdName, cmdCreator, cmdSyntaxCreator)
	except:
		sys.stderr.write("Failed to register command: %s" % kCmdName)
		raise
		
# uninitialize the script plug-in
def uninitializePlugin(mobject):
	mplugin = OpenMayaMPx.MFnPlugin(mobject)
	try:
		mplugin.deregisterCommand(kCmdName)
	except:
		sys.stderr.write("Failed to deregister command: %s" % kCmdName)
		raise
	try:
		mplugin.deregisterNode( kNodeId )
	except:
		sys.stderr.write( "Failed to deregister node: %s" % kNodeTypeName )
		raise

I’m a bit confused about what you are trying to do. Here is how I’m reading it, but correct me if I am wrong.
[ul]
[li] You are making a new Maya node, called (for now) “nodeTest”.
[/li][li] This node has a compound attribute as input and a numeric attribute as output.
[/li][li] Your command:
[/li] creates a new attribute, “customAttr”, on the object itself
creates a “nodeTest” node
connects the output of “nodeTest” to the object’s “customAttr”
[/ul]
So when you update “customAttr” on the node, you want it to update “customAttr” on the object?

Another question: When you say you are trying to do something similar to the built-in extrude, do you mean that you want your node to modify the mesh? Right now its only output is numeric. If you want to modify the mesh, I recommend looking at two of the example files in the “devkit” folder of Maya: polyModifier.py and splitUVCmd.py. PolyModifier.py handles inserting the new node into the construction history of the selected mesh. SplitUVCmd.py is an example of how to subclass from polyModifier to make your own node that gets inserted into the object’s construction history.

Thanks for the reply, I’ll elaborate:

  • You are making a new Maya node, called (for now) “nodeTest”.
  • This node has a numeric attribute as input and a numeric attribute as output.

Command:

  • creates a new attribute, “customAttr”, on the object itself (Which should be the shape node, since you will have faces selected) - isn’t in the script to check for this at the moment.
  • creates a “nodeTest” node
  • connects the output of “nodeTest” to the object’s “customAttr”

Results:
Connection works correctly, however the “nodeTest” node does not show up in the attribute window (under inputs) of the shape object with “customAttr” attached.

As far as your other question: I’m remaking my inset tool to work correctly as a maya tool should work (see: http://www.creativecrash.com/maya/downloads/scripts-plugins/modeling/poly-tools/c/maya-inset-tool). Currently i’m only using a numeric attribute to try and get the visual functionality to work. I’ll look in to those two examples more though, perhaps I’m skipping a step, and by connecting the node in to the construction history it might do what I need.

Yeah, those two files should definitely help you figure out how to insert your node into the construction history so it will show up in the Inputs section of the channel box. One thing worth mentioning, though, if you decide to subclass from polyModifier: it seems to have a bug in the case where your object has no construction history but construction history is turned on. So you may want to test on objects with construction history, or you may be left wondering why your node STILL isn’t showing up. (Or you can choose not to subclass from polyModifier, in which case the bug isn’t an issue.)