Repository: ADN-DevTech/Maya-Training-Material Branch: master Commit: b4c2c7b71e18 Files: 220 Total size: 15.2 MB Directory structure: gitextract_xa2stlhf/ ├── .gitignore ├── 00_API_Overview_Introduction/ │ ├── 00_API_Overview_Introduction.pptx │ └── 00_Distinguishing Python.pptx ├── 01_API_Overview/ │ ├── 01_API_Overview.pptx │ ├── 01_Assignment.docx │ ├── 02_API_Overview.pptx │ └── helloWorld/ │ ├── Exercise - py/ │ │ └── helloWorldCmd.py │ └── Solution - py/ │ └── helloWorldCmd.py ├── 02_Commands/ │ ├── 02_Assignment.docx │ ├── 02_Commands.pptx │ ├── 03_Helper Classes.pptx │ ├── 04_CommandsArguments.pptx │ ├── 04_UndoRedo.pptx │ ├── 05_UndoRedo.pptx │ ├── dagInfo/ │ │ ├── Exercise - C++/ │ │ │ ├── dagInfo.cpp │ │ │ ├── dagInfo.h │ │ │ ├── dagInfo.sln │ │ │ ├── dagInfo.vcxproj │ │ │ └── pluginMain.cpp │ │ ├── Exercise - py/ │ │ │ └── dagInfo.py │ │ ├── Solution - C++/ │ │ │ ├── dagInfo.cpp │ │ │ ├── dagInfo.h │ │ │ ├── dagInfo.sln │ │ │ ├── dagInfo.vcxproj │ │ │ └── pluginMain.cpp │ │ ├── Solution - py/ │ │ │ └── dagInfo.py │ │ └── multiInstance.ma │ ├── instanceRotate/ │ │ ├── Exercise - C++/ │ │ │ ├── instanceRotate.sln │ │ │ ├── instanceRotate.vcxproj │ │ │ ├── instanceRotateCmd.cpp │ │ │ ├── instanceRotateCmd.h │ │ │ └── pluginMain.cpp │ │ ├── Exercise - py/ │ │ │ └── instanceRotateCmd.py │ │ ├── Solution - C++/ │ │ │ ├── instanceRotate.sln │ │ │ ├── instanceRotate.vcxproj │ │ │ ├── instanceRotateCmd.cpp │ │ │ ├── instanceRotateCmd.h │ │ │ └── pluginMain.cpp │ │ └── Solution - py/ │ │ └── instanceRotateCmd.py │ └── nodeInfo/ │ ├── Exercise - C++/ │ │ ├── nodeInfoCmd.cpp │ │ ├── nodeInfoCmd.h │ │ ├── nodeInfoCmd.sln │ │ ├── nodeInfoCmd.vcxproj │ │ └── pluginMain.cpp │ ├── Exercise - py/ │ │ └── nodeInfoCmd.py │ ├── Solution - C++/ │ │ ├── nodeInfoCmd.cpp │ │ ├── nodeInfoCmd.h │ │ ├── nodeInfoCmd.sln │ │ ├── nodeInfoCmd.vcxproj │ │ └── pluginMain.cpp │ └── Solution - py/ │ └── nodeInfoCmd.py ├── 03_Nodes/ │ ├── 03_Assignment.docx │ ├── 03_Nodes.pptx │ ├── simpleNode/ │ │ ├── Exercise - C++/ │ │ │ ├── pluginMain.cpp │ │ │ ├── simpleNode.cpp │ │ │ ├── simpleNode.h │ │ │ ├── simpleNode.sln │ │ │ └── simpleNode.vcxproj │ │ ├── Exercise - py/ │ │ │ └── simpleNode.py │ │ ├── Solution - C++/ │ │ │ ├── pluginMain.cpp │ │ │ ├── simpleNode.cpp │ │ │ ├── simpleNode.h │ │ │ ├── simpleNode.sln │ │ │ └── simpleNode.vcxproj │ │ └── Solution - py/ │ │ └── simpleNode.py │ ├── sineNode/ │ │ ├── Exercise - C++/ │ │ │ ├── pluginMain.cpp │ │ │ ├── simpleNode.cpp │ │ │ ├── simpleNode.h │ │ │ ├── simpleNode.sln │ │ │ └── simpleNode.vcxproj │ │ ├── Exercise - py/ │ │ │ └── sineNode.py │ │ ├── Solution - C++/ │ │ │ ├── pluginMain.cpp │ │ │ ├── simpleNode.cpp │ │ │ ├── simpleNode.h │ │ │ ├── simpleNode.sln │ │ │ └── simpleNode.vcxproj │ │ └── Solution - py/ │ │ └── sineNode.py │ └── transCircleNode/ │ ├── Exercise - C++/ │ │ ├── AEtransCircleTemplate.mel │ │ ├── pluginMain.cpp │ │ ├── transCircleNode.cpp │ │ ├── transCircleNode.h │ │ ├── transCircleNode.mel │ │ ├── transCircleNode.sln │ │ └── transCircleNode.vcxproj │ ├── Exercise - py/ │ │ ├── AEtransCircleTemplate.mel │ │ ├── transCircleNode.mel │ │ └── transCircleNode.py │ ├── Solution - C++/ │ │ ├── AEtransCircleTemplate.mel │ │ ├── pluginMain.cpp │ │ ├── transCircleNode.cpp │ │ ├── transCircleNode.h │ │ ├── transCircleNode.mel │ │ ├── transCircleNode.sln │ │ └── transCircleNode.vcxproj │ └── Solution - py/ │ ├── AEtransCircleTemplate.mel │ ├── transCircleNode.mel │ └── transCircleNode.py ├── 04_NodeAttributes/ │ ├── 04_Assignment.docx │ ├── 04_NodeAttributes.pptx │ ├── dynNode/ │ │ ├── Exercise - C++/ │ │ │ ├── DynNode.sln │ │ │ ├── DynNode.vcxproj │ │ │ ├── dynNode.cpp │ │ │ ├── dynNode.h │ │ │ └── pluginMain.cpp │ │ ├── Exercise - py/ │ │ │ └── dynNode.py │ │ ├── Solution - C++/ │ │ │ ├── DynNode.sln │ │ │ ├── DynNode.vcxproj │ │ │ ├── dynNode.cpp │ │ │ ├── dynNode.h │ │ │ └── pluginMain.cpp │ │ └── Solution - py/ │ │ └── dynNode.py │ └── simpleNode - with Typed Attr/ │ ├── Exercise - C++/ │ │ ├── pluginMain.cpp │ │ ├── simpleNode.cpp │ │ ├── simpleNode.h │ │ ├── simpleNode.sln │ │ └── simpleNode.vcxproj │ ├── Exercise - py/ │ │ └── simpleNode.py │ ├── Solution - C++/ │ │ ├── pluginMain.cpp │ │ ├── simpleNode.cpp │ │ ├── simpleNode.h │ │ ├── simpleNode.sln │ │ └── simpleNode.vcxproj │ └── Solution - py/ │ └── simpleNode.py ├── 05_DependencyGraph/ │ ├── 05_Assignment.docx │ ├── 05_DependencyGraph.pptx │ └── retrieveWeight/ │ ├── Exercise - C++/ │ │ ├── pluginMain.cpp │ │ ├── retrieveWeight.sln │ │ ├── retrieveWeight.vcxproj │ │ ├── retrieveWeightCmd.cpp │ │ └── retrieveWeightCmd.h │ ├── Exercise - py/ │ │ └── retrieveWeight.py │ ├── Solution - C++/ │ │ ├── pluginMain.cpp │ │ ├── retrieveWeight.sln │ │ ├── retrieveWeight.vcxproj │ │ ├── retrieveWeightCmd.cpp │ │ └── retrieveWeightCmd.h │ ├── Solution - py/ │ │ └── retrieveWeight.py │ └── blendShape.ma ├── 06_MiscTools/ │ ├── 06_Assignment.docx │ ├── 06_MiscTools.pptx │ ├── sceneMsg/ │ │ ├── Exercise - C++/ │ │ │ ├── pluginMain.cpp │ │ │ ├── sceneMsgCmd.cpp │ │ │ ├── sceneMsgCmd.h │ │ │ ├── sceneMsgCmd.sln │ │ │ └── sceneMsgCmd.vcxproj │ │ ├── Exercise - py/ │ │ │ └── sceneMsgCmd.py │ │ ├── Solution - C++/ │ │ │ ├── pluginMain.cpp │ │ │ ├── sceneMsgCmd.cpp │ │ │ ├── sceneMsgCmd.h │ │ │ ├── sceneMsgCmd.sln │ │ │ └── sceneMsgCmd.vcxproj │ │ └── Solution - py/ │ │ └── sceneMsgCmd.py │ └── setUpTransCircle/ │ ├── Exercise - C++/ │ │ ├── AEtransCircleTemplate.mel │ │ ├── pluginMain.cpp │ │ ├── setUpTransCircle.sln │ │ ├── setUpTransCircle.vcxproj │ │ ├── setUpTransCircleCmd.cpp │ │ ├── setUpTransCircleCmd.h │ │ ├── transCircleNode.cpp │ │ └── transCircleNode.h │ ├── Exercise - py/ │ │ └── setUpTransCircle.py │ ├── Solution - C++/ │ │ ├── AEtransCircleTemplate.mel │ │ ├── pluginMain.cpp │ │ ├── setUpTransCircle.sln │ │ ├── setUpTransCircle.vcxproj │ │ ├── setUpTransCircleCmd.cpp │ │ ├── setUpTransCircleCmd.h │ │ ├── transCircleNode.cpp │ │ └── transCircleNode.h │ └── Solution - py/ │ └── setUpTransCircle.py ├── 07_Locator/ │ ├── 07_Assignment.docx │ ├── 07_Locator.pptx │ └── arrowLocator/ │ ├── Exercise - C++/ │ │ ├── arrowLocator.sln │ │ ├── arrowLocator.vcxproj │ │ ├── arrowLocatorNode.cpp │ │ └── arrowLocatorNode.h │ ├── Exercise - py/ │ │ └── arrowLocator.py │ ├── Solution - C++/ │ │ ├── arrowLocator.sln │ │ ├── arrowLocator.vcxproj │ │ ├── arrowLocatorNode.cpp │ │ └── arrowLocatorNode.h │ └── Solution - py/ │ └── arrowLocator.py ├── 08_Manipulators/ │ ├── 08_Assignment.docx │ ├── 08_Manipulators.pptx │ └── arrowLocatorManip/ │ ├── Exercise - C++/ │ │ ├── arrowLocatorManip.sln │ │ ├── arrowLocatorManip.vcxproj │ │ ├── arrowLocatorManipNode.cpp │ │ ├── arrowLocatorManipNode.h │ │ ├── arrowLocatorNode.cpp │ │ └── arrowLocatorNode.h │ ├── Exercise - py/ │ │ └── arrowLocatorManip.py │ ├── Solution - C++/ │ │ ├── arrowLocatorManip.sln │ │ ├── arrowLocatorManip.vcxproj │ │ ├── arrowLocatorManipNode.cpp │ │ ├── arrowLocatorManipNode.h │ │ ├── arrowLocatorNode.cpp │ │ └── arrowLocatorNode.h │ └── Solution - py/ │ └── arrowLocatorManip.py ├── 09_PythonAPI/ │ ├── 09_Assignment.docx │ ├── 09_Python 2.0.pptx │ ├── 09_Python Scripting Exercise.pptx │ ├── 09_PythonAPI.pptx │ ├── 09_ReadingC++Docs.pptx │ ├── helloWorld/ │ │ ├── Exercise - py/ │ │ │ └── helloWorldCmd.py │ │ └── Solution - py/ │ │ └── helloWorldCmd.py │ └── sineNode/ │ ├── Exercise - py/ │ │ └── sineNode.py │ ├── Solution - py/ │ │ └── sineNode.py │ └── sineNode-setup.mel ├── 10_PythonAdvanced/ │ ├── 10_PythonAdvanced.ppt │ ├── DemoInstructions.docx │ └── examples/ │ ├── ShotServer.py │ ├── alt_str.py │ ├── cppCentroid.cpp │ ├── dist.py │ ├── guipdb.py │ ├── guipdb1.py │ └── pyCentroid.py ├── AdditionalDocuments/ │ ├── Introduction to Maya API Summary.pptx │ └── MELvsPython.ppt └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ build/ [Bb]in/ [Oo]bj/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets !packages/*/build/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.log *.scc # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch *.ncrunch* .*crunch*.local.xml # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.Publish.xml *.pubxml # NuGet Packages Directory ## TODO: If you have NuGet Package Restore enabled, uncomment the next line #packages/ # Windows Azure Build Output csx *.build.csdef # Windows Store app package directory AppPackages/ # Others sql/ *.Cache ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.[Pp]ublish.xml *.pfx *.publishsettings # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files App_Data/*.mdf App_Data/*.ldf # ========================= # Windows detritus # ========================= # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Mac crap .DS_Store # Compiled Object files *.slo *.lo *.o # Compiled Dynamic libraries *.so *.dylib # Compiled Static libraries *.lai *.la *.a ================================================ FILE: 01_API_Overview/helloWorld/Exercise - py/helloWorldCmd.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. # Python script to execute to test the sample in the Maya Script Editor # import maya # maya.cmds.loadPlugin("helloWorldCmd.py") # maya.cmds.spHelloWorld() #- Import all the necessary modules here #TODO: ... kPluginCmdName = "spHelloWorld" # class implementation for custom command class scriptedCommand(OpenMayaMPx.MPxCommand): #- TODO: Add Implementation of __init__(self) and doIt(self,argList) #... # Creator #- TODO: Implement the creator function and apply asMPxPtr() to it #... # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Register this custom command #... except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Deregister this custom command #... except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) raise ================================================ FILE: 01_API_Overview/helloWorld/Solution - py/helloWorldCmd.py ================================================ # Copyright (C) # # File: helloWorld.py # # Author: Autodesk Developer Network # Python script to execute to test the sample in the Maya Script Editor # import maya # maya.cmds.loadPlugin("helloWorldCmd.py") # maya.cmds.spHelloWorld() #- Import all the necessary modules here import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginCmdName = "spHelloWorld" # class implementation for custom command class scriptedCommand(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self,argList): print "Hello World!" # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( scriptedCommand() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) raise ================================================ FILE: 02_Commands/dagInfo/Exercise - C++/dagInfo.cpp ================================================ // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include "dagInfo.h" #include #include #include #include #include #include #include #include #include #include //- This method performs the action of the command. It iterates over all //- selected items and prints out connected plug and dependency node type //- information. MStatus dagInfo::doIt(const MArgList& ) { MStatus stat; //- Select all objects currently selected into the Maya editor. MSelectionList slist; MGlobal::getActiveSelectionList( slist ); //- Create an iterator on the selection list (using the iterator pattern). MItSelectionList iter( slist, MFn::kDagNode,&stat ); //- Iterate over all selected dependency nodes for ( ; !iter.isDone(); iter.next() ) { //- get the dependency node first and then apply MFnDagNode function set onto it. MObject depNode; iter.getDependNode(depNode); MFnDagNode fnDag(depNode); cout<<"********************************************************"< // Command class declaration class dagInfo : public MPxCommand { public: dagInfo() {} virtual ~dagInfo() {} static void *creator() { return new dagInfo(); } //- This method should perform a command by setting up internal class data //- and then calling the redoIt method if undo is supported by the command. //- The actual action performed by the command should be done in the redoIt //- method. This is a pure virtual method, and must be overridden in derived //- classes. virtual MStatus doIt(const MArgList &); }; ================================================ FILE: 02_Commands/dagInfo/Exercise - C++/dagInfo.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dagInfo", "dagInfo.vcxproj", "{62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Debug|x64.ActiveCfg = Debug|x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Debug|x64.Build.0 = Debug|x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Release|x64.ActiveCfg = Release|x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 02_Commands/dagInfo/Exercise - C++/dagInfo.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/dagInfo.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaAnim.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\dagInfo.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/dagInfo.pdb Debug/dagInfo.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/dagInfo.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaAnim.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\dagInfo.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/dagInfo.pdb Debug/dagInfo.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/dagInfo.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\dagInfo.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/dagInfo.pdb Release/dagInfo.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/dagInfo.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\dagInfo.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/dagInfo.pdb Release/dagInfo.lib ================================================ FILE: 02_Commands/dagInfo/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include #include "dagInfo.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand("dagInfo",dagInfo::creator); return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand("dagInfo"); return status; } ================================================ FILE: 02_Commands/dagInfo/Exercise - py/dagInfo.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx # Command name kPluginCmdName = "dagInfo" # dagInfo command class dagInfo(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) #- This method performs the action of the command. It iterates over all #- selected items and prints out connected plug and dependency node type #- information. def doIt(self, args): #- Select all objects currently selected into the Maya editor. slist = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList( slist ) #- Create an iterator on the selection list (using the iterator pattern). iter = OpenMaya.MItSelectionList( slist, OpenMaya.MFn.kDagNode ) #- Iterate over all selected dependency nodes while ( iter.isDone() == 0 ): #- Not getting the dag path, it will only return one path. I.e.: #dagPath = OpenMaya.MDagPath #iter.getDagPath(dagPath) #- Instead, get the dependency node first and then apply MFnDagNode function set onto it. depNode = OpenMaya.MObject() iter.getDependNode(depNode) fnDag = OpenMaya.MFnDagNode(depNode) print "********************************************************" sys.stdout.write( '\n' ) print "The selected node name is %s" % fnDag.name() print ", node type : %s" % depNode.apiTypeStr() sys.stdout.write( '\n' ) #- TODO: Retrieve number of instances on this dag node num = #... if( num != 1 ): print "Number of instances on this node is : %d" % num sys.stdout.write( '\n' ) # Save out the MMatrix __str__ function so we can replace it once were done oldMMatrix_str = OpenMaya.MMatrix .__str__ # Call my new printing function to print the matrix so that is it readable OpenMaya.MMatrix.__str__ = myMatrix_str #- TODO: Retrieve all the instanced paths of this dag node and print out them dagPathArray = OpenMaya.MDagPathArray() #... for j in range (0, dagPathArray.length()): instanceDagPath = dagPathArray[j] #- TODO: Get this instance full dag path and print it #... sys.stdout.write( '\n' ) #- TODO: Get the exclusive matrix of this node exMatrix = #... print "The exclusive transformation matrix of this node is " print exMatrix sys.stdout.write( '\n' ) #- TODO: Get the inclusive matrix of this node #- If it is a shape node, the inclusive and exclusive matrix should be the same #- If it is a transform node and its transformation matrix is not identity, they #- should be different! inMatrix = #... print "The inclusive transformation matrix of this node is " print inMatrix sys.stdout.write( '\n' ) #- TODO: If this dag node is a transform node, also get its local transformation matrix if ( #... ): fnTrans = OpenMaya.MFnTransform(instanceDagPath) localMatrix = fnTrans.transformation() print "The local transformation matrix represented by this transform node is " print localMatrix.asMatrix() sys.stdout.write( '\n' ) iter.next() # Replace MMatrix __str__ function to the default OpenMaya.MMatrix.__str__ = oldMMatrix_str # New __str__ function for Making the matrix readable.... def myMatrix_str(self): return "[[%g,%g,%g,%g][%g,%g,%g,%g][%g,%g,%g,%g][%g,%g,%g,%g]]" % (self(0,0), self(0,1), self(0,2), self(0,3), self(1,0), self(1,1), self(1,2), self(1,3), self(2,0), self(2,1), self(2,2), self(2,3), self(3,0), self(3,1), self(3,2), self(3,3)) # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( dagInfo() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) ================================================ FILE: 02_Commands/dagInfo/Solution - C++/dagInfo.cpp ================================================ // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include "dagInfo.h" #include #include #include #include #include #include #include #include #include #include //- This method performs the action of the command. It iterates over all //- selected items and prints out connected plug and dependency node type //- information. MStatus dagInfo::doIt(const MArgList& ) { MStatus stat; //- Select all objects currently selected into the Maya editor. MSelectionList slist; MGlobal::getActiveSelectionList( slist ); //- Create an iterator on the selection list (using the iterator pattern). MItSelectionList iter( slist, MFn::kDagNode,&stat ); //- Iterate over all selected dependency nodes for ( ; !iter.isDone(); iter.next() ) { //- get the dependency node first and then apply MFnDagNode function set onto it. MObject depNode; iter.getDependNode(depNode); MFnDagNode fnDag(depNode); cout<<"********************************************************"< // Command class declaration class dagInfo : public MPxCommand { public: dagInfo() {} virtual ~dagInfo() {} static void *creator() { return new dagInfo(); } //- This method should perform a command by setting up internal class data //- and then calling the redoIt method if undo is supported by the command. //- The actual action performed by the command should be done in the redoIt //- method. This is a pure virtual method, and must be overridden in derived //- classes. virtual MStatus doIt(const MArgList &); }; ================================================ FILE: 02_Commands/dagInfo/Solution - C++/dagInfo.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dagInfo", "dagInfo.vcxproj", "{62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Debug|x64.ActiveCfg = Debug|x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Debug|x64.Build.0 = Debug|x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Release|x64.ActiveCfg = Release|x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 02_Commands/dagInfo/Solution - C++/dagInfo.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {62B3E8DE-B8B9-4DEF-99F4-78E2EA80E56B} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ .mll C:\MayaAPITraining\plug-ins\ Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/dagInfo.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaAnim.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\dagInfo.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/dagInfo.pdb Debug/dagInfo.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/dagInfo.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaAnim.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\dagInfo.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/dagInfo.pdb Debug/dagInfo.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/dagInfo.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\dagInfo.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/dagInfo.pdb Release/dagInfo.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/dagInfo.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\dagInfo.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/dagInfo.pdb Release/dagInfo.lib ================================================ FILE: 02_Commands/dagInfo/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include #include "dagInfo.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2012", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand("dagInfo",dagInfo::creator); return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand("dagInfo"); return status; } ================================================ FILE: 02_Commands/dagInfo/Solution - py/dagInfo.py ================================================ # Copyright (C) # # File: dagInfo.py # # Author: Autodesk Developer Network import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx # Command name kPluginCmdName = "dagInfo" # dagInfo command class dagInfo(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) #- This method performs the action of the command. It iterates over all #- selected items and prints out connected plug and dependency node type #- information. def doIt(self, args): #- Select all objects currently selected into the Maya editor. slist = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList( slist ) #- Create an iterator on the selection list (using the iterator pattern). iter = OpenMaya.MItSelectionList( slist, OpenMaya.MFn.kDagNode ) #- Iterate over all selected dependency nodes while ( iter.isDone() == 0 ): #- Not getting the dag path, it will only return one path. I.e.: #dagPath = OpenMaya.MDagPath #iter.getDagPath(dagPath) #- Instead, get the dependency node first and then apply MFnDagNode function set onto it. depNode = OpenMaya.MObject() iter.getDependNode(depNode) fnDag = OpenMaya.MFnDagNode(depNode) print "********************************************************" sys.stdout.write( '\n' ) print "The selected node name is %s, node type : %s" % (fnDag.name(), depNode.apiTypeStr()) sys.stdout.write( '\n' ) #- Retrieve number of instances on this dag node num = fnDag.instanceCount(1) if( num != 1 ): print "Number of instances on this node is : %d" % num sys.stdout.write( '\n' ) #Save out the MMatrix __str__ function so we can replace it once were done oldMMatrix_str = OpenMaya.MMatrix .__str__ # Call my new printing function to print the matrix so that is it readable OpenMaya.MMatrix.__str__ = myMatrix_str #- Retrieve all the instanced paths of this dag node and print out them dagPathArray = OpenMaya.MDagPathArray() fnDag.getAllPaths(dagPathArray) for j in range (0, dagPathArray.length()): instanceDagPath = dagPathArray[j] print "Dag Path %d for this node: %s" % (j, instanceDagPath.fullPathName()) sys.stdout.write( '\n' ) #- Get the exclusive matrix of this node exMatrix = instanceDagPath.exclusiveMatrix() print "The exclusive transformation matrix of this node is:" print exMatrix sys.stdout.write( '\n' ) #- Get the inclusive matrix of this node #- If it is a shape node, the inclusive and exclusive matrix should be the same #- If it is a transform node and its transformation matrix is not identity, they #- should be different! inMatrix = instanceDagPath.inclusiveMatrix() print "The inclusive transformation matrix of this node is:" print inMatrix sys.stdout.write( '\n' ) #- If this dag node is a transform node, also get its local transformation matrix if (depNode.hasFn(OpenMaya.MFn.kTransform)): fnTrans = OpenMaya.MFnTransform(instanceDagPath) localMatrix = fnTrans.transformation() print "The local transformation matrix represented by this transform node is:" print localMatrix.asMatrix() sys.stdout.write( '\n' ) iter.next() # Replace MMatrix __str__ function to the default OpenMaya.MMatrix.__str__ = oldMMatrix_str # New __str__ function for Making the matrix readable.... def myMatrix_str(self): return "[[%g,%g,%g,%g][%g,%g,%g,%g][%g,%g,%g,%g][%g,%g,%g,%g]]" % (self(0,0), self(0,1), self(0,2), self(0,3), self(1,0), self(1,1), self(1,2), self(1,3), self(2,0), self(2,1), self(2,2), self(2,3), self(3,0), self(3,1), self(3,2), self(3,3)) # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( dagInfo() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) ================================================ FILE: 02_Commands/dagInfo/multiInstance.ma ================================================ //Maya ASCII 2012 scene //Name: multiInstance.ma //Last modified: Sun, Sep 25, 2011 11:03:05 PM //Codeset: 1252 requires maya "2012"; currentUnit -l centimeter -a degree -t film; fileInfo "application" "maya"; fileInfo "product" "Maya 2012"; fileInfo "version" "2012 Hotfix 1"; fileInfo "cutIdentifier" "001200000000-798788"; fileInfo "osv" "Microsoft Windows XP Professional Service Pack 3 (Build 2600)\n"; createNode transform -s -n "persp"; setAttr ".v" no; setAttr ".t" -type "double3" 36.204867073134864 24.239823589777796 10.518486229164782 ; setAttr ".r" -type "double3" -32.738352729661635 73.799999999992863 1.1400200983521435e-014 ; createNode camera -s -n "perspShape" -p "persp"; setAttr -k off ".v" no; setAttr ".fl" 34.999999999999993; setAttr ".coi" 44.82186966202994; setAttr ".imn" -type "string" "persp"; setAttr ".den" -type "string" "persp_depth"; setAttr ".man" -type "string" "persp_mask"; setAttr ".hc" -type "string" "viewSet -p %camera"; createNode transform -s -n "top"; setAttr ".v" no; setAttr ".t" -type "double3" 0 100.1 0 ; setAttr ".r" -type "double3" -89.999999999999986 0 0 ; createNode camera -s -n "topShape" -p "top"; setAttr -k off ".v" no; setAttr ".rnd" no; setAttr ".coi" 100.1; setAttr ".ow" 30; setAttr ".imn" -type "string" "top"; setAttr ".den" -type "string" "top_depth"; setAttr ".man" -type "string" "top_mask"; setAttr ".hc" -type "string" "viewSet -t %camera"; setAttr ".o" yes; createNode transform -s -n "front"; setAttr ".v" no; setAttr ".t" -type "double3" 0 0 100.1 ; createNode camera -s -n "frontShape" -p "front"; setAttr -k off ".v" no; setAttr ".rnd" no; setAttr ".coi" 100.1; setAttr ".ow" 30; setAttr ".imn" -type "string" "front"; setAttr ".den" -type "string" "front_depth"; setAttr ".man" -type "string" "front_mask"; setAttr ".hc" -type "string" "viewSet -f %camera"; setAttr ".o" yes; createNode transform -s -n "side"; setAttr ".v" no; setAttr ".t" -type "double3" 100.1 0 0 ; setAttr ".r" -type "double3" 0 89.999999999999986 0 ; createNode camera -s -n "sideShape" -p "side"; setAttr -k off ".v" no; setAttr ".rnd" no; setAttr ".coi" 100.1; setAttr ".ow" 30; setAttr ".imn" -type "string" "side"; setAttr ".den" -type "string" "side_depth"; setAttr ".man" -type "string" "side_mask"; setAttr ".hc" -type "string" "viewSet -s %camera"; setAttr ".o" yes; createNode transform -n "pCylinder1"; setAttr ".t" -type "double3" 0 0 -6 ; createNode mesh -n "pCylinderShape1" -p "pCylinder1"; setAttr -k off ".v"; setAttr -s 4 ".iog"; setAttr ".vir" yes; setAttr ".vif" yes; setAttr ".uvst[0].uvsn" -type "string" "map1"; setAttr ".cuvs" -type "string" "map1"; setAttr ".dcc" -type "string" "Ambient+Diffuse"; setAttr ".covm[0]" 0 1 1; setAttr ".cdvm[0]" 0 1 1; setAttr ".bnr" 0; createNode transform -n "pCylinder2"; setAttr ".t" -type "double3" 0 0 -2 ; createNode transform -n "pCylinder3"; setAttr ".t" -type "double3" 0 0 2 ; createNode transform -n "pCylinder4"; setAttr ".t" -type "double3" 0 0 6 ; parent -s -nc -r -add "|pCylinder1|pCylinderShape1" "pCylinder2" ; parent -s -nc -r -add "|pCylinder1|pCylinderShape1" "pCylinder3" ; parent -s -nc -r -add "|pCylinder1|pCylinderShape1" "pCylinder4" ; createNode lightLinker -s -n "lightLinker1"; setAttr -s 2 ".lnk"; setAttr -s 2 ".slnk"; createNode displayLayerManager -n "layerManager"; createNode displayLayer -n "defaultLayer"; createNode renderLayerManager -n "renderLayerManager"; createNode renderLayer -n "defaultRenderLayer"; setAttr ".g" yes; createNode polyCylinder -n "polyCylinder1"; setAttr ".sc" 1; setAttr ".cuv" 3; createNode script -n "uiConfigurationScriptNode"; setAttr ".b" -type "string" ( "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `modelPanel -unParent -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels `;\n\t\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n" + " -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n -rendererName \"base_OpenGL_Renderer\" \n" + " -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n" + " -deformers 1\n -dynamics 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n" + " -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n -rendererName \"base_OpenGL_Renderer\" \n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n" + " -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n -handles 1\n -pivots 1\n" + " -textures 1\n -strokes 1\n -motionTrails 1\n -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `modelPanel -unParent -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels `;\n\t\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n" + " -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n -rendererName \"base_OpenGL_Renderer\" \n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n" + " -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n" + " -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n" + " -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n -rendererName \"base_OpenGL_Renderer\" \n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n" + " -sortTransparent 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" == $panelName) {\n" + "\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `modelPanel -unParent -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels `;\n\t\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n" + " -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n -rendererName \"base_OpenGL_Renderer\" \n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -nurbsCurves 1\n" + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n" + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n" + " -rendererName \"base_OpenGL_Renderer\" \n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -fluids 1\n" + " -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `modelPanel -unParent -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels `;\n\t\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n" + " -wireframeOnShaded 0\n -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n -rendererName \"base_OpenGL_Renderer\" \n -colorResolution 256 256 \n -bumpResolution 512 512 \n" + " -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -fluids 1\n" + " -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"wireframe\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n" + " -bufferMode \"double\" \n -twoSidedLighting 1\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 8192\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -maxConstantTransparency 1\n -rendererName \"base_OpenGL_Renderer\" \n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n" + " -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n" + " -shadows 0\n $editorName;\nmodelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `outlinerPanel -unParent -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels `;\n\t\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 1\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n" + " -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n" + " -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 1\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n" + " -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n" + "\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"graphEditor\" -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n" + " -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n" + " -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 1\n -displayInfinities 0\n -autoFit 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showResults \"off\" \n -showBufferCurves \"off\" \n -smoothness \"fine\" \n -resultSamples 1\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -stackedCurves 0\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -displayNormalized 0\n -preSelectionHighlight 0\n -constrainDrag 0\n -classicMode 1\n $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n" + " outlinerEditor -e \n -showShapes 1\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n" + " -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 1\n -displayInfinities 0\n -autoFit 0\n -snapTime \"integer\" \n" + " -snapValue \"none\" \n -showResults \"off\" \n -showBufferCurves \"off\" \n -smoothness \"fine\" \n -resultSamples 1\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -stackedCurves 0\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -displayNormalized 0\n -preSelectionHighlight 0\n -constrainDrag 0\n -classicMode 1\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"dopeSheetPanel\" -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n" + " -showShapes 1\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n" + " -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -autoFit 0\n -snapTime \"integer\" \n" + " -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showContainerContents 0\n -ignoreDagHierarchy 0\n" + " -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n" + " -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -autoFit 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n" + "\t\t\t$panelName = `scriptedPanel -unParent -type \"clipEditorPanel\" -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -autoFit 0\n -snapTime \"none\" \n -snapValue \"none\" \n -manageSequencer 0 \n $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -autoFit 0\n -snapTime \"none\" \n" + " -snapValue \"none\" \n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"hyperGraphPanel\" -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n" + " -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n -showExpressions 0\n" + " -showConstraints 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"hyperShadePanel\" -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n" + "\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"visorPanel\" -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Texture Editor\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"polyTexturePlacementPanel\" -l (localizedPanelLabel(\"UV Texture Editor\")) -mbv $menusOkayInPanels `;\n" + "\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Texture Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"renderWindowPanel\" -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"blendShapePanel\" (localizedPanelLabel(\"Blend Shape\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\tblendShapePanel -unParent -l (localizedPanelLabel(\"Blend Shape\")) -mbv $menusOkayInPanels ;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n" + "\t\tblendShapePanel -edit -l (localizedPanelLabel(\"Blend Shape\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"dynRelEdPanel\" -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"relationshipPanel\" -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels `;\n" + "\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"referenceEditorPanel\" -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"componentEditorPanel\" (localizedPanelLabel(\"Component Editor\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"componentEditorPanel\" -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels `;\n" + "\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"dynPaintScriptedPanelType\" -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"scriptEditorPanel\" -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels `;\n" + "\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"multiListerPanel\" (localizedPanelLabel(\"Multilister\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"multiListerPanel\" -l (localizedPanelLabel(\"Multilister\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Multilister\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"devicePanel\" (localizedPanelLabel(\"Devices\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\tdevicePanel -unParent -l (localizedPanelLabel(\"Devices\")) -mbv $menusOkayInPanels ;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n" + "\t\tdevicePanel -edit -l (localizedPanelLabel(\"Devices\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"webBrowserPanel\" (localizedPanelLabel(\"Web Browser\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"webBrowserPanel\" -l (localizedPanelLabel(\"Web Browser\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Web Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"createNodePanel\" -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels `;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n" + "\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" == $panelName) {\n\t\tif ($useSceneConfig) {\n\t\t\t$panelName = `scriptedPanel -unParent -type \"sequenceEditorPanel\" -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -autoFit 0\n -snapTime \"none\" \n -snapValue \"none\" \n -manageSequencer 1 \n $editorName;\n\t\t}\n\t} else {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n" + "\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -autoFit 0\n -snapTime \"none\" \n -snapValue \"none\" \n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-defaultImage \"\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap true\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"wireframe\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 1\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 8192\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -maxConstantTransparency 1\\n -rendererName \\\"base_OpenGL_Renderer\\\" \\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -shadows 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"wireframe\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 1\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 8192\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -maxConstantTransparency 1\\n -rendererName \\\"base_OpenGL_Renderer\\\" \\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -shadows 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n setFocus `paneLayout -q -p1 $gMainPane`;\n sceneUIReplacement -deleteRemaining;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); setAttr ".st" 3; createNode script -n "sceneConfigurationScriptNode"; setAttr ".b" -type "string" "playbackOptions -min 1 -max 24 -ast 1 -aet 48 "; setAttr ".st" 6; select -ne :time1; setAttr ".o" 1; setAttr ".unw" 1; select -ne :renderPartition; setAttr -s 2 ".st"; select -ne :initialShadingGroup; setAttr -s 4 ".dsm"; setAttr ".ro" yes; select -ne :initialParticleSE; setAttr ".ro" yes; select -ne :defaultShaderList1; setAttr -s 2 ".s"; select -ne :postProcessList1; setAttr -s 2 ".p"; select -ne :defaultRenderingList1; select -ne :renderGlobalsList1; select -ne :hardwareRenderGlobals; setAttr ".ctrs" 256; setAttr ".btrs" 512; select -ne :defaultHardwareRenderGlobals; setAttr ".fn" -type "string" "im"; setAttr ".res" -type "string" "ntsc_4d 646 485 1.333"; connectAttr "polyCylinder1.out" "|pCylinder1|pCylinderShape1.i"; relationship "link" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; relationship "link" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; relationship "shadowLink" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; relationship "shadowLink" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; connectAttr "layerManager.dli[0]" "defaultLayer.id"; connectAttr "renderLayerManager.rlmi[0]" "defaultRenderLayer.rlid"; connectAttr "|pCylinder1|pCylinderShape1.iog" ":initialShadingGroup.dsm" -na; connectAttr "|pCylinder2|pCylinderShape1.iog" ":initialShadingGroup.dsm" -na; connectAttr "|pCylinder3|pCylinderShape1.iog" ":initialShadingGroup.dsm" -na; connectAttr "|pCylinder4|pCylinderShape1.iog" ":initialShadingGroup.dsm" -na; connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; // End of multiInstance.ma ================================================ FILE: 02_Commands/instanceRotate/Exercise - C++/instanceRotate.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "instanceRotate", "instanceRotate.vcxproj", "{B29093BC-064C-4465-A61B-2DE73002010E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B29093BC-064C-4465-A61B-2DE73002010E}.Debug|x64.ActiveCfg = Debug|x64 {B29093BC-064C-4465-A61B-2DE73002010E}.Debug|x64.Build.0 = Debug|x64 {B29093BC-064C-4465-A61B-2DE73002010E}.Release|x64.ActiveCfg = Release|x64 {B29093BC-064C-4465-A61B-2DE73002010E}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 02_Commands/instanceRotate/Exercise - C++/instanceRotate.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {B29093BC-064C-4465-A61B-2DE73002010E} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\instanceRotate.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\instanceRotate.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 02_Commands/instanceRotate/Exercise - C++/instanceRotateCmd.cpp ================================================ // // Copyright (C) // // File: instanceRotateCmd.cpp // // MEL Command: instanceRotate // // Author: Maya Plug-in Wizard 2.0 // #include #include #include "instanceRotateCmd.h" #include #include #include #include #include #include //- Create a new MSyntax object to teach Maya about possible arguments //- in our command. This newSyntax() method is used during the command //- registration into our plug-in /*static*/ MSyntax instanceRotate::cmdSyntax() { MSyntax syntax; syntax.addFlag(ROTATEFLAG,ROTATELONGFLAG,MSyntax::kUnsigned); syntax.enableEdit(false); syntax.enableQuery(false); return syntax; } //- This method should perform a command by setting up internal class data //- and then calling the redoIt method if undo is supported by the command. //- The actual action performed by the command should be done in the redoIt //- method. This is a pure virtual method, and must be overridden in derived //- classes. MStatus instanceRotate::doIt( const MArgList& argList) { MStatus stat = MS::kSuccess; //- Since all the command actions will be done in the redoIt() method, this //- method will only parse the arguments. redoIt() will not use arguments //- at all. MArgDatabase argDB(syntax(),argList,&stat); if ( MS::kSuccess != stat ) { cerr << "Invalid flag used"; return stat.statusCode(); } unsigned int numFlags = argDB.numberOfFlagsUsed(); if(numFlags != 1) { MGlobal::displayError("Simple Plugs requires one flag argument and a DAG object must be selected"); return MS::kFailure; } else { if(argDB.isFlagSet(ROTATEFLAG, &stat)) { uint flag =0; //- The user enters 1, 2, or 3 to indicate x, y, or z rotation axis //- TODO: get flag argument from "ROTATEFLAG" //... if(flag == AXIS_X) axis = AXIS_X; else if(flag == AXIS_Y) axis = AXIS_Y; else if(flag == AXIS_Z) axis = AXIS_Z; else { MGlobal::displayError("Invalid axis rotation argument"); return MS::kFailure; } } } return redoIt(); } //- This method should do the actual work of the command based on the internal //- class data only. Internal class data should be set in the doIt method. MStatus instanceRotate::redoIt() { setResult( "instanceRotate command executed!\n" ); //- This is really where is the intelligence of the command. Here we will //- preform all the actions we wanted to implement for this command. //- Get the active selection in the Maya viewport. MSelectionList selList; MGlobal::getActiveSelectionList(selList); if(selList.isEmpty()) { MGlobal::displayError("A single DAG object must be selected"); return MS::kFailure; } MDagPath dagPath; selList.getDagPath(0,dagPath); //- Chances are the user selected the object from the panel view or //- outliner window so the object in the list will actually be a //- transform node... if so we call extendToShape to grab the actual //- shape node from the dagPath //- TODO: Test if this node is a transform node, and if so extend the //- TODO: dagPath to the real shape node. //... //... if(dagPath.isInstanced()) { shapeObj = dagPath; rotate(dagPath); } else { MGlobal::displayError("The selected item is not an instanced DAG object"); return MS::kFailure; } return MS::kSuccess; } //- This method should undo the work done by the redoIt method based on the //- internal class data only. MStatus instanceRotate::undoIt() { MGlobal::displayInfo( "instanceRotate command undone!\n" ); MFnDagNode fnDag(shapeObj); for(uint i = 0; i #include #include //- Forward declaration class MArgList; //- A convenience enum to keep track of which axis the user wanted to rotate around typedef enum AXIS {AXIS_X = 1, AXIS_Y = 2, AXIS_Z = 3}; //- This are the long and short command names. #define ROTATEFLAG "-r" #define ROTATELONGFLAG "-rotate" #define ROTATIONVALUE 0.785398163 // Command class declaration class instanceRotate : public MPxCommand { public: instanceRotate() {} virtual ~instanceRotate() {} //- This method should perform a command by setting up internal class data //- and then calling the redoIt method if undo is supported by the command. //- The actual action performed by the command should be done in the redoIt //- method. This is a pure virtual method, and must be overridden in derived //- classes. virtual MStatus doIt( const MArgList& ); //- This method should do the actual work of the command based on the internal //- class data only. Internal class data should be set in the doIt method. virtual MStatus redoIt(); //- This method should undo the work done by the redoIt method based on the //- internal class data only. virtual MStatus undoIt(); //- This method is used to specify whether or not the command is undoable. In //- the base class, it always returns false. If you are writing a command that //- might be eligible for undo, you should override this method. //- After Maya executes the command's doIt method, it will call isUndoable. If //- isUndoable returns true, Maya will retain the instance of the class and pass //- it to Maya's undo manager so that the undoIt and redoIt methods can be called //- when appropriate. If isUndoable returns false, the command instance will be //- immediately destroyed. virtual bool isUndoable() const { return true; } static void* creator() { new instanceRotate(); } virtual bool hasSyntax() { return true; } static MSyntax cmdSyntax(); //- Rotates each instance with 45 degrees along user-specified axis void rotate( MDagPath dp ); //- Store the user selection of the rotation axis (one axis for all of the instances) AXIS axis; //- Store the base shape for the instances here for undo MDagPath shapeObj; //- Store the number of instances for one shape uint numInstances; //- Store the original rotation values for undo here MDoubleArray rotations; }; ================================================ FILE: 02_Commands/instanceRotate/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include "instanceRotateCmd.h" #include MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2008", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand( "instanceRotate", instanceRotate::creator,instanceRotate::cmdSyntax ); if (!status) { status.perror("registerCommand"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand( "instanceRotate" ); if (!status) { status.perror("deregisterCommand"); return status; } return status; } ================================================ FILE: 02_Commands/instanceRotate/Exercise - py/instanceRotateCmd.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx # Command name kPluginCmdName = "instanceRotate" # Command switch short and long names ROTATEFLAG = "-r" ROTATELONGFLAG = "-rotate" ROTATIONVALUE = 0.785398163 AXIS_X = 1 AXIS_Y = 2 AXIS_Z = 3 # instanceRotate command class instanceRotate(OpenMayaMPx.MPxCommand): #- Store the base shape for the instances here for undo shapeObj = OpenMaya.MDagPath() #- Store the original rotation values for undo here rotations = OpenMaya.MDoubleArray() def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) #- Store the user selection of the rotation axis (one axis for all of the instances) self.axis = AXIS_X #- Store the number of instances for one shape self.numInstances = 0 #- This method is used to specify whether or not the command is undoable. In #- the base class, it always returns false. If you are writing a command that #- might be eligible for undo, you should override this method. #- After Maya executes the command's doIt method, it will call isUndoable. If #- isUndoable returns true, Maya will retain the instance of the class and pass #- it to Maya's undo manager so that the undoIt and redoIt methods can be called #- when appropriate. If isUndoable returns false, the command instance will be #- immediately destroyed. #def isUndoable(self): # return True #def hasSyntax(self): # return True #- This method should perform a command by setting up internal class data #- and then calling the redoIt method if undo is supported by the command. #- The actual action performed by the command should be done in the redoIt #- method. This is a pure virtual method, and must be overridden in derived #- classes. def doIt(self, args): #- Since all the command actions will be done in the redoIt() method, this #- method will only parse the arguments. redoIt() will not use arguments #- at all. argParser = OpenMaya.MArgParser (self.syntax(),args) numFlags = argParser.numberOfFlagsUsed() if(numFlags != 1): OpenMaya.MGlobal.displayError("Simple Plugs requires one flag argument and a DAG object must be selected") return None else: if(argParser.isFlagSet(ROTATEFLAG) | argParser.isFlagSet(ROTATELONGFLAG)): #- The user enters 1, 2, or 3 to indicate x, y, or z rotation axis flag =argParser.flagArgumentInt(ROTATEFLAG,0) if(flag == AXIS_X): self.axis = AXIS_X elif(flag == AXIS_Y): self.axis = AXIS_Y elif(flag == AXIS_Z): self.axis = AXIS_Z else: OpenMaya.MGlobal.displayError("Invalid axis rotation argument") return None return self.redoIt(args) #- This method should do the actual work of the command based on the internal #- class data only. Internal class data should be set in the doIt method. def redoIt(self, args): OpenMayaMPx.MPxCommand.setResult( "instanceRotate command executed!\n" ) #- This is really where is the intelligence of the command. Here we will #- preform all the actions we wanted to implement for this command. #- Get the active selection in the Maya viewport. selList = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selList) if(selList.isEmpty()): OpenMaya.MGlobal.displayError("A single DAG object must be selected") return None dagPath = OpenMaya.MDagPath() selList.getDagPath(0,dagPath) #- Chances are the user selected the object from the panel view or #- outliner window so the object in the list will actually be a #- transform node... if so we call extendToShape to grab the actual #- shape node from the dagPath #- TODO: Test if this node is a transform node, and if so extend the #- TODO: dagPath to the real shape node. #... #... if(dagPath.isInstanced()): self.shapeObj = dagPath self.rotate(dagPath) else: OpenMaya.MGlobal.displayError("The selected item is not an instanced DAG object") return None #- This method should undo the work done by the redoIt method based on the #- internal class data only. def undoIt(self, args): OpenMaya.MGlobal.displayInfo( "instanceRotate command undone!\n" ) fnDag = MFnDagNode(self.shapeObj) for i in range ( 0, self.numInstances ): currentParent = fnDag.parent(i) fnParent = OpenMaya.MFnDependencyNode(currentParent) rotPlug = fnParent.findPlug("rotate") if (self.axis == AXIS_X): rotxPlug = rotPlug.child(0) rotxPlug.setDouble(self.rotations[i]) elif (self.axis == AXIS_Z): rotzPlug = rotPlug.child(2) rotzPlug.setDouble(self.rotations[i]) else: # AXIS_Y: rotyPlug = rotPlug.child(1) rotyPlug.setDouble(self.rotations[i]) #- Empty the array in case the user chooses redoIt self.rotations.clear() #- Method used by redoIt to assign a 45 degree rotation along a random axis. def rotate( self, dp ): #- The passed-in dag object is a shape object, #- need to find all the parent transform objects. fnDag = OpenMaya.MFnDagNode(dp) #- The number of parents represents the current number of instances. self.numInstances = fnDag.parentCount() for i in range ( 0, self.numInstances ): currentParent = fnDag.parent(i) fnParent = OpenMaya.MFnDependencyNode(currentParent) #- Find the rotate plug, figure out which axis the user opted for #- and set the plug to a random direction. #- TODO: find the plug named 'rotate' rotPlug = #... #- Acquire a random number deciding which direction the 45 degree should be randVal = random.randint(0, 1000) if(randVal % 2 == 0): randVal = 1 else: randVal = -1 print "The randVal is %d " % randVal sys.stdout.write( '\n' ) if (self.axis == AXIS_X): #- TODO: Get the X plug of the 'rotate' plug rotxPlug = #... #- retrieve original rotation and store it in member variable "rotations" origRot = 0 #- TODO: Get the plug value #... self.rotations.append(origRot) #- set new rotation rot = origRot + randVal * ROTATIONVALUE #- TODO: Set the new plug value #... elif (self.axis == AXIS_Z): #- TODO: Get the Z plug of the 'rotate' plug rotzPlug = #... origRot = 0 #- TODO: Get the plug value #... self.rotations.append(origRot) rot = origRot + randVal * ROTATIONVALUE #- TODO: Set the new plug value #... else: # AXIS_Y: - by default, rotate around y axis - TODO: Get the Y plug of the 'rotate' plug rotyPlug = #... origRot = 0 #- TODO: Get the plug value #... self.rotations.append(origRot) rot = origRot + randVal * ROTATIONVALUE #- TODO: Set the new plug value #... # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( instanceRotate() ) #- Create a new MSyntax object to teach Maya about possible arguments #- in our command. This newSyntax() method is used during the command #- registration into our plug-in # Syntax creator def syntaxCreator(): syntax = OpenMaya.MSyntax() syntax.addFlag(ROTATEFLAG, ROTATELONGFLAG, OpenMaya.MSyntax.kUnsigned) syntax.enableEdit(0) syntax.enableQuery(0) return syntax # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator, syntaxCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) ================================================ FILE: 02_Commands/instanceRotate/Solution - C++/instanceRotate.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "instanceRotate", "instanceRotate.vcxproj", "{B29093BC-064C-4465-A61B-2DE73002010E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B29093BC-064C-4465-A61B-2DE73002010E}.Debug|x64.ActiveCfg = Debug|x64 {B29093BC-064C-4465-A61B-2DE73002010E}.Debug|x64.Build.0 = Debug|x64 {B29093BC-064C-4465-A61B-2DE73002010E}.Release|x64.ActiveCfg = Release|x64 {B29093BC-064C-4465-A61B-2DE73002010E}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 02_Commands/instanceRotate/Solution - C++/instanceRotate.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {B29093BC-064C-4465-A61B-2DE73002010E} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\instanceRotate.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\instanceRotate.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 02_Commands/instanceRotate/Solution - C++/instanceRotateCmd.cpp ================================================ // // Copyright (C) // // File: instanceRotateCmd.cpp // // MEL Command: instanceRotate // // Author: Maya Plug-in Wizard 2.0 // #include #include #include "instanceRotateCmd.h" #include #include #include #include #include #include //- Create a new MSyntax object to teach Maya about possible arguments //- in our command. This newSyntax() method is used during the command //- registration into our plug-in /*static*/ MSyntax instanceRotate::cmdSyntax() { MSyntax syntax; syntax.addFlag(ROTATEFLAG,ROTATELONGFLAG,MSyntax::kUnsigned); syntax.enableEdit(false); syntax.enableQuery(false); return syntax; } //- This method should perform a command by setting up internal class data //- and then calling the redoIt method if undo is supported by the command. //- The actual action performed by the command should be done in the redoIt //- method. This is a pure virtual method, and must be overridden in derived //- classes. MStatus instanceRotate::doIt( const MArgList& argList) { MStatus stat = MS::kSuccess; //- Since all the command actions will be done in the redoIt() method, this //- method will only parse the arguments. redoIt() will not use arguments //- at all. MArgDatabase argDB(syntax(),argList,&stat); if ( MS::kSuccess != stat ) { cerr << "Invalid flag used"; return stat.statusCode(); } unsigned int numFlags = argDB.numberOfFlagsUsed(); if(numFlags != 1) { MGlobal::displayError("Simple Plugs requires one flag argument and a DAG object must be selected"); return MS::kFailure; } else { if(argDB.isFlagSet(ROTATEFLAG, &stat)) { uint flag =0; //- The user enters 1, 2, or 3 to indicate x, y, or z rotation axis argDB.getFlagArgument(ROTATEFLAG,0,flag); if(flag == AXIS_X) axis = AXIS_X; else if(flag == AXIS_Y) axis = AXIS_Y; else if(flag == AXIS_Z) axis = AXIS_Z; else { MGlobal::displayError("Invalid axis rotation argument"); return MS::kFailure; } } } return redoIt(); } //- This method should do the actual work of the command based on the internal //- class data only. Internal class data should be set in the doIt method. MStatus instanceRotate::redoIt() { setResult( "instanceRotate command executed!\n" ); //- This is really where is the intelligence of the command. Here we will //- preform all the actions we wanted to implement for this command. //- Get the active selection in the Maya viewport. MSelectionList selList; MGlobal::getActiveSelectionList(selList); if(selList.isEmpty()) { MGlobal::displayError("A single DAG object must be selected"); return MS::kFailure; } MDagPath dagPath; selList.getDagPath(0,dagPath); //- Chances are the user selected the object from the panel view or //- outliner window so the object in the list will actually be a //- transform node... if so we call extendToShape to grab the actual //- shape node from the dagPath if(dagPath.hasFn(MFn::kTransform)) dagPath.extendToShape(); if(dagPath.isInstanced()) { shapeObj = dagPath; rotate(dagPath); } else { MGlobal::displayError("The selected item is not an instanced DAG object"); return MS::kFailure; } return MS::kSuccess; } //- This method should undo the work done by the redoIt method based on the //- internal class data only. MStatus instanceRotate::undoIt() { MGlobal::displayInfo( "instanceRotate command undone!\n" ); MFnDagNode fnDag(shapeObj); for(uint i = 0; i #include #include //- Forward declaration class MArgList; //- A convenience enum to keep track of which axis the user wanted to rotate around typedef enum AXIS {AXIS_X = 1, AXIS_Y = 2, AXIS_Z = 3}; //- This are the long and short command names. #define ROTATEFLAG "-r" #define ROTATELONGFLAG "-rotate" #define ROTATIONVALUE 0.785398163 // Command class declaration class instanceRotate : public MPxCommand { public: instanceRotate() {} virtual ~instanceRotate() {} //- This method should perform a command by setting up internal class data //- and then calling the redoIt method if undo is supported by the command. //- The actual action performed by the command should be done in the redoIt //- method. This is a pure virtual method, and must be overridden in derived //- classes. virtual MStatus doIt( const MArgList& ); //- This method should do the actual work of the command based on the internal //- class data only. Internal class data should be set in the doIt method. virtual MStatus redoIt(); //- This method should undo the work done by the redoIt method based on the //- internal class data only. virtual MStatus undoIt(); //- This method is used to specify whether or not the command is undoable. In //- the base class, it always returns false. If you are writing a command that //- might be eligible for undo, you should override this method. //- After Maya executes the command's doIt method, it will call isUndoable. If //- isUndoable returns true, Maya will retain the instance of the class and pass //- it to Maya's undo manager so that the undoIt and redoIt methods can be called //- when appropriate. If isUndoable returns false, the command instance will be //- immediately destroyed. virtual bool isUndoable() const { return true; } static void* creator() { return new instanceRotate(); } virtual bool hasSyntax() { return true; } static MSyntax cmdSyntax(); //- Rotates each instance with 45 degrees along user-specified axis void rotate( MDagPath dp ); //- Store the user selection of the rotation axis (one axis for all of the instances) AXIS axis; //- Store the base shape for the instances here for undo MDagPath shapeObj; //- Store the number of instances for one shape uint numInstances; //- Store the original rotation values for undo here MDoubleArray rotations; }; ================================================ FILE: 02_Commands/instanceRotate/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include "instanceRotateCmd.h" #include MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2008", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand( "instanceRotate", instanceRotate::creator,instanceRotate::cmdSyntax ); if (!status) { status.perror("registerCommand"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand( "instanceRotate" ); if (!status) { status.perror("deregisterCommand"); return status; } return status; } ================================================ FILE: 02_Commands/instanceRotate/Solution - py/instanceRotateCmd.py ================================================ # # Copyright (C) # # File: instanceRotateCmd.py # # MEL Command: instanceRotate # # Author: Maya Plug-in Wizard 2.0 # import sys, random import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx # Command name kPluginCmdName = "instanceRotate" # Command switch short and long names ROTATEFLAG = "-r" ROTATELONGFLAG = "-rotate" ROTATIONVALUE = 0.785398163 AXIS_X = 1 AXIS_Y = 2 AXIS_Z = 3 # instanceRotate command class instanceRotate(OpenMayaMPx.MPxCommand): #- Store the base shape for the instances here for undo shapeObj = OpenMaya.MDagPath() #- Store the original rotation values for undo here rotations = OpenMaya.MDoubleArray() def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) #- Store the user selection of the rotation axis (one axis for all of the instances) self.axis = AXIS_X #- Store the number of instances for one shape self.numInstances = 0 #- This method is used to specify whether or not the command is undoable. In #- the base class, it always returns false. If you are writing a command that #- might be eligible for undo, you should override this method. #- After Maya executes the command's doIt method, it will call isUndoable. If #- isUndoable returns true, Maya will retain the instance of the class and pass #- it to Maya's undo manager so that the undoIt and redoIt methods can be called #- when appropriate. If isUndoable returns false, the command instance will be #- immediately destroyed. #def isUndoable(self): # return True #def hasSyntax(self): # return True #- This method should perform a command by setting up internal class data #- and then calling the redoIt method if undo is supported by the command. #- The actual action performed by the command should be done in the redoIt #- method. This is a pure virtual method, and must be overridden in derived #- classes. def doIt(self, args): #- Since all the command actions will be done in the redoIt() method, this #- method will only parse the arguments. redoIt() will not use arguments #- at all. argParser = OpenMaya.MArgParser (self.syntax(),args) numFlags = argParser.numberOfFlagsUsed() if(numFlags != 1): OpenMaya.MGlobal.displayError("Simple Plugs requires one flag argument and a DAG object must be selected") return None else: if(argParser.isFlagSet(ROTATEFLAG) | argParser.isFlagSet(ROTATELONGFLAG)): #- The user enters 1, 2, or 3 to indicate x, y, or z rotation axis flag =argParser.flagArgumentInt(ROTATEFLAG,0) if(flag == AXIS_X): self.axis = AXIS_X elif(flag == AXIS_Y): self.axis = AXIS_Y elif(flag == AXIS_Z): self.axis = AXIS_Z else: OpenMaya.MGlobal.displayError("Invalid axis rotation argument") return None return self.redoIt(args) #- This method should do the actual work of the command based on the internal #- class data only. Internal class data should be set in the doIt method. def redoIt(self, args): OpenMayaMPx.MPxCommand.setResult( "instanceRotate command executed!\n" ) #- This is really where is the intelligence of the command. Here we will #- preform all the actions we wanted to implement for this command. #- Get the active selection in the Maya viewport. selList = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selList) if(selList.isEmpty()): OpenMaya.MGlobal.displayError("A single DAG object must be selected") return None dagPath = OpenMaya.MDagPath() selList.getDagPath(0,dagPath) #- Chances are the user selected the object from the panel view or #- outliner window so the object in the list will actually be a #- transform node... if so we call extendToShape to grab the actual #- shape node from the dagPath if(dagPath.hasFn(OpenMaya.MSpace.kTransform)): dagPath.extendToShape() if(dagPath.isInstanced()): self.shapeObj = dagPath self.rotate(dagPath) else: OpenMaya.MGlobal.displayError("The selected item is not an instanced DAG object") return None #- This method should undo the work done by the redoIt method based on the #- internal class data only. def undoIt(self, args): OpenMaya.MGlobal.displayInfo( "instanceRotate command undone!\n" ) fnDag = MFnDagNode(self.shapeObj) for i in range ( 0, self.numInstances ): currentParent = fnDag.parent(i) fnParent = OpenMaya.MFnDependencyNode(currentParent) rotPlug = fnParent.findPlug("rotate") if (self.axis == AXIS_X): rotxPlug = rotPlug.child(0) rotxPlug.setDouble(self.rotations[i]) elif (self.axis == AXIS_Z): rotzPlug = rotPlug.child(2) rotzPlug.setDouble(self.rotations[i]) else: # AXIS_Y: rotyPlug = rotPlug.child(1) rotyPlug.setDouble(self.rotations[i]) #- Empty the array in case the user chooses redoIt self.rotations.clear() #- Method used by redoIt to assign a 45 degree rotation along a random axis. def rotate( self, dp ): #- The passed-in dag object is a shape object, #- need to find all the parent transform objects. fnDag = OpenMaya.MFnDagNode(dp) #- The number of parents represents the current number of instances. self.numInstances = fnDag.parentCount() for i in range ( 0, self.numInstances ): currentParent = fnDag.parent(i) fnParent = OpenMaya.MFnDependencyNode(currentParent) #- Find the rotate plug, figure out which axis the user opted for #- and set the plug to a random direction. rotPlug = fnParent.findPlug("rotate") #- Acquire a random number deciding which direction the 45 degree should be randVal = random.randint(0, 1000) if(randVal % 2 == 0): randVal = 1 else: randVal = -1 print "The randVal is %d " % randVal sys.stdout.write( '\n' ) if (self.axis == AXIS_X): rotxPlug = rotPlug.child(0) #- retrieve original rotation and store it in member variable "rotations" origRot = rotxPlug.asDouble() self.rotations.append(origRot) #- set new rotation rot = origRot + randVal * ROTATIONVALUE rotxPlug.setDouble(rot) elif (self.axis == AXIS_Z): rotzPlug = rotPlug.child(2) origRot = rotzPlug.asDouble() self.rotations.append(origRot) rot = origRot + randVal * ROTATIONVALUE rotzPlug.setDouble(rot) else: # AXIS_Y: - by default, rotate around y axis rotyPlug = rotPlug.child(1) origRot = rotyPlug.asDouble() self.rotations.append(origRot) rot = origRot + randVal * ROTATIONVALUE rotyPlug.setDouble(rot) # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( instanceRotate() ) #- Create a new MSyntax object to teach Maya about possible arguments #- in our command. This newSyntax() method is used during the command #- registration into our plug-in # Syntax creator def syntaxCreator(): syntax = OpenMaya.MSyntax() syntax.addFlag(ROTATEFLAG, ROTATELONGFLAG, OpenMaya.MSyntax.kUnsigned) syntax.enableEdit(0) syntax.enableQuery(0) return syntax # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator, syntaxCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) ================================================ FILE: 02_Commands/nodeInfo/Exercise - C++/nodeInfoCmd.cpp ================================================ // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nodeInfoCmd.h" // Command class implementation nodeInfo::nodeInfo() : quiet (false) {} nodeInfo::~nodeInfo() {} //- Create a new MSyntax object to teach Maya about possible arguments //- in our command. This newSyntax() method is used during the command //- registration into our plug-in /*stattic*/ MSyntax nodeInfo::newSyntax() { MSyntax syntax; //- TODO: add flags onto the new created MSyntax object //.... return syntax; } //- This is a method which will be used by our command doIt() method to //- check arguments passed into our command call. MStatus nodeInfo::parseArgs( const MArgList& args ) { MStatus stat; MArgDatabase argData(syntax(), args); //- TODO: use MArgDataBase::isFlagSet to parse if the flag has been set by user //- and assign the corresponding boolean value to variable "quiet" based on the flag //... return stat; } //- This method performs the action of the command. It iterates over all //- selected items and prints out connected plug and dependency node type //- information. //- TODO: Define the method called by Maya to execute your command (the //- function argument will be named args for this exercise). //... { MStatus stat; // Status code MObject dependNode; // Selected dependency node stat = parseArgs ( args ); if ( !stat ) return stat; MSelectionList slist; //- TODO: Retrieve all objects currently selected into the Maya editor and put it onto "slist" //... //- Create an iterator on the selection list (using the iterator pattern). MItSelectionList iter( slist, MFn::kInvalid,&stat ); //- Iterate over all selected dependency nodes for ( ; !iter.isDone(); iter.next() ) { //- TODO: From the iterator,get corresponding dependency node //- by using MItSelectionList::getDependNode() //... //- TODO: Create a function set for the dependency node (name it fnDependNode) //... //- Check the type of the dependency node MString nodeName = fnDependNode.name(); cout << "////////////////////////////////////////////" << endl; cout << nodeName << " is of type " << dependNode.apiTypeStr() << endl; MPlugArray connectedPlugs; //- TODO: Get all connected plugs to this node by using MFnDependencyNode::getConnections() //- add assign them to "connectedPlugs" //... int numberOfPlugs = connectedPlugs.length(); if ( !quiet ) { cout << "Number of connections found: " << numberOfPlugs << endl; } //- Print out the dependency node name and attributes //- for each plug for ( int i=0; i //- This are the long and shor command names. #define kQuietFlag "-q" #define kQuietFlagLong "-quiet" // Command class declaration class nodeInfo : public MPxCommand { public: nodeInfo(); virtual ~nodeInfo(); //- TODO: Declare the method called by Maya to execute your command. //... //- Create a new MSyntax object to teach Maya about possible arguments //- in our command. This newSyntax() method is used during the command //- registration into our plug-in static MSyntax newSyntax(); static void* creator() { return new nodeInfo (); } private: MStatus parseArgs( const MArgList& args ); bool quiet; }; ================================================ FILE: 02_Commands/nodeInfo/Exercise - C++/nodeInfoCmd.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nodeInfoCmd", "nodeInfoCmd.vcxproj", "{B86ED337-5087-4A1B-B9F4-3B634AE09BC4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Debug|x64.ActiveCfg = Debug|x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Debug|x64.Build.0 = Debug|x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Release|x64.ActiveCfg = Release|x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 02_Commands/nodeInfo/Exercise - C++/nodeInfoCmd.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\nodeInfoCmd.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\nodeInfoCmd.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 02_Commands/nodeInfo/Exercise - C++/pluginMain.cpp ================================================ // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include "nodeInfoCmd.h" #include MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, PLUGIN_COMPANY, "2009", "Any"); // Add plug-in feature registration here //- TODO: Register your command into Maya, and make sure you define a syntax //... if (!status) { status.perror("registerCommand"); return status; } return status; } MStatus uninitializePlugin( MObject obj) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here //- TODO: unregister your command from Maya before you unload. //... if (!status) { status.perror("deregisterCommand"); return status; } return status; } ================================================ FILE: 02_Commands/nodeInfo/Exercise - py/nodeInfoCmd.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx # Command name kPluginCmdName = "nodeInfoCmd" # Command switch short and long names kQuietFlag = "-q" kQuietFlagLong = "-quiet" # nodeInfoCmd command class nodeInfoCmd(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) self.quiet = 0 #- This is a method which will be used by our command doIt() method to #- check arguments passed into our command call. def parseArgs ( self, args ): argData = OpenMaya.MArgDatabase( self.syntax(), args) if (argData.isFlagSet(kQuietFlag)): self.quiet = 1 #- This method performs the action of the command. It iterates over all #- selected items and prints out connected plug and dependency node type #- information. #- TODO: Define the method called by Maya to execute your command (the #- function argument will be named args for this exercise). def #... self.parseArgs ( args ) #- TODO: Select all objects currently selected into the Maya editor. slist = OpenMaya.MSelectionList() #... #- Create an iterator on the selection list (using the iterator pattern). iter = OpenMaya.MItSelectionList(slist) #- Iterate over all selected dependency nodes dependNode = OpenMaya.MObject() fnDependNode = OpenMaya.MFnDependencyNode() while (iter.isDone() == 0): #- TODO: Get the selected dependency node #... #- TODO: Create a function set for the dependency node #... if not self.quiet: #- Check the type of the dependency node nodeName = fnDependNode.name() print "######################" sys.stdout.write( '\n' ) print nodeName print " is of type %s" % dependNode.apiTypeStr() sys.stdout.write( '\n' ) #- TODO: Get all connected plugs to this node try: connectedPlugs = OpenMaya.MPlugArray() try: #... except: pass numberOfPlugs = connectedPlugs.length() if not self.quiet: print "Number of connections found: %d " % numberOfPlugs sys.stdout.write( '\n' ) #- Print out the dependency node name and attributes #- for each plug for i in range( 0, numberOfPlugs ): plug = connectedPlugs[i] pinfo = plug.info() if not self.quiet: print " Connected Plug Info: %s" % pinfo sys.stdout.write( '\n' ) #- Now get the plugs that this plug is the #- destination of and print the node type. array = OpenMaya.MPlugArray() #- TODO: Get the list of plugs, this plug is connected to. #... for j in range( 0, array.length() ): mnode = array[j].node() if not self.quiet: fnConnectedNode = OpenMaya.MFnDependencyNode(mnode) print " This plug is a destination of node: %s" % fnConnectedNode.name() sys.stdout.write( '\n' ) except: sys.stderr.write( "Failed to get connections: %s" % kPluginCmdName) #raise iter.next() # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( nodeInfoCmd() ) #- Create a new MSyntax object to teach Maya about possible arguments #- in our command. This newSyntax() method is used during the command #- registration into our plug-in # Syntax creator def syntaxCreator(): syntax = OpenMaya.MSyntax() syntax.addFlag(kQuietFlag, kQuietFlagLong) return syntax # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Register your command into Maya, and make sure you define a syntax #... except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: unregister your command from Maya before you unload. #... except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) ================================================ FILE: 02_Commands/nodeInfo/Solution - C++/nodeInfoCmd.cpp ================================================ // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nodeInfoCmd.h" // Command class implementation nodeInfo::nodeInfo() : quiet (false) {} nodeInfo::~nodeInfo() {} //- Create a new MSyntax object to teach Maya about possible arguments //- in our command. This newSyntax() method is used during the command //- registration into our plug-in /*static*/ MSyntax nodeInfo::newSyntax() { MSyntax syntax; syntax.addFlag(kQuietFlag, kQuietFlagLong); return syntax; } //- This is a method which will be used by our command doIt() method to //- check arguments passed into our command call. MStatus nodeInfo::parseArgs( const MArgList& args ) { MStatus stat; MArgDatabase argData(syntax(), args); if (argData.isFlagSet(kQuietFlag)) quiet = true; return stat; } //- This method performs the action of the command. It iterates over all //- selected items and prints out connected plug and dependency node type //- information. MStatus nodeInfo::doIt( const MArgList& args ) { MStatus stat; // Status code MObject dependNode; // Selected dependency node stat = parseArgs ( args ); if ( !stat ) return stat; //- Retrieve all objects currently selected into the Maya editor. MSelectionList slist; MGlobal::getActiveSelectionList( slist ); //- Create an iterator on the selection list (using the iterator pattern). MItSelectionList iter( slist, MFn::kInvalid,&stat ); //- Iterate over all selected dependency nodes for ( ; !iter.isDone(); iter.next() ) { //- Get the selected dependency node iter.getDependNode( dependNode ); //- Create a function set for the dependency node MFnDependencyNode fnDependNode( dependNode ); //- Check the type of the dependency node MString nodeName = fnDependNode.name(); cout << "////////////////////////////////////////////" << endl; cout << nodeName << " is of type " << dependNode.apiTypeStr() << endl; //- Get all connected plugs to this node MPlugArray connectedPlugs; fnDependNode.getConnections( connectedPlugs ); int numberOfPlugs = connectedPlugs.length(); if ( !quiet ) { cout << "Number of connections found: " << numberOfPlugs << endl; } //- Print out the dependency node name and attributes //- for each plug for ( int i=0; i //- This are the long and short command names. #define kQuietFlag "-q" #define kQuietFlagLong "-quiet" // Command class declaration class nodeInfo : public MPxCommand { public: nodeInfo(); virtual ~nodeInfo(); //- This method should perform a command by setting up internal class data //- and then calling the redoIt method if undo is supported by the command. //- The actual action performed by the command should be done in the redoIt //- method. This is a pure virtual method, and must be overridden in derived //- classes. virtual MStatus doIt( const MArgList& args ); //- Create a new MSyntax object to teach Maya about possible arguments //- in our command. This newSyntax() method is used during the command //- registration into our plug-in static MSyntax newSyntax(); static void* creator() { return new nodeInfo (); } private: MStatus parseArgs( const MArgList& args ); bool quiet; }; ================================================ FILE: 02_Commands/nodeInfo/Solution - C++/nodeInfoCmd.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nodeInfoCmd", "nodeInfoCmd.vcxproj", "{B86ED337-5087-4A1B-B9F4-3B634AE09BC4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Debug|x64.ActiveCfg = Debug|x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Debug|x64.Build.0 = Debug|x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Release|x64.ActiveCfg = Release|x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 02_Commands/nodeInfo/Solution - C++/nodeInfoCmd.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {B86ED337-5087-4A1B-B9F4-3B634AE09BC4} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\nodeInfoCmd.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\nodeInfoCmd.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 02_Commands/nodeInfo/Solution - C++/pluginMain.cpp ================================================ // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include "nodeInfoCmd.h" #include MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, PLUGIN_COMPANY, "2009", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand( "nodeInfo", nodeInfo::creator, nodeInfo::newSyntax); if (!status) { status.perror("registerCommand"); return status; } return status; } MStatus uninitializePlugin( MObject obj) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // plugin.deregisterCommand ( "nodeInfo" ) ; if (!status) { status.perror("deregisterCommand"); return status; } return status; } ================================================ FILE: 02_Commands/nodeInfo/Solution - py/nodeInfoCmd.py ================================================ # # File: # # Dependency Graph Node: # # Author: Maya Plug-in Wizard 2.0 # import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx # Command name kPluginCmdName = "nodeInfoCmd" # Command switch short and long names kQuietFlag = "-q" kQuietFlagLong = "-quiet" # nodeInfoCmd command class nodeInfoCmd(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) self.quiet = 0 #- This is a method which will be used by our command doIt() method to #- check arguments passed into our command call. def parseArgs ( self, args ): argData = OpenMaya.MArgDatabase( self.syntax(), args) if argData.isFlagSet(kQuietFlag): self.quiet = 1 #- This method performs the action of the command. It iterates over all #- selected items and prints out connected plug and dependency node type #- information. def doIt(self, args): self.parseArgs ( args ) #- Select all objects currently selected into the Maya editor. slist = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList( slist ) #- Create an iterator on the selection list (using the iterator pattern). iter = OpenMaya.MItSelectionList(slist) #- Iterate over all selected dependency nodes dependNode = OpenMaya.MObject() fnDependNode = OpenMaya.MFnDependencyNode() while (iter.isDone() == 0): #- Get the selected dependency node iter.getDependNode( dependNode ) #- Create a function set for the dependency node fnDependNode.setObject( dependNode ) if not self.quiet: #- Check the type of the dependency node nodeName = fnDependNode.name() print "######################" sys.stdout.write( '\n' ) print nodeName print " is of type %s" % dependNode.apiTypeStr() sys.stdout.write( '\n' ) #- Get all connected plugs to this node try: connectedPlugs = OpenMaya.MPlugArray() try: fnDependNode.getConnections(connectedPlugs) except: pass numberOfPlugs = connectedPlugs.length() if not self.quiet: print "Number of connections found: %d " % numberOfPlugs sys.stdout.write( '\n' ) #- Print out the dependency node name and attributes #- for each plug for i in range( 0, numberOfPlugs ): plug = connectedPlugs[i] pinfo = plug.info() if not self.quiet: print " Connected Plug Info: %s" % pinfo sys.stdout.write( '\n' ) #- Now get the plugs that this plug is the #- destination of and print the node type. array = OpenMaya.MPlugArray() plug.connectedTo( array, 1, 0 ) for j in range( 0, array.length() ): mnode = array[j].node() if not self.quiet: fnConnectedNode = OpenMaya.MFnDependencyNode(mnode) print " This plug is a destination of node: %s" % fnConnectedNode.name() sys.stdout.write( '\n' ) except: sys.stderr.write( "Failed to get connections: %s" % kPluginCmdName) #raise iter.next() # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( nodeInfoCmd() ) #- Create a new MSyntax object to teach Maya about possible arguments #- in our command. This newSyntax() method is used during the command #- registration into our plug-in # Syntax creator def syntaxCreator(): syntax = OpenMaya.MSyntax() syntax.addFlag(kQuietFlag, kQuietFlagLong) return syntax # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator, syntaxCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) ================================================ FILE: 03_Nodes/simpleNode/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "simpleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // //- TODO: Register your node here, so Maya can use it and recognize it //- TODO: while reading/saving a file which has instance of this node type. //... if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // //- TODO: Unregister your node here, so Maya stops using it. //... if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 03_Nodes/simpleNode/Exercise - C++/simpleNode.cpp ================================================ // // Copyright (C) // // File: simpleNode.cpp // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #include "simpleNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- In the solution project, 0x00001 is a temporary ID reserved for development. Never use that ID in a //- production environment. //- TODO: Define here your unique node ID //... //- Instantiate the static attributes of your node class. /*static*/ MObject simpleNode::input; /*static*/ MObject simpleNode::output; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus simpleNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; simpleNode::input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- TODO: Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute definition not saved into Maya file. //... //- TODO: Attribute will not be written to files when this type of node is stored //... //- Now add the attribute to your node definition using the addAttribute() //- method. //- Add the attributes we have created to the node addAttribute( simpleNode::input ); //- TODO: Add the output attribute to the node type definition //... //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- TODO: Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. //... //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus simpleNode::compute( const MPlug& plug, MDataBlock& data ) { //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == simpleNode::output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( simpleNode::input ); //- Read the input value from the handle. float result = inputData.asFloat(); //- Get a handle to the output attribute. Use "outputValue", which //- is similar to the "inputValue" call above except that no //- dependency graph computation will be done as a result of this call. //- TODO: Get a handle on the output attribute //... //- TODO: Set the new output value to the handle (multiply the value by 2 for //- example to see a change [result * 2]) //... //- Mark the destination plug as being clean. This will prevent the //- dependency graph from repeating this calculation until an input //- attribute of this node which affects this output attribute changes. //- TODO: Tell Maya the plug is now clean //... //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 03_Nodes/simpleNode/Exercise - C++/simpleNode.h ================================================ // // Copyright (C) // // File: simpleNode.h // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class simpleNode : public MPxNode { public: simpleNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~simpleNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new simpleNode(); } //- Declare the static initialize() method. static MStatus initialize(); public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // input attribute //- TODO: Declare here the output attribute //- TODO: ... //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. //- TODO: Declare here your unique node ID //... }; ================================================ FILE: 03_Nodes/simpleNode/Exercise - C++/simpleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleNode", "simpleNode.vcxproj", "{439648C5-792B-4918-AC04-5B034F382742}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.ActiveCfg = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.Build.0 = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.ActiveCfg = Release|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 03_Nodes/simpleNode/Exercise - C++/simpleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {439648C5-792B-4918-AC04-5B034F382742} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) ..\..\..\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib ================================================ FILE: 03_Nodes/simpleNode/Exercise - py/simpleNode.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys #- Assing a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- In the solution project, 0x00001 is a temporary ID reserved for development. Never use that ID in a #- production environment. kPluginNodeTypeName = "simpleNode" #- TODO: Define here your unique node ID simpleNodeId = #... # Node definition class simpleNode(OpenMayaMPx.MPxNode): # Node attributes input = OpenMaya.MObject() #- TODO: Declare here the output attribute #- TODO: ... def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self,plug,dataBlock): if ( plug == simpleNode.output ): #- Get a handle to the input attribute that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = dataBlock.inputValue( simpleNode.input ) #- Read the input value from the handle. result = inputData.asFloat() #- Get a handle to the output attribute. This is similar to the #- "inputValue" call above except that no dependency graph #- computation will be done as a result of this call. #- Get a handle on the aOutput attribute outputHandle = dataBlock.outputValue( simpleNode.output ) #- TODO: Set the new output value to the handle (multiply the value by 2 for #- example to see a change [result * 2]) #... #- Mark the destination plug as being clean. This will prevent the #- dependency graph from repeating this calculation until an input #- attribute of this node which affects this output attribute changes. #- TODO: Tell Maya the plug is now clean #... #- Tell Maya that we do not know how to handle this plug, but let give a chance #- to our parent class to evaluate it. return OpenMaya.kUnknownParameter # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( simpleNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- def nodeInitializer(): #- Initialize a float input attribute using the MFnNumericAttribute #- class. Make that attribute definition saved into Maya file (setStorable), #- and selectable in the channel box (setKeyable). #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() simpleNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(1) #- Attribute is keyable and will show up in the channel box nAttr.setKeyable(1) #- TODO: Initialize a float output attribute using the MFnNumericAttribute #- class. Make that attribute definition not saved into Maya file. #... #- TODO: Attribute will not be written to files when this type of node is stored #... #- Now add the attribute to your node definition using the addAttribute() #- method. #- Add the attributes we have created to the node simpleNode.addAttribute( simpleNode.input ) #- TODO: Add the output attribute to the node type definition #... #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimatelly in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- TODO: Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. #... # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Register your node here, so Maya can use it and recognize it #- TODO: while reading/saving a file which has instance of this node type. #... except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Unregister your node here, so Maya stops using it. #... except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 03_Nodes/simpleNode/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "simpleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // //- Register your node here, so Maya can use it and recognize it //- while reading/saving a file which has instance of this node type. status = plugin.registerNode( "simpleNode", simpleNode::id, simpleNode::creator, simpleNode::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // //- Unregister your node here, so Maya stops using it. status = plugin.deregisterNode( simpleNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 03_Nodes/simpleNode/Solution - C++/simpleNode.cpp ================================================ // // Copyright (C) // // File: simpleNode.cpp // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #include "simpleNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x00001 is a temporary ID for reserved for development. Never use that ID in a //- production environment. /*static*/ MTypeId simpleNode::id( 0x00001 ); //- Instantiate the static attributes of your node class. /*static*/ MObject simpleNode::input; /*static*/ MObject simpleNode::output; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus simpleNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; simpleNode::input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute definition not saved into Maya file. simpleNode::output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 ); //- Attribute will not be written to files when this type of node is stored nAttr.setStorable(false); //- Now add the attribute to your node definition using the addAttribute() //- method. //- Add the attributes we have created to the node addAttribute( simpleNode::input ); //- Add the aOutput attribute to the node type definition addAttribute( simpleNode::output ); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. attributeAffects( simpleNode::input, simpleNode::output ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus simpleNode::compute( const MPlug& plug, MDataBlock& data ) { //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == simpleNode::output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( simpleNode::input ); //- Read the input value from the handle. float result = inputData.asFloat(); //- Get a handle to the output attribute. This is similar to the //- "inputValue" call above except that no dependency graph //- computation will be done as a result of this call. //- Get a handle on the output attribute MDataHandle outputHandle = data.outputValue( simpleNode::output ); //- Set the new output value to the handle. outputHandle.set( result * 2 ); //- Mark the destination plug as being clean. This will prevent the //- dependency graph from repeating this calculation until an input //- attribute of this node which affects this output attribute changes. //- Tell Maya the plug is now clean data.setClean(plug); //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 03_Nodes/simpleNode/Solution - C++/simpleNode.h ================================================ // // Copyright (C) // // File: simpleNode.h // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class simpleNode : public MPxNode { public: simpleNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~simpleNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new simpleNode(); } //- Declare the static initialize() method. static MStatus initialize(); public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // input attribute static MObject output; // output attribute //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 03_Nodes/simpleNode/Solution - C++/simpleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleNode", "simpleNode.vcxproj", "{439648C5-792B-4918-AC04-5B034F382742}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.ActiveCfg = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.Build.0 = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.ActiveCfg = Release|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 03_Nodes/simpleNode/Solution - C++/simpleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {439648C5-792B-4918-AC04-5B034F382742} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) ..\..\..\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib ================================================ FILE: 03_Nodes/simpleNode/Solution - py/simpleNode.py ================================================ # # Copyright (C) # # File: simpleNode.cpp # # Dependency Graph Node: simpleNode # # Author: Maya Plug-in Wizard 2.0 # import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys #- Assing a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- 0x00001 is a temporary ID for reserved for development. Never use that ID in a #- production environment. kPluginNodeTypeName = "simpleNode" simpleNodeId = OpenMaya.MTypeId(0x00001) # Node definition class simpleNode(OpenMayaMPx.MPxNode): # Node attributes input = OpenMaya.MObject() output = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self,plug,dataBlock): if ( plug == simpleNode.output ): #- Get a handle to the input attribute that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = dataBlock.inputValue( simpleNode.input ) #- Read the input value from the handle. result = inputData.asFloat() #- Get a handle to the output attribute. This is similar to the #- "inputValue" call above except that no dependency graph #- computation will be done as a result of this call. #- Get a handle on the aOutput attribute outputHandle = dataBlock.outputValue( simpleNode.output ) #- Set the new output value to the handle. outputHandle.setFloat( result * 2 ) #- Mark the destination plug as being clean. This will prevent the #- dependency graph from repeating this calculation until an input #- attribute of this node which affects this output attribute changes. #- Tell Maya the plug is now clean dataBlock.setClean( plug ) #- Return success to Maya #- Tell Maya that we do not know how to handle this plug, but let give a chance #- to our parent class to evaluate it. return OpenMaya.kUnknownParameter # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( simpleNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- def nodeInitializer(): #- Initialize a float input attribute using the MFnNumericAttribute #- class. Make that attribute definition saved into Maya file (setStorable), #- and selectable in the channel box (setKeyable). #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() simpleNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(1) #- Attribute is keyable and will show up in the channel box nAttr.setKeyable(1) #- Initialize a float output attribute using the MFnNumericAttribute #- class. Make that attribute definition not saved into Maya file. simpleNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will not be written to files when this type of node is stored nAttr.setStorable(0) #- Now add the attribute to your node definition using the addAttribute() #- method. #- Add the attributes we have created to the node simpleNode.addAttribute( simpleNode.input ) #- Add the aOutput attribute to the node type definition simpleNode.addAttribute( simpleNode.output ) #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimatelly in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. simpleNode.attributeAffects( simpleNode.input, simpleNode.output ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, simpleNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( simpleNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 03_Nodes/sineNode/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "simpleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // //- TODO: Register your node here, so Maya can use it and recognize it //- TODO: while reading/saving a file which has instance of this node type. //... if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // //- TODO: Unregister your node here, so Maya stops using it. //... if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 03_Nodes/sineNode/Exercise - C++/simpleNode.cpp ================================================ // // Copyright (C) // // File: simpleNode.cpp // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #include "simpleNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- In the solution project, 0x00001 is a temporary ID for reserved for development. Never use that ID in a //- production environment. //- TODO: Define here your unique node ID //... //- Instantiate the static attributes of your node class. /*static*/ MObject simpleNode::input; /*static*/ MObject simpleNode::output; /*static*/ MObject simpleNode::descString; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus simpleNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- TODO: Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute definition not saved into Maya file. //... //- TODO: Attribute will not be written to files when this type of node is stored //... //- Initialize a string output attribute using the MFnTypedAttribute //- class. Make that attribute definition saved into Maya file. //- In order to specify the attribute default value, you will need to //- use the MFnStringData class, before creating the attribute itself. //- Use MFnStringData to implement default value first MFnStringData fnStringData; MString defaultString("description string for current node"); MObject defaultStringObj = fnStringData.create(defaultString); //- TODO: create a string attribute using the MFnTypedAttribute //- and use the above MObject as a default value for your string attribute //... //- Attribute will be written to files when this type of node is stored typedAttr.setStorable(true); //- Now add the attribute to your node definition using the addAttribute() //- method. //- Add the attributes we have created to the node addAttribute( input ); //- TODO: Add the output attribute to the node type definition //... addAttribute(descString); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- TODO: Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. //... //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus simpleNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( input, &returnStatus ); //- Read the input value from the handle. float result = inputData.asFloat(); //- Get a handle to the output attribute. Use "outputValue", which //- is similar to the "inputValue" call above except that no //- dependency graph computation will be done as a result of this call. //- ToDO: Get a handle on the aOutput attribute //... //- TODO: Set the new output value to the handle. //... //- Mark the destination plug as being clean. This will prevent the //- dependency graph from repeating this calculation until an input //- attribute of this node which affects this output attribute changes. //- TODO: Tell Maya the plug is now clean //... //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 03_Nodes/sineNode/Exercise - C++/simpleNode.h ================================================ // // Copyright (C) // // File: simpleNode.h // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class simpleNode : public MPxNode { public: simpleNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~simpleNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new simpleNode(); } //- Declare the static initialize() method. static MStatus initialize(); public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // input attribute //- TODO: Declare here the output attribute //- TODO: ... static MObject descString; // Description string attribute describing the function of this node //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. //- TODO: Declare here your unique node ID //... }; ================================================ FILE: 03_Nodes/sineNode/Exercise - C++/simpleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleNode", "simpleNode.vcxproj", "{439648C5-792B-4918-AC04-5B034F382742}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.ActiveCfg = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.Build.0 = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.ActiveCfg = Release|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 03_Nodes/sineNode/Exercise - C++/simpleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {439648C5-792B-4918-AC04-5B034F382742} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ .mll /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Debug\simpleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib ================================================ FILE: 03_Nodes/sineNode/Exercise - py/sineNode.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. #- TODO: Import all the necessary modules here #... kPluginNodeTypeName = "spSineNode" #- TODO: Allocate a type id for your custom node #... # Node definition class sineNode(OpenMayaMPx.MPxNode): #- TODO: Define your class variables #... def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- TODO: Add Implementation of compute #... if ( plug == sineNode.output ): #- TODO: Get handle of input attribute and data from the handle #... result = math.sin( inputFloat ) * 10.0 outputHandle = dataBlock.outputValue( sineNode.output ) outputHandle.setFloat( result ) dataBlock.setClean( plug ) return OpenMaya.kUnknownParameter # creator def nodeCreator(): #- TODO: Implement the creator and apply asMPxPtr() to it #... # initializer def nodeInitializer(): # input #- TODO: Create an input attribute with name "input" #... nAttr.setStorable(1) # output nAttr = OpenMaya.MFnNumericAttribute() sineNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) nAttr.setWritable(1) #- TODO: Add attributes and set up relationship #... # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Register this custom node #... except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Deregister this custom node #... except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 03_Nodes/sineNode/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "simpleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // //- Register your node here, so Maya can use it and recognize it //- while reading/saving a file which has instance of this node type. status = plugin.registerNode( "simpleNode", simpleNode::id, simpleNode::creator, simpleNode::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // //- Unregister your node here, so Maya stops using it. status = plugin.deregisterNode( simpleNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 03_Nodes/sineNode/Solution - C++/simpleNode.cpp ================================================ // // Copyright (C) // // File: simpleNode.cpp // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #include "simpleNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x00001 is a temporary ID for reserved for development. Never use that ID in a //- production environment. /*static*/ MTypeId simpleNode::id( 0x00001 ); //- Instantiate the static attributes of your node class. /*static*/ MObject simpleNode::input; /*static*/ MObject simpleNode::output; /*static*/ MObject simpleNode::descString; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus simpleNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute definition not saved into Maya file. output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 ); //- Attribute will not be written to files when this type of node is stored nAttr.setStorable(false); //- Initialize a string output attribute using the MFnTypedAttribute //- class. Make that attribute definition saved into Maya file. //- In order to specify the attribute default value, you will need to //- use the MFnStringData class, before creating the attribute itself. //- Create a string attribute using MFnTypedAttribute MFnTypedAttribute typedAttr; //- Use MFnStringData to implement default value of this attribute MFnStringData fnStringData; MString defaultString("description string for current node"); MObject defaultStringObj = fnStringData.create(defaultString); descString = typedAttr.create("descString", "dStr", MFnData::kString,defaultStringObj); //- Attribute will be written to files when this type of node is stored typedAttr.setStorable(true); //- Now add the attribute to your node definition using the addAttribute() //- method. //- Add the attributes we have created to the node addAttribute( input ); //- Add the aOutput attribute to the node type definition addAttribute( output ); addAttribute(descString); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. attributeAffects( input, output ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus simpleNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( input, &returnStatus ); //- Read the input value from the handle. float result = inputData.asFloat(); //- Get a handle to the output attribute. This is similar to the //- "inputValue" call above except that no dependency graph //- computation will be done as a result of this call. //- Get a handle on the aOutput attribute MDataHandle outputHandle = data.outputValue( simpleNode::output ); //- Set the new output value to the handle. outputHandle.set( result * 2 ); //- Mark the destination plug as being clean. This will prevent the //- dependency graph from repeating this calculation until an input //- attribute of this node which affects this output attribute changes. //- Tell Maya the plug is now clean data.setClean(plug); //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 03_Nodes/sineNode/Solution - C++/simpleNode.h ================================================ // // Copyright (C) // // File: simpleNode.h // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class simpleNode : public MPxNode { public: simpleNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~simpleNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new simpleNode(); } //- Declare the static initialize() method. static MStatus initialize(); public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // input attribute static MObject output; // output attribute static MObject descString; // Description string attribute describing the function of this node //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 03_Nodes/sineNode/Solution - C++/simpleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleNode", "simpleNode.vcxproj", "{439648C5-792B-4918-AC04-5B034F382742}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.ActiveCfg = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.Build.0 = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.ActiveCfg = Release|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 03_Nodes/sineNode/Solution - C++/simpleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {439648C5-792B-4918-AC04-5B034F382742} DynamicLibrary DynamicLibrary DynamicLibrary DynamicLibrary <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Debug\simpleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib ================================================ FILE: 03_Nodes/sineNode/Solution - py/sineNode.py ================================================ # # Copyright (C) # # File: sineNode.py # # Dependency Graph Node: sineNode # # Author: # import math, sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "spSineNode" sineNodeId = OpenMaya.MTypeId(0x87000) # Node definition class sineNode(OpenMayaMPx.MPxNode): # class variables input = OpenMaya.MObject() output = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) def compute(self,plug,dataBlock): if ( plug == sineNode.output ): dataHandle = dataBlock.inputValue( sineNode.input ) inputFloat = dataHandle.asFloat() result = math.sin( inputFloat ) * 10.0 outputHandle = dataBlock.outputValue( sineNode.output ) outputHandle.setFloat( result ) dataBlock.setClean( plug ) return OpenMaya.kUnknownParameter # creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( sineNode() ) # Initializer def nodeInitializer(): # input nAttr = OpenMaya.MFnNumericAttribute() sineNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) # output nAttr = OpenMaya.MFnNumericAttribute() sineNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) nAttr.setWritable(1) # add attributes sineNode.addAttribute( sineNode.input ) sineNode.addAttribute( sineNode.output ) sineNode.attributeAffects( sineNode.input, sineNode.output ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, sineNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( sineNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 03_Nodes/transCircleNode/Exercise - C++/AEtransCircleTemplate.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // // Creation Date: March 04, 2009 // // // Procedure Name: // AEtransCircleTemplate // // Description: // Creates the attribute editor controls for the transCircle node // // Input Value: // nodeName // // Output Value: // None // /////////////////////////////////////////////////////////////// // Example : /////////////////////////////////////////////////////////////// /* file -f -new; createNode transCircle; openAEWindow; */ global proc AEtransCircleTemplate( string $nodeName ) { } ================================================ FILE: 03_Nodes/transCircleNode/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "transCircleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); //- TODO: Add plug-in feature registration here //... return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); //- TODO: Add plug-in feature deregistration here //... return status; } ================================================ FILE: 03_Nodes/transCircleNode/Exercise - C++/transCircleNode.cpp ================================================ // // Copyright (C) // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include "transCircleNode.h" //- Assign a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x80013 is a temporary ID reserved for development. Never use that ID in a //- production environment. /*static*/MTypeId transCircle::id( 0x80013 ); //- Instantiate the static attributes of your node class. /*static*/MObject transCircle::input; /*static*/MObject transCircle::frames; /*static*/MObject transCircle::scale; /*static*/MObject transCircle::inputTranslateX; /*static*/MObject transCircle::inputTranslateY; /*static*/MObject transCircle::inputTranslateZ; /*static*/MObject transCircle::inputTranslate; //- TODO: Instantiate the outputTranslate compound attribute and its X, Y, Z //- TODO: components //... //... //... //... //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus transCircle::initialize() { //- Create a numeric attribute using MFnNumericAttribute MFnNumericAttribute nAttr; input = nAttr.create( "input", "in", MFnNumericData::kDouble, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Create individual input translate attributes inputTranslateX = nAttr.create( "inputTranslateX", "itX", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateY = nAttr.create( "inputTranslateY", "itY", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); //- Create compound input translate attributes by adding individual input translate attributes MFnCompoundAttribute comAttr; inputTranslate = comAttr.create("inputTranslate","it"); comAttr.addChild(inputTranslateX); comAttr.addChild(inputTranslateY); comAttr.addChild(inputTranslateZ); comAttr.setStorable(true); //- TODO: Create the outputTranslate compound attribute and its X, Y, Z //- TODO: components. Make the attribute saved into the Maya file, and not //- TODO: writable. Tips: properties needs to be set for each components, //- TODO: including the parent. //- Create individual output translate attributes //... //... //... //... //... //... //... //... //... //- Create compound output translate attributes by adding individual output translate attributes //... //... //... //... //... //... //- Create other attributes for our node scale = nAttr.create( "scale", "sc",MFnNumericData::kDouble, 10.0 ); nAttr.setStorable(true); frames = nAttr.create( "frames", "fr", MFnNumericData::kDouble, 48.0 ); nAttr.setStorable(true); //- Now add the attribute to your node definition using the addAttribute() //- method. //- Add the attributes we have created to the node. For compound attributes, //- you only need to add the parent attribute. addAttribute( input ); addAttribute( inputTranslate ); //- TODO: Add the compound attribute to the list of the node' attribute. //- TODO: Since the child-parent relationship has been setup, we only need //- TODO: to add the parent attribute. //... addAttribute( scale ); addAttribute( frames ); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. //- All input compound attributes' children will affect the individual children //- of the output compound attributes. Also, any change to the //- parent attribute is affecting the children of the output attribute and the //- output parent attribute as well. attributeAffects( inputTranslateX, outputTranslateX ); attributeAffects( inputTranslateY, outputTranslateY ); attributeAffects( inputTranslateZ, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslateX ); attributeAffects( inputTranslate, outputTranslateY ); attributeAffects( inputTranslate, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslate ); //- Other relationships, attributeAffects( input, outputTranslateX ); attributeAffects( input, outputTranslateY ); attributeAffects( scale, outputTranslateX ); attributeAffects( scale, outputTranslateY ); attributeAffects( frames, outputTranslateX ); attributeAffects( frames, outputTranslateY ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus transCircle::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. bool k = ( plug == outputTranslateX ) | ( plug == outputTranslateY ) | ( plug == outputTranslateZ ) | ( plug == outputTranslate ); if (!k) return MS::kUnknownParameter; //- Get a handle on the input attributes that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( input, &stat ); MDataHandle scaleData = data.inputValue( scale, &stat ); MDataHandle framesData = data.inputValue( frames, &stat ); //- Retrieve value of current frame attribute,scale factor //- and number of frames for one circle double currentFrame = inputData.asDouble(); double scaleFactor = scaleData.asDouble(); double framesPerCircle = framesData.asDouble(); //- Retrieve values on individual input translate attribute //- TODO: Retrieve the double value of the X, Y, Z components of the inputTranslate attribute MDataHandle inputTranslateXHandle = //... double inputTranslateXData = //... MDataHandle inputTranslateYHandle = //... double inputTranslateYData = //... MDataHandle inputTranslateZHandle = //... double inputTranslateZData = //... //- Calculate corresponding angle based on current frame double angle = 6.2831853 * ( currentFrame/framesPerCircle ); //- The value of output translate is input translate value plus the value of circular movement double outputTranslateXData = inputTranslateXData + (sin( angle ) * scaleFactor); double outputTranslateYData = inputTranslateYData + 1.0; double outputTranslateZData = inputTranslateZData + (cos( angle ) * scaleFactor); //- Get a handle on the output attributes and set the new value. //- TODO: Set the double value of the X, Y, Z components of the outputTranslate attribute MDataHandle outputTranslateXHandle = //... //... MDataHandle outputTranslateYHandle = //... //... MDataHandle outputTranslateZHandle = //... //... //- Tell Maya the plug is now clean data.setClean(plug); //- Return success to Maya return MS::kSuccess; } ================================================ FILE: 03_Nodes/transCircleNode/Exercise - C++/transCircleNode.h ================================================ // // Copyright (C) // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class transCircle : public MPxNode { public: transCircle() {} virtual ~transCircle() {} virtual MStatus compute( const MPlug& plug, MDataBlock& data ); static MStatus initialize(); static void* creator() { return new transCircle(); } public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // The input value. //- Compound attributes in Maya are build from several individual attributes. In //- our example the input compound attribute is made of inputTranslateX, //- inputTranslateY and inputTranslateZ. static MObject inputTranslateX; // The translate X value. (input) static MObject inputTranslateY; // The translate Y value. (input) static MObject inputTranslateZ; // The translate Z value. (input) static MObject inputTranslate; //- TODO: Declare a outputTranslate compound attribute and its X, Y, Z //- TODO: components, in order to make the rest of the code work, //- TODO: name your output parent object "outputTranslate",and its children //- TODO: "outputTranslateX", "outputTranslateY" and "outputTranslateZ" //... //... //... //... static MObject frames; // Number of frames for one circle. static MObject scale; // Radius of circle. //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 03_Nodes/transCircleNode/Exercise - C++/transCircleNode.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ createNode transCircle -n circleNode1; sphere -n sphere1 -r 1; sphere -n sphere2 -r 2; connectAttr sphere2.translate circleNode1.inputTranslate; connectAttr circleNode1.outputTranslate sphere1.translate; connectAttr time1.outTime circleNode1.input; ================================================ FILE: 03_Nodes/transCircleNode/Exercise - C++/transCircleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "transCircleNode", "transCircleNode.vcxproj", "{B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Debug|x64.ActiveCfg = Debug|x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Debug|x64.Build.0 = Debug|x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Release|x64.ActiveCfg = Release|x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 03_Nodes/transCircleNode/Exercise - C++/transCircleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/transCircleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) ..\..\..\plug-ins\transCircleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/transCircleNode.pdb Debug/transCircleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/transCircleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\transCircleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/transCircleNode.pdb Debug/transCircleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/transCircleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\transCircleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/transCircleNode.pdb Release/transCircleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/transCircleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\transCircleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/transCircleNode.pdb Release/transCircleNode.lib ================================================ FILE: 03_Nodes/transCircleNode/Exercise - py/AEtransCircleTemplate.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // // Creation Date: March 04, 2009 // // // Procedure Name: // AEtransCircleTemplate // // Description: // Creates the attribute editor controls for the transCircle node // // Input Value: // nodeName // // Output Value: // None // /////////////////////////////////////////////////////////////// // Example : /////////////////////////////////////////////////////////////// /* file -f -new; createNode transCircle; openAEWindow; */ global proc AEtransCircleTemplate( string $nodeName ) { // Put our attributes into a scrolled layout field editorTemplate -beginScrollLayout; // They all go into the collapsable "Parameters" section editorTemplate -beginLayout "Parameters" -collapse false; // Add a "special" control for the scale attribute that allow // "quick set" options for scales of 5, 10, and 15. editorTemplate -callCustom "transCircleScaleNew" "transCircleScaleReplace" "scale"; // Add the default controls for the scale and frames attributes editorTemplate -addControl "scale"; editorTemplate -addControl "frames"; editorTemplate -endLayout; // Create an "Extras" section and also add controls for any // attributes we have not explicitly mentioned. editorTemplate -addExtraControls; editorTemplate -endScrollLayout; // Tell the attribute editor not to display the attributes we // don't care about. editorTemplate -suppress "inputTranslate"; editorTemplate -suppress "input"; editorTemplate -suppress "caching"; editorTemplate -suppress "nodeState"; } /////////////////////////////////////////////////////////////// // // Description : // This procedure is called when the AE is editing a transCircle // node for the first time. Use this for creating the custom // layout and controls // global proc transCircleScaleNew( string $attrName ) { // Create the "quick set" control for the scale attribute radioButtonGrp -label "Quick Scale" -numberOfRadioButtons 3 -label1 "Five" -data1 5 -label2 "Ten" -data2 10 -label3 "Fifteen" -data3 15 scaleGrp; connectControl scaleGrp $attrName; } /////////////////////////////////////////////////////////////// // // Description : // This procedure is called whenever the AE is editing another // transCircle type. This procedure is necessary to reconnect // any controls with their associated attributes // global proc transCircleScaleReplace( string $attrName ) { // Install the connection between the radioButtonGrp and the // actual scale attribute connectControl scaleGrp $attrName; } ================================================ FILE: 03_Nodes/transCircleNode/Exercise - py/transCircleNode.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ createNode transCircle -n circleNode1; sphere -n sphere1 -r 1; sphere -n sphere2 -r 2; connectAttr sphere2.translate circleNode1.inputTranslate; connectAttr circleNode1.outputTranslate sphere1.translate; connectAttr time1.outTime circleNode1.input; ================================================ FILE: 03_Nodes/transCircleNode/Exercise - py/transCircleNode.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx #- Assing a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- 0x80013 is a temporary ID reserved for development. Never use that ID in a #- production environement. kPluginNodeTypeName = "transCircle" transCircleNodeId = OpenMaya.MTypeId(0x80013) # Node definition class transCircleNode(OpenMayaMPx.MPxNode): # Node attributes #- Compound attributes in Maya are build from several individual attributes. In #- our example the translation vector is made of the x,y,z attributes, and the #- compound attribute itself. inputTranslateX = OpenMaya.MObject() # The translate X value. (input) inputTranslateY = OpenMaya.MObject() # The translate Y value. (input) inputTranslateZ = OpenMaya.MObject() # The translate Z value. (input) inputTranslate = OpenMaya.MObject() #- TODO: Declare a outputTranslate coumpound attribute and its X, Y, Z #- TODO: components #... #... #... #... frames = OpenMaya.MObject() # Number of frames for one circle. scale = OpenMaya.MObject() # Radius of circle. def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self,plug,dataBlock): #- Check which output attribute we have been asked to compute. If this #- node doesn't know how to compute it, you must return MS::kUnknownParameter. if ( plug == transCircleNode.outputTranslateX or plug == transCircleNode.outputTranslateY or plug == transCircleNode.outputTranslateZ or plug == transCircleNode.outputTranslate ): #- Get a handle on the input attributes that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = data.inputValue( transCircleNode.input ) scaleData = data.inputValue( transCircleNode.scale ) framesData = data.inputValue( transCircleNode.frames ) #- Retrieve value of current frame attribute,scale factor #- and number of frames for one circle currentFrame = inputData.asDouble() scaleFactor = scaleData.asDouble() framesPerCircle = framesData.asDouble() #- Retrieve values on individual input translate attribute #- TODO: Retrieve the double value of the X, Y, Z components of the inputTranslate attribute inputTranslateXHandle = #... inputTranslateXData = #... inputTranslateYHandle = #... inputTranslateYData = #... inputTranslateZHandle = #... inputTranslateZData = #... #- Calculate corresponding angle based on current frame angle = 6.2831853 * ( currentFrame/framesPerCircle ) #- The value of output translate is input translate value plus the value of circular movement outputTranslateXData = inputTranslateXData + (sin( angle ) * scaleFactor) outputTranslateYData = inputTranslateYData + 1.0 outputTranslateZData = inputTranslateZData + (cos( angle ) * scaleFactor) #- Get a handle on the output attributes and set the new value. #- TODO: Set the double value of the X, Y, Z components of the outputTranslate attribute outputTranslateXHandle = #... #... outputTranslateYHandle = #... #... outputTranslateZHandle = #... #... #- Tell Maya the plug is now clean dataBlock.setClean( plug ) else: return OpenMaya.kUnknownParameter # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( transCircleNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- def nodeInitializer(): #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() transCircleNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kDouble, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(1) #- Create individual input translate attributes transCircleNode.inputTranslateX = nAttr.create( "inputTranslateX", "itX", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(1) transCircleNode.inputTranslateY = nAttr.create( "inputTranslateY", "itY", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(1) transCircleNode.inputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(1) #- Create compound input translate attributes and add individual input translate attributes comAttr = OpenMaya.MFnCompoundAttribute() transCircleNode.inputTranslate = comAttr.create("inputTranslate","it") comAttr.addChild(transCircleNode.inputTranslateX) comAttr.addChild(transCircleNode.inputTranslateY) comAttr.addChild(transCircleNode.inputTranslateZ) comAttr.setStorable(1) #- TODO: Create the outputTranslate coumpound attribute and its X, Y, Z #- TODO: components. Make the attribute saved into the Maya file, and not #- TODO: writable. Tips: properties needs to be set for each components, #- TODO: including the parent. #- Create individual output translate attributes #... #... #... #... #... #... #... #... #... #- Create compound output translate attributes and add individual output translate attributes #... #... #... #... #... #... #- Create other attributes for our node transCircleNode.scale = nAttr.create( "scale", "sc", OpenMaya.MFnNumericData.kDouble, 10.0 ) nAttr.setStorable(1) transCircleNode.frames = nAttr.create( "frames", "fr", OpenMaya.MFnNumericData.kDouble, 48.0 ) nAttr.setStorable(1) #- Now add the attribute to your node definition using the addAttribute() #- method. #- Add the attributes we have created to the node. For compound attributes, #- you only need to add the parent attribute. transCircleNode.addAttribute( transCircleNode.input ) transCircleNode.addAttribute( transCircleNode.inputTranslate ) #- TODO: Add the coumpound attribute to the list of the node' attribute. #- TODO: Since the child-parent relationship has been setup, we only need #- TODO: to add the parent attribute. #... transCircleNode.addAttribute( transCircleNode.scale ) transCircleNode.addAttribute( transCircleNode.frames ) #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimatelly in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. #- All input compound attributes' component will affects the output components #- of the output compound attributes' components. Including the parent attribute. transCircleNode.attributeAffects( transCircleNode.inputTranslateX, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.inputTranslateY, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.inputTranslateZ, transCircleNode.outputTranslateZ ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslateZ ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslate ) #- Other relationships, transCircleNode.attributeAffects( transCircleNode.input, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.input, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.scale, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.scale, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.frames, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.frames, transCircleNode.outputTranslateY ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Register your node here, so Maya can use it and recognize it #- TODO: while reading/saving a file which has instance of this node type. #... except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Unregister your node here, so Maya stops using it. #... except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 03_Nodes/transCircleNode/Solution - C++/AEtransCircleTemplate.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // // Creation Date: March 04, 2009 // // // Procedure Name: // AEtransCircleTemplate // // Description: // Creates the attribute editor controls for the transCircle node // // Input Value: // nodeName // // Output Value: // None // /////////////////////////////////////////////////////////////// // Example : /////////////////////////////////////////////////////////////// /* file -f -new; createNode transCircle; openAEWindow; */ global proc AEtransCircleTemplate( string $nodeName ) { // Put our attributes into a scrolled layout field editorTemplate -beginScrollLayout; // The all go into the collapsable "Parameters" section editorTemplate -beginLayout "Parameters" -collapse false; // Add a "special" control for the scale attribute that allow // "quick set" options for scales of 5, 10, and 15. editorTemplate -callCustom "transCircleScaleNew" "transCircleScaleReplace" "scale"; // Add the default controls for the scale and frames attributes editorTemplate -addControl "scale"; editorTemplate -addControl "frames"; editorTemplate -endLayout; // Create an "Extras" section and also add controls for any // attributes we have not explicitly mentioned. editorTemplate -addExtraControls; editorTemplate -endScrollLayout; // Tell the attribute editor not to display the attributes we // don't care about. editorTemplate -suppress "inputTranslate"; editorTemplate -suppress "input"; editorTemplate -suppress "caching"; editorTemplate -suppress "nodeState"; } /////////////////////////////////////////////////////////////// // // Description : // This procedure is called when the AE is editing a transCircle // node for the first time. Use this for creating the custom // layout and controls // global proc transCircleScaleNew( string $attrName ) { // Maya the "quick set" control for the scale attribute radioButtonGrp -label "Quick Scale" -numberOfRadioButtons 3 -label1 "Five" -data1 5 -label2 "Ten" -data2 10 -label3 "Fifteen" -data3 15 scaleGrp; connectControl scaleGrp $attrName; } /////////////////////////////////////////////////////////////// // // Description : // This procedure is called whenever the AE is editing another // transCircle type. This procedure is necessary to reconnect // any controls with their associated attributes // global proc transCircleScaleReplace( string $attrName ) { // Install the connection between the radioButtonGrp and the // actual scale attribute connectControl scaleGrp $attrName; } ================================================ FILE: 03_Nodes/transCircleNode/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "transCircleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // status = plugin.registerNode( "transCircle", transCircle::id, transCircle::creator, transCircle::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterNode( transCircle::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 03_Nodes/transCircleNode/Solution - C++/transCircleNode.cpp ================================================ // // Copyright (C) // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #include "transCircleNode.h" //- Assing a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x80013 is a temporary ID reserved for development. Never use that ID in a //- production environment. /*static*/MTypeId transCircle::id( 0x80013 ); //- Instantiate the static attributes of your node class. /*static*/MObject transCircle::input; /*static*/MObject transCircle::frames; /*static*/MObject transCircle::scale; /*static*/MObject transCircle::inputTranslateX; /*static*/MObject transCircle::inputTranslateY; /*static*/MObject transCircle::inputTranslateZ; /*static*/MObject transCircle::inputTranslate; /*static*/MObject transCircle::outputTranslateX; /*static*/MObject transCircle::outputTranslateY; /*static*/MObject transCircle::outputTranslateZ; /*static*/MObject transCircle::outputTranslate; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus transCircle::initialize() { //- Create a numeric attribute using MFnNumericAttribute MFnNumericAttribute nAttr; input = nAttr.create( "input", "in", MFnNumericData::kDouble, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Create individual input translate attributes inputTranslateX = nAttr.create( "inputTranslateX", "itX", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateY = nAttr.create( "inputTranslateY", "itY", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); //- Create compound input translate attributes by adding individual input translate attributes MFnCompoundAttribute comAttr; inputTranslate = comAttr.create("inputTranslate","it"); comAttr.addChild(inputTranslateX); comAttr.addChild(inputTranslateY); comAttr.addChild(inputTranslateZ); comAttr.setStorable(true); //- Create individual output translate attributes outputTranslateX = nAttr.create( "outputTranslateX", "otX", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslateY = nAttr.create( "outputTranslateY", "otY",MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslateZ = nAttr.create( "outputTranslateZ", "otZ", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); //- Create compound output translate attributes by adding individual output translate attributes outputTranslate = comAttr.create( "outputTranslate", "ot" ); comAttr.addChild(outputTranslateX); comAttr.addChild(outputTranslateY); comAttr.addChild(outputTranslateZ); comAttr.setWritable(false); comAttr.setStorable(true); //- Create other attributes for our node scale = nAttr.create( "scale", "sc",MFnNumericData::kDouble, 10.0 ); nAttr.setStorable(true); frames = nAttr.create( "frames", "fr", MFnNumericData::kDouble, 48.0 ); nAttr.setStorable(true); //- Now add the attribute to your node definition using the addAttribute() //- method. //- Add the attributes we have created to the node. For compound attributes, //- you only need to add the parent attribute. addAttribute( input ); addAttribute( inputTranslate ); addAttribute( outputTranslate ); addAttribute( scale ); addAttribute( frames ); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimatelly in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. //- All input compound attributes' children will affect the individual children //- of the output compound attributes. Also, any change to the //- parent attribute is affecting the children of the output attribute and the //- output parent attribute as well. attributeAffects( inputTranslateX, outputTranslateX ); attributeAffects( inputTranslateY, outputTranslateY ); attributeAffects( inputTranslateZ, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslateX ); attributeAffects( inputTranslate, outputTranslateY ); attributeAffects( inputTranslate, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslate ); //- Other relationships, attributeAffects( input, outputTranslateX ); attributeAffects( input, outputTranslateY ); attributeAffects( scale, outputTranslateX ); attributeAffects( scale, outputTranslateY ); attributeAffects( frames, outputTranslateX ); attributeAffects( frames, outputTranslateY ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus transCircle::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. bool k = ( plug == outputTranslateX ) | ( plug == outputTranslateY ) | ( plug == outputTranslateZ ) | ( plug == outputTranslate ); if (!k) return MS::kUnknownParameter; //- Get a handle on the input attributes that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( input, &stat ); MDataHandle scaleData = data.inputValue( scale, &stat ); MDataHandle framesData = data.inputValue( frames, &stat ); //- Retrieve value of current frame attribute,scale factor //- and number of frames for one circle double currentFrame = inputData.asDouble(); double scaleFactor = scaleData.asDouble(); double framesPerCircle = framesData.asDouble(); //- Retrieve values on individual input translate attribute MDataHandle inputTranslateXHandle = data.inputValue(inputTranslateX); double inputTranslateXData = inputTranslateXHandle.asDouble(); MDataHandle inputTranslateYHandle = data.inputValue(inputTranslateY); double inputTranslateYData = inputTranslateYHandle.asDouble(); MDataHandle inputTranslateZHandle = data.inputValue(inputTranslateZ); double inputTranslateZData = inputTranslateZHandle.asDouble(); //- Calculate corresponding angle based on current frame double angle = 6.2831853 * ( currentFrame/framesPerCircle ); //- The value of output translate is input translate value plus the value of circular movement double outputTranslateXData = inputTranslateXData + (sin( angle ) * scaleFactor); double outputTranslateYData = inputTranslateYData + 1.0; double outputTranslateZData = inputTranslateZData + (cos( angle ) * scaleFactor); //- Get a handle on the output attributes and set the new value. MDataHandle outputTranslateXHandle = data.outputValue( outputTranslateX ); outputTranslateXHandle.set(outputTranslateXData); MDataHandle outputTranslateYHandle = data.outputValue( outputTranslateY ); outputTranslateYHandle.set(outputTranslateYData); MDataHandle outputTranslateZHandle = data.outputValue( outputTranslateZ ); outputTranslateZHandle.set(outputTranslateZData); //- Tell Maya the plug is now clean data.setClean(plug); //- Return success to Maya return MS::kSuccess; } ================================================ FILE: 03_Nodes/transCircleNode/Solution - C++/transCircleNode.h ================================================ // // Copyright (C) // // File: // // Dependency Graph Node: // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class transCircle : public MPxNode { public: transCircle() {} virtual ~transCircle() {} virtual MStatus compute( const MPlug& plug, MDataBlock& data ); static MStatus initialize(); static void* creator() { return new transCircle(); } public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // The input value. //- Compound attributes in Maya are build from several individual attributes. In //- our example the input compound attribute is made of inputTranslateX, //- inputTranslateY and inputTranslateZ. static MObject inputTranslateX; // The translate X value. (input) static MObject inputTranslateY; // The translate Y value. (input) static MObject inputTranslateZ; // The translate Z value. (input) static MObject inputTranslate; static MObject outputTranslateX; // The translate X value. (output) static MObject outputTranslateY; // The translate Y value. (output) static MObject outputTranslateZ; // The translate Z value. (output) static MObject outputTranslate; static MObject frames; // Number of frames for one circle. static MObject scale; // Radius of circle. //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 03_Nodes/transCircleNode/Solution - C++/transCircleNode.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ createNode transCircle -n circleNode1; sphere -n sphere1 -r 1; sphere -n sphere2 -r 2; connectAttr sphere2.translate circleNode1.inputTranslate; connectAttr circleNode1.outputTranslate sphere1.translate; connectAttr time1.outTime circleNode1.input; ================================================ FILE: 03_Nodes/transCircleNode/Solution - C++/transCircleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "transCircleNode", "transCircleNode.vcxproj", "{B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Debug|x64.ActiveCfg = Debug|x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Debug|x64.Build.0 = Debug|x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Release|x64.ActiveCfg = Release|x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 03_Nodes/transCircleNode/Solution - C++/transCircleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {B6A0AEBE-B5EE-4EB6-BE01-F1738C49F587} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/transCircleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) ..\..\..\plug-ins\transCircleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/transCircleNode.pdb Debug/transCircleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/transCircleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\transCircleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/transCircleNode.pdb Debug/transCircleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/transCircleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\transCircleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/transCircleNode.pdb Release/transCircleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/transCircleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\transCircleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/transCircleNode.pdb Release/transCircleNode.lib ================================================ FILE: 03_Nodes/transCircleNode/Solution - py/AEtransCircleTemplate.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // // Creation Date: March 04, 2009 // // // Procedure Name: // AEtransCircleTemplate // // Description: // Creates the attribute editor controls for the transCircle node // // Input Value: // nodeName // // Output Value: // None // /////////////////////////////////////////////////////////////// // Example : /////////////////////////////////////////////////////////////// /* file -f -new; createNode transCircle; openAEWindow; */ global proc AEtransCircleTemplate( string $nodeName ) { // Put our attributes into a scrolled layout field editorTemplate -beginScrollLayout; // They all go into the collapsable "Parameters" section editorTemplate -beginLayout "Parameters" -collapse false; // Add a "special" control for the scale attribute that allow // "quick set" options for scales of 5, 10, and 15. editorTemplate -callCustom "transCircleScaleNew" "transCircleScaleReplace" "scale"; // Add the default controls for the scale and frames attributes editorTemplate -addControl "scale"; editorTemplate -addControl "frames"; editorTemplate -endLayout; // Create an "Extras" section and also add controls for any // attributes we have not explicitly mentioned. editorTemplate -addExtraControls; editorTemplate -endScrollLayout; // Tell the attribute editor not to display the attributes we // don't care about. editorTemplate -suppress "inputTranslate"; editorTemplate -suppress "input"; editorTemplate -suppress "caching"; editorTemplate -suppress "nodeState"; } /////////////////////////////////////////////////////////////// // // Description : // This procedure is called when the AE is editing a transCircle // node for the first time. Use this for creating the custom // layout and controls // global proc transCircleScaleNew( string $attrName ) { // Create the "quick set" control for the scale attribute radioButtonGrp -label "Quick Scale" -numberOfRadioButtons 3 -label1 "Five" -data1 5 -label2 "Ten" -data2 10 -label3 "Fifteen" -data3 15 scaleGrp; connectControl scaleGrp $attrName; } /////////////////////////////////////////////////////////////// // // Description : // This procedure is called whenever the AE is editing another // transCircle type. This procedure is necessary to reconnect // any controls with their associated attributes // global proc transCircleScaleReplace( string $attrName ) { // Install the connection between the radioButtonGrp and the // actual scale attribute connectControl scaleGrp $attrName; } ================================================ FILE: 03_Nodes/transCircleNode/Solution - py/transCircleNode.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ createNode transCircle -n circleNode1; sphere -n sphere1 -r 1; sphere -n sphere2 -r 2; connectAttr sphere2.translate circleNode1.inputTranslate; connectAttr circleNode1.outputTranslate sphere1.translate; connectAttr time1.outTime circleNode1.input; ================================================ FILE: 03_Nodes/transCircleNode/Solution - py/transCircleNode.py ================================================ # # Copyright (C) # # File: transCircleNode.py # # Dependency Graph Node: # # Author: Maya Plug-in Wizard 2.0 # import sys, math import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx #- Assing a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- 0x80013 is a temporary ID reserved for development. Never use that ID in a #- production environement. kPluginNodeTypeName = "transCircle" transCircleNodeId = OpenMaya.MTypeId(0x80013) # Node definition class transCircleNode(OpenMayaMPx.MPxNode): # Node attributes #- Compound attributes in Maya are build from several individual attributes. In #- our example the translation vector is made of the x,y,z attributes, and the #- compound attribute itself. inputTranslateX = OpenMaya.MObject() # The translate X value. (input) inputTranslateY = OpenMaya.MObject() # The translate Y value. (input) inputTranslateZ = OpenMaya.MObject() # The translate Z value. (input) inputTranslate = OpenMaya.MObject() outputTranslateX = OpenMaya.MObject() # The translate X value. (output) outputTranslateY = OpenMaya.MObject() # The translate Y value. (output) outputTranslateZ = OpenMaya.MObject() # The translate Z value. (output) outputTranslate = OpenMaya.MObject() frames = OpenMaya.MObject() # Number of frames for one circle. scale = OpenMaya.MObject() # Radius of circle. def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- dataBlock - object that provides access to the attributes for this node def compute(self,plug,dataBlock): #- Check which output attribute we have been asked to compute. If this #- node doesn't know how to compute it, you must return MS::kUnknownParameter. if ( plug == transCircleNode.outputTranslateX or plug == transCircleNode.outputTranslateY or plug == transCircleNode.outputTranslateZ or plug == transCircleNode.outputTranslate ): #- Get a handle on the input attributes that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = dataBlock.inputValue( transCircleNode.input ) scaleData = dataBlock.inputValue( transCircleNode.scale ) framesData = dataBlock.inputValue( transCircleNode.frames ) #- Retrieve value of current frame attribute,scale factor #- and number of frames for one circle currentFrame = inputData.asDouble() scaleFactor = scaleData.asDouble() framesPerCircle = framesData.asDouble() #- Retrieve values on individual input translate attribute inputTranslateXHandle = dataBlock.inputValue(transCircleNode.inputTranslateX) inputTranslateXData = inputTranslateXHandle.asDouble() inputTranslateYHandle = dataBlock.inputValue(transCircleNode.inputTranslateY) inputTranslateYData = inputTranslateYHandle.asDouble() inputTranslateZHandle = dataBlock.inputValue(transCircleNode.inputTranslateZ) inputTranslateZData = inputTranslateZHandle.asDouble() #- Calculate corresponding angle based on current frame angle = 6.2831853 * ( currentFrame/framesPerCircle ) #- The value of output translate is input translate value plus the value of circular movement outputTranslateXData = inputTranslateXData + (math.sin( angle ) * scaleFactor) outputTranslateYData = inputTranslateYData + 1.0 outputTranslateZData = inputTranslateZData + (math.cos( angle ) * scaleFactor) #- Get a handle on the output attributes and set the new value. outputTranslateXHandle = dataBlock.outputValue( transCircleNode.outputTranslateX ) outputTranslateXHandle.setDouble(outputTranslateXData) outputTranslateYHandle = dataBlock.outputValue( transCircleNode.outputTranslateY ) outputTranslateYHandle.setDouble(outputTranslateYData) outputTranslateZHandle = dataBlock.outputValue( transCircleNode.outputTranslateZ ) outputTranslateZHandle.setDouble(outputTranslateZData) #- Tell Maya the plug is now clean dataBlock.setClean( plug ) else: return OpenMaya.kUnknownParameter # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( transCircleNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- def nodeInitializer(): #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() transCircleNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kDouble, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(1) #- Create individual input translate attributes transCircleNode.inputTranslateX = nAttr.create( "inputTranslateX", "itX", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(1) transCircleNode.inputTranslateY = nAttr.create( "inputTranslateY", "itY", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(1) transCircleNode.inputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(1) #- Create compound input translate attributes and add individual input translate attributes comAttr = OpenMaya.MFnCompoundAttribute() transCircleNode.inputTranslate = comAttr.create("inputTranslate","it") comAttr.addChild(transCircleNode.inputTranslateX) comAttr.addChild(transCircleNode.inputTranslateY) comAttr.addChild(transCircleNode.inputTranslateZ) comAttr.setStorable(1) #- Create individual output translate attributes transCircleNode.outputTranslateX = nAttr.create( "outputTranslateX", "otX", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(0) nAttr.setStorable(1) transCircleNode.outputTranslateY = nAttr.create( "outputTranslateY", "otY", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(0) nAttr.setStorable(1) transCircleNode.outputTranslateZ = nAttr.create( "outputTranslateZ", "otZ", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(0) nAttr.setStorable(1) #- Create compound output translate attributes and add individual output translate attributes transCircleNode.outputTranslate = comAttr.create("outputTranslate","ot") comAttr.addChild(transCircleNode.outputTranslateX) comAttr.addChild(transCircleNode.outputTranslateY) comAttr.addChild(transCircleNode.outputTranslateZ) comAttr.setWritable(0) comAttr.setStorable(1) #- Create other attributes for our node transCircleNode.scale = nAttr.create( "scale", "sc", OpenMaya.MFnNumericData.kDouble, 10.0 ) nAttr.setStorable(1) transCircleNode.frames = nAttr.create( "frames", "fr", OpenMaya.MFnNumericData.kDouble, 48.0 ) nAttr.setStorable(1) #- Now add the attribute to your node definition using the addAttribute() #- method. #- Add the attributes we have created to the node. For compound attributes, #- you only need to add the parent attribute. transCircleNode.addAttribute( transCircleNode.input ) transCircleNode.addAttribute( transCircleNode.inputTranslate ) transCircleNode.addAttribute( transCircleNode.outputTranslate ) transCircleNode.addAttribute( transCircleNode.scale ) transCircleNode.addAttribute( transCircleNode.frames ) #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimatelly in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. #- All input compound attributes' component will affects the output components #- of the output compound attributes' components. Including the parent attribute. transCircleNode.attributeAffects( transCircleNode.inputTranslateX, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.inputTranslateY, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.inputTranslateZ, transCircleNode.outputTranslateZ ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslateZ ) transCircleNode.attributeAffects( transCircleNode.inputTranslate, transCircleNode.outputTranslate ) #- Other relationships, transCircleNode.attributeAffects( transCircleNode.input, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.input, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.scale, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.scale, transCircleNode.outputTranslateY ) transCircleNode.attributeAffects( transCircleNode.frames, transCircleNode.outputTranslateX ) transCircleNode.attributeAffects( transCircleNode.frames, transCircleNode.outputTranslateY ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, transCircleNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( transCircleNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 04_NodeAttributes/dynNode/Exercise - C++/DynNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DynNode", "DynNode.vcxproj", "{CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Debug|x64.ActiveCfg = Debug|x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Debug|x64.Build.0 = Debug|x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Release|x64.ActiveCfg = Release|x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 04_NodeAttributes/dynNode/Exercise - C++/DynNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ .mll /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\My Documents\maya\2009\plug-ins\dynNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\dynNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 04_NodeAttributes/dynNode/Exercise - C++/dynNode.cpp ================================================ // // Copyright (C) // // File: dynNode.cpp // // Dependency Graph Node: dynNode // // Author: Maya Plug-in Wizard 2.0 // #include "dynNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x00001 is a temporary ID reserved for development. Never use that ID in a //- production environment. /*static*/ MTypeId dynNode::id( 0x00001 ); //- Instantiate the static attributes of your node class. /*static*/ MObject dynNode::input; /*static*/ MObject dynNode::output; //- No MPxNode member function can be called from the MPxNode constructor. //- The postConstructor will get called immediately after the constructor //- so it is safe to call any MPxNode member function in postConstructor(). //- TODO: Implement postConstructor(), create dynamic attribute and add it onto the node //... //... //... //... //- The setDependentsDirty() method allows attributeAffects relationships //- in a much more general way than via MPxNode::attributeAffects //- which is limited to static attributes only. //- The setDependentsDirty() method allows relationships to be established //- between any combination of dynamic and static attributes. //- //- Within a setDependentsDirty(), you get passed in the //- plug (the first argument "dirtyPlug"), which is being set dirty, //- and then, based upon which plug it is,you may choose to dirty any other //- plugs by adding them to the affectedPlugs list (the second argument "plugArray"). //- Arguments: //- dirtyPlug - the plug which Maya sets dirty //- plugArray - an array of plugs which are affected by the first plug //- TODO: Implement setDependentsDirty() so that the dynamic attribute is affecting //- TODO: attribute "output" //... //... //... //... //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus dynNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; dynNode::input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute is not saved into Maya file. dynNode::output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 ); //- Attribute will not be written to files when this type of node is stored nAttr.setStorable(false); //- Now add the attribute to your node definition using the addAttribute() //- method. addAttribute( dynNode::input ); addAttribute( dynNode::output ); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. attributeAffects( dynNode::input, dynNode::output ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus dynNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == dynNode::output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( dynNode::input, &returnStatus ); //- Read the input value from the handle. float inputValue = inputData.asFloat(); //- Since output is affected by the dynamic attribute too, //- retrieve the dynamic attribute value //- TODO: Get a handle to the dynamic attribute and assign its //- TODO: value to a float variable "dynValue" //... //... //- Get a handle to the output attribute. This is similar to the //- "inputValue" call above except that no dependency graph //- computation will be done as a result of this call. //- Get a handle on the output attribute MDataHandle outputHandle = data.outputValue( dynNode::output ); //- Set the new output value to the handle. outputHandle.set( inputValue + dynValue ); //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let's give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 04_NodeAttributes/dynNode/Exercise - C++/dynNode.h ================================================ // // Copyright (C) // // File: dynNode.h // // Dependency Graph Node: dynNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class dynNode : public MPxNode { public: dynNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~dynNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new dynNode(); } //- Declare the static initialize() method. static MStatus initialize(); ///- TODO: Declare the virtual postConstructor() method. //... //- TODO: Declare the virtual setDependentsDirty() method. //... public: //- There needs to be a MObject handle declared for each attribute that //- the node will have. These handles are needed for getting and setting //- the values later. // static MObject input; // input attribute static MObject output; // output attribute //- TODO: Declare a member variable to store the dynamic attribute //... //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 04_NodeAttributes/dynNode/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "dynNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2008", "Any"); //- Register your node here, so Maya can use it and recognize it //- while reading/saving a file which has instance of this node type. status = plugin.registerNode( "dynNode", dynNode::id, dynNode::creator, dynNode::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); //- Unregister your node here, so Maya stops using it. status = plugin.deregisterNode( dynNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 04_NodeAttributes/dynNode/Exercise - py/dynNode.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys #- Assigning a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- 0x00001 is a temporary ID for reserved for development. Never use that ID in a #- production environment. kPluginNodeTypeName = "dynNode" dynNodeId = OpenMaya.MTypeId(0x00001) # Node definition class dynNode(OpenMayaMPx.MPxNode): aInput = OpenMaya.MObject() aOutput = OpenMaya.MObject() dynAttr = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- No MPxNode member function can be called from the MPxNode constructor. #- The postConstructor will get called immediately after the constructor #- so it is safe to call any MPxNode member function in postConstructor(). #- TODO: Implement postConstructor(), create dynamic attribute and add it onto the node #... #... #... #... #- The setDependentsDirty() method allows attributeAffects relationships #- in a much more general way than via MPxNode::attributeAffects #- which is limited to static attributes only. #- The setDependentsDirty() method allows relationships to be established #- between any combination of dynamic and static attributes. #- #- Within a setDependentsDirty(), you get passed in the #- plug (the first argument "dirtyPlug"), which is being set dirty, #- and then, based upon which plug it is,you may choose to dirty any other #- plugs by adding them to the affectedPlugs list (the second argument "plugArray"). #- Arguments: #- dirtyPlug - the plug which Maya sets dirty #- plugArray - an array of plugs which are affected by the first plug #- TODO: Implement setDependentsDirty() so that the dynamic attribute is affecting #- TODO: attribute "output" #... #... #... #... #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self,plug,data): #- Check which output attribute we have been asked to compute. If this #- node doesn't know how to compute it, you must return MS::kUnknownParameter. if plug == dynNode.aOutput: #- Get a handle to the input attribute that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = data.inputValue(dynNode.aInput) #- Read the input value from the handle. inputValue = inputData.asFloat() #- Since output is affected by the dynamic attribute too, #- retrieve the dynamic attribute value #- TODO: Get a handle to the dynamic attribute and assign its #- TODO: value to a float variable "dynValue" #... #... #- Get a handle to the output attribute. This is similar to the #- "inputValue" call above except that no dependency graph #- computation will be done as a result of this call. #- Get a handle on the aOutput attribute outputHandle = data.outputValue(dynNode.aOutput) #- Set the new output value to the handle. outputHandle.setFloat( inputValue + dynValue ) #- Tell Maya that we do not know how to handle this plug, but let's give a chance #- to our parent class to evaluate it. else: return OpenMaya.kUnknownParameter # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( dynNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- Return Values: MS::kSuccess / MS::kFailure def nodeInitializer(): #- Initialize a float input attribute using the MFnNumericAttribute #- class. Make that attribute definition saved into Maya file (setStorable), #- and selectable in the channel box (setKeyable). #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() dynNode.aInput = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(True) #- Attribute is keyable and will show up in the channel box nAttr.setKeyable(True) #- Initialize a float output attribute using the MFnNumericAttribute #- class. Make that attribute is not saved into Maya file. dynNode.aOutput = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will not be written to files when this type of node is stored nAttr.setStorable(False) #- Now add the attribute to your node definition using the addAttribute() #- method. dynNode.addAttribute( dynNode.aInput ) dynNode.addAttribute( dynNode.aOutput ) #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimately in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. dynNode.attributeAffects( dynNode.aInput, dynNode.aOutput ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, dynNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( dynNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 04_NodeAttributes/dynNode/Solution - C++/DynNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DynNode", "DynNode.vcxproj", "{CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Debug|x64.ActiveCfg = Debug|x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Debug|x64.Build.0 = Debug|x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Release|x64.ActiveCfg = Release|x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 04_NodeAttributes/dynNode/Solution - C++/DynNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {CC44F4F1-DFF1-466C-AEC2-1F36FB80F568} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ .mll /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2010\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\My Documents\maya\2010\plug-ins\dynNode.mll C:\Program Files\Autodesk\Maya2010\lib;%(AdditionalLibraryDirectories) Debug/.pdb false Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\dynNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb false Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb false Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb false Release/.lib ================================================ FILE: 04_NodeAttributes/dynNode/Solution - C++/dynNode.cpp ================================================ // // Copyright (C) // // File: dynNode.cpp // // Dependency Graph Node: dynNode // // Author: Maya Plug-in Wizard 2.0 // #include "dynNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x00001 is a temporary ID for reserved for development. Never use that ID in a //- production environment. /*static*/ MTypeId dynNode::id( 0x00001 ); //- Instantiate the static attributes of your node class. /*static*/ MObject dynNode::input; /*static*/ MObject dynNode::output; //- No MPxNode member function can be called from the MPxNode constructor. //- The postConstructor will get called immediately after the constructor //- so it is safe to call any MPxNode member function in postConstructor(). void dynNode::postConstructor() { //- Create a dynamic float attribute and add it onto the node MFnNumericAttribute nAttr; dynAttr = nAttr.create( "dynAttr", "da", MFnNumericData::kFloat, 0.0 ); nAttr.setStorable(true); nAttr.setKeyable(true); //- Add this dynamic attribute onto this node //- You cannot call addAttribute() directly, if you look into the MPxNode //- documentation, addAttribute()only works during the static initialization //- method of the user defined node class MObject thisNode = thisMObject(); MFnDependencyNode depNode(thisNode); depNode.addAttribute(dynAttr); } //- The setDependentsDirty() method allows attributeAffects relationships //- in a much more general way than via MPxNode::attributeAffects //- which is limited to static attributes only. //- The setDependentsDirty() method allows relationships to be established //- between any combination of dynamic and static attributes. //- //- Within a setDependentsDirty(), you get passed in the //- plug (the first argument "dirtyPlug"), which is being set dirty, //- and then, based upon which plug it is,you may choose to dirty any other //- plugs by adding them to the affectedPlugs list (the second argument "plugArray"). //- Arguments: //- dirtyPlug - the plug which Maya sets dirty //- plugArray - an array of plugs which are affected by the first plug MStatus dynNode::setDependentsDirty(const MPlug &dirtyPlug, MPlugArray &plugArray) { //- This code shows how to make a dynamic attribute (dynAttr) //- affect a static attribute (output) //- Check if the dynamic attribute is set to dirty by Maya if( dirtyPlug.partialName() == "da" ) { //- Set the output plug to be affected by this dynamic attribute //- by adding the output plug onto the plugArray MObject thisNode = thisMObject(); MPlug outputPlug( thisNode, dynNode::output ); plugArray.append(outputPlug); } return MS::kSuccess; } //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus dynNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; dynNode::input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute is not saved into Maya file. dynNode::output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 ); //- Attribute will not be written to files when this type of node is stored nAttr.setStorable(false); //- Now add the attribute to your node definition using the addAttribute() //- method. addAttribute( dynNode::input ); addAttribute( dynNode::output ); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. attributeAffects( dynNode::input, dynNode::output ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus dynNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == dynNode::output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( dynNode::input, &returnStatus ); //- Read the input value from the handle. float inputValue = inputData.asFloat(); //- Since output is affected by the dynamic attribute too, //- retrieve the dynamic attribute value MDataHandle dynData = data.inputValue( dynAttr, &returnStatus ); float dynValue = dynData.asFloat(); //- Get a handle to the output attribute. This is similar to the //- "inputValue" call above except that no dependency graph //- computation will be done as a result of this call. //- Get a handle on the output attribute MDataHandle outputHandle = data.outputValue( dynNode::output ); //- Set the new output value to the handle. outputHandle.set( inputValue + dynValue ); //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let's give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 04_NodeAttributes/dynNode/Solution - C++/dynNode.h ================================================ // // Copyright (C) // // File: dynNode.h // // Dependency Graph Node: dynNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class dynNode : public MPxNode { public: dynNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~dynNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new dynNode(); } //- Declare the static initialize() method. static MStatus initialize(); //- Declare the virtual postConstructor() method. virtual void postConstructor(); //- Declare the virtual setDependentsDirty() method. virtual MStatus setDependentsDirty(const MPlug &dirtyPlug,MPlugArray &plugArray); public: //- There needs to be a MObject handle declared for each attribute that //- the node will have. These handles are needed for getting and setting //- the values later. // static MObject input; // input attribute static MObject output; // output attribute //- Declare a member variable to store the dynamic attribute MObject dynAttr; //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 04_NodeAttributes/dynNode/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "dynNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2008", "Any"); //- Register your node here, so Maya can use it and recognize it //- while reading/saving a file which has instance of this node type. status = plugin.registerNode( "dynNode", dynNode::id, dynNode::creator, dynNode::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); //- Unregister your node here, so Maya stops using it. status = plugin.deregisterNode( dynNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 04_NodeAttributes/dynNode/Solution - py/dynNode.py ================================================ # # Copyright (C) # # File: dynNode.py # # Dependency Graph Node: # # Author: Maya Plug-in Wizard 2.0 # import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys #- Assigning a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- 0x00001 is a temporary ID for reserved for development. Never use that ID in a #- production environment. kPluginNodeTypeName = "dynNode" dynNodeId = OpenMaya.MTypeId(0x00001) # Node definition class dynNode(OpenMayaMPx.MPxNode): aInput = OpenMaya.MObject() aOutput = OpenMaya.MObject() dynAttr = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self,plug,data): #- Check which output attribute we have been asked to compute. If this #- node doesn't know how to compute it, you must return MS::kUnknownParameter. if plug == dynNode.aOutput: #- Get a handle to the input attribute that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = data.inputValue(dynNode.aInput) #- Read the input value from the handle. inputValue = inputData.asFloat() print inputValue #- Since output is affected by the dynamic attribute too, #- retrieve the dynamic attribute value dynData = data.inputValue(self.dynAttr) dynValue = dynData.asFloat() print dynValue #- Get a handle to the output attribute. This is similar to the #- "inputValue" call above except that no dependency graph #- computation will be done as a result of this call. #- Get a handle on the aOutput attribute outputHandle = data.outputValue(dynNode.aOutput) #- Set the new output value to the handle. print "combined Value", inputValue + dynValue outputHandle.setFloat( inputValue + dynValue ) #- Tell Maya that we do not know how to handle this plug, but let's give a chance #- to our parent class to evaluate it. else: return OpenMaya.kUnknownParameter #- No MPxNode member function can be called from the MPxNode constructor. #- The postConstructor will get called immediately after the constructor #- so it is safe to call any MPxNode member function in postConstructor(). def postConstructor(self): #- Create a dynamic float attribute and add it onto the node nAttr = OpenMaya.MFnNumericAttribute() self.dynAttr = nAttr.create( "dynAttr", "da", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(True) nAttr.setKeyable(True) #- Add this dynamic attribute onto this node #- You cannot call addAttribute() directly, if you look into the MPxNode #- documentation, addAttribute()only works during the static initialization #- method of the user defined node class thisNode = self.thisMObject() fnThisNode = OpenMaya.MFnDependencyNode(thisNode) print "Adding Dynamic Attribute" fnThisNode.addAttribute(self.dynAttr) #- The setDependentsDirty() method allows attributeAffects relationships #- in a much more general way than via MPxNode::attributeAffects #- which is limited to static attributes only. #- The setDependentsDirty() method allows relationships to be established #- between any combination of dynamic and static attributes. #- #- Within a setDependentsDirty(), you get passed in the #- plug (the first argument "dirtyPlug"), which is being set dirty, #- and then, based upon which plug it is,you may choose to dirty any other #- plugs by adding them to the affectedPlugs list (the second argument "plugArray"). #- Arguments: #- dirtyPlug - the plug which Maya sets dirty #- plugArray - an array of plugs which are affected by the first plug def setDependentsDirty(self, dirtyPlug, plugArray): #- This code shows how to make a dynamic attribute (dynAttr) #- affect a static attribute (output) #- Check if the dynamic attribute is set to dirty by Maya if dirtyPlug == self.dynAttr: #- Set the output plug to be affected by this dynamic attribute #- by adding the output plug onto the plugArray thisNode = self.thisMObject() try: plug = OpenMaya.MPlug(thisNode, dynNode.aOutput) plugArray.append(plug) except: pass return OpenMayaMPx.MPxNode.setDependentsDirty(self, dirtyPlug, plugArray) # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( dynNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- Return Values: MS::kSuccess / MS::kFailure def nodeInitializer(): #- Initialize a float input attribute using the MFnNumericAttribute #- class. Make that attribute definition saved into Maya file (setStorable), #- and selectable in the channel box (setKeyable). #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() dynNode.aInput = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(True) #- Attribute is keyable and will show up in the channel box nAttr.setKeyable(True) #- Initialize a float output attribute using the MFnNumericAttribute #- class. Make that attribute is not saved into Maya file. dynNode.aOutput = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will not be written to files when this type of node is stored nAttr.setStorable(False) #- Now add the attribute to your node definition using the addAttribute() #- method. dynNode.addAttribute( dynNode.aInput ) dynNode.addAttribute( dynNode.aOutput ) #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimately in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. dynNode.attributeAffects( dynNode.aInput, dynNode.aOutput ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, dynNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( dynNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "simpleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // //- Register your node here, so Maya can use it and recognize it //- while reading/saving a file which has instance of this node type. status = plugin.registerNode( "simpleNode", simpleNode::id, simpleNode::creator, simpleNode::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // //- Unregister your node here, so Maya stops using it. status = plugin.deregisterNode( simpleNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Exercise - C++/simpleNode.cpp ================================================ // // Copyright (C) // // File: simpleNode.cpp // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #include "simpleNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x00001 is a temporary ID for reserved for development. Never use that ID in a //- production environment. /*static*/ MTypeId simpleNode::id( 0x00001 ); //- Instantiate the static attributes of your node class. /*static*/ MObject simpleNode::input; /*static*/ MObject simpleNode::output; /*static*/ MObject simpleNode::descString; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus simpleNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute definition not saved into Maya file. output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 ); //- Attribute will not be written to files when this type of node is stored nAttr.setStorable(false); //- Initialize a string output attribute using the MFnTypedAttribute //- class.In order to specify the attribute default value, you will need to //- use the MFnStringData class, before creating the attribute itself. //- TODO: create a MFnTypedAttribute instance //... //- TODO: Use MFnStringData to create default value for this typed attribute //... //... //- TODO: create a string attribute using the above MFnTypedAttribute instance //- and use the above MObject as a default value for your string attribute //... //- Now add the attribute to your node definition using the addAttribute() //- method. addAttribute( input ); addAttribute( output ); //- TODO: Add the string attribute to the node type definition //... //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. attributeAffects( input, output ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus simpleNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( input, &returnStatus ); //- Read the input value from the handle. float result = inputData.asFloat(); //- Get a handle to the output attribute. This is similar to the //- "inputValue" call above except that no dependency graph //- computation will be done as a result of this call. //- Get a handle on the aOutput attribute MDataHandle outputHandle = data.outputValue( simpleNode::output ); //- Set the new output value to the handle. outputHandle.set( result * 2 ); //- Mark the destination plug as being clean. This will prevent the //- dependency graph from repeating this calculation until an input //- attribute of this node which affects this output attribute changes. //- Tell Maya the plug is now clean data.setClean(plug); //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Exercise - C++/simpleNode.h ================================================ // // Copyright (C) // // File: simpleNode.h // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class simpleNode : public MPxNode { public: simpleNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~simpleNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new simpleNode(); } //- Declare the static initialize() method. static MStatus initialize(); public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // input attribute static MObject output; // output attribute static MObject descString; // Description string attribute describing the function of this node //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Exercise - C++/simpleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleNode", "simpleNode.vcxproj", "{439648C5-792B-4918-AC04-5B034F382742}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.ActiveCfg = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.Build.0 = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.ActiveCfg = Release|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Exercise - C++/simpleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {439648C5-792B-4918-AC04-5B034F382742} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ .mll /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\My Documents\maya\2009\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Exercise - py/simpleNode.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx #- Assing a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- 0x80001 is a temporary ID for reserved for development. Never use that ID in a #- production environement. kPluginNodeTypeName = "simpleNode" simpleNodeId = OpenMaya.MTypeId(0x80001) # Node definition class simpleNode(OpenMayaMPx.MPxNode): # Node attributes input = OpenMaya.MObject() output = OpenMaya.MObject() #- TODO: Declare here the string attribute #- TODO: ... def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self,plug,dataBlock): if ( plug == simpleNode.output ): #- Get a handle to the input attribute that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = dataBlock.inputValue( simpleNode.input ) #- Read the input value from the handle. result = inputData.asFloat() #- Get a handle to the output attribute. This is similar to the #- "inputValue" call above except that no dependency graph #- computation will be done as a result of this call. #- Get a handle on the aOutput attribute outputHandle = dataBlock.outputValue( simpleNode.output ) #- Set the new output value to the handle. outputHandle.setFloat( result * 2 ); #- Mark the destination plug as being clean. This will prevent the #- dependency graph from repeating this calculation until an input #- attribute of this node which affects this output attribute changes. #- Tell Maya the plug is now clean dataBlock.setClean( plug ) #- Tell Maya that we do not know how to handle this plug, but let give a chance #- to our parent class to evaluate it. return OpenMaya.kUnknownParameter # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( simpleNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- def nodeInitializer(): #- Initialize a float input attribute using the MFnNumericAttribute #- class. Make that attribute definition saved into Maya file (setStorable), #- and selectable in the channel box (setKeyable). #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() simpleNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(1) #- Attribute is keyable and will show up in the channel box nAttr.setKeyable(1) #- Initialize a float output attribute using the MFnNumericAttribute #- class. Make that attribute definition not saved into Maya file. simpleNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will not be written to files when this type of node is stored nAttr.setStorable(0) #- Initialize a string output attribute using the MFnTypedAttribute #- class.In order to specify the attribute default value, you will need to #- use the MFnStringData class, before creating the attribute itself. #- TODO: create a MFnTypedAttribute instance #... #- TODO: Use MFnStringData to create default value for this typed attribute #... #... #- TODO: create a string attribute using the above MFnTypedAttribute instance #- and use the above object as a default value for your string attribute #... #- Now add the attribute to your node definition using the addAttribute() #- method. #- Add the attributes we have created to the node simpleNode.addAttribute( simpleNode.input ); simpleNode.addAttribute( simpleNode.output ); #- TODO: Add the string attribute to the node type definition #... #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimatelly in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. simpleNode.attributeAffects( simpleNode.input, simpleNode.output ); # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, simpleNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( simpleNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "simpleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // //- Register your node here, so Maya can use it and recognize it //- while reading/saving a file which has instance of this node type. status = plugin.registerNode( "simpleNode", simpleNode::id, simpleNode::creator, simpleNode::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // //- Unregister your node here, so Maya stops using it. status = plugin.deregisterNode( simpleNode::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Solution - C++/simpleNode.cpp ================================================ // // Copyright (C) // // File: simpleNode.cpp // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #include "simpleNode.h" #include //- Assigning a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x00001 is a temporary ID for reserved for development. Never use that ID in a //- production environment. /*static*/ MTypeId simpleNode::id( 0x00001 ); //- Instantiate the static attributes of your node class. /*static*/ MObject simpleNode::input; /*static*/ MObject simpleNode::output; /*static*/ MObject simpleNode::descString; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- MStatus simpleNode::initialize() { //- Initialize a float input attribute using the MFnNumericAttribute //- class. Make that attribute definition saved into Maya file (setStorable), //- and selectable in the channel box (setKeyable). //- Create a generic attribute using MFnNumericAttribute MFnNumericAttribute nAttr; input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 ); //- Attribute will be written to files when this type of node is stored nAttr.setStorable(true); //- Attribute is keyable and will show up in the channel box nAttr.setKeyable(true); //- Initialize a float output attribute using the MFnNumericAttribute //- class. Make that attribute definition not saved into Maya file. output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 ); //- Attribute will not be written to files when this type of node is stored nAttr.setStorable(false); //- Initialize a string output attribute using the MFnTypedAttribute //- class.In order to specify the attribute default value, you will need to //- use the MFnStringData class, before creating the attribute itself. //- Create a string attribute using MFnTypedAttribute MFnTypedAttribute typedAttr; //- Use MFnStringData to implement default value of this attribute MFnStringData fnStringData; MString defaultString("description string for current node"); MObject defaultStringObj = fnStringData.create(defaultString); descString = typedAttr.create("descString", "dStr", MFnData::kString,defaultStringObj); //- Now add the attribute to your node definition using the addAttribute() //- method. //- Add the attributes we have created to the node addAttribute( input ); addAttribute( output ); addAttribute(descString); //- Finally tell Maya how the information should flow through your node. //- This will also tell Maya how the dirty flag is propagated in your node //- and ultimately in the Maya DG. To do this, use the attributeAffects() //- method to link your node' attributes together. //- Set up a dependency between the input and the output. This will cause //- the output to be marked dirty when the input changes. The output will //- then be recomputed the next time the value of the output is requested. attributeAffects( input, output ); //- Return success to Maya return MS::kSuccess; } //- This method computes the value of the given output plug based //- on the values of the input attributes. //- Arguments: //- plug - the plug to compute //- data - object that provides access to the attributes for this node MStatus simpleNode::compute( const MPlug& plug, MDataBlock& data ) { MStatus returnStatus; //- Check which output attribute we have been asked to compute. If this //- node doesn't know how to compute it, you must return MS::kUnknownParameter. if( plug == output ) { //- Get a handle to the input attribute that we will need for the //- computation. If the value is being supplied via a connection //- in the dependency graph, then this call will cause all upstream //- connections to be evaluated so that the correct value is supplied. MDataHandle inputData = data.inputValue( input, &returnStatus ); //- Read the input value from the handle. float result = inputData.asFloat(); //- Get a handle to the output attribute. This is similar to the //- "inputValue" call above except that no dependency graph //- computation will be done as a result of this call. //- Get a handle on the aOutput attribute MDataHandle outputHandle = data.outputValue( simpleNode::output ); //- Set the new output value to the handle. outputHandle.set( result * 2 ); //- Mark the destination plug as being clean. This will prevent the //- dependency graph from repeating this calculation until an input //- attribute of this node which affects this output attribute changes. //- Tell Maya the plug is now clean data.setClean(plug); //- Return success to Maya return MS::kSuccess; } //- Tell Maya that we do not know how to handle this plug, but let give a chance //- to our parent class to evaluate it. return MS::kUnknownParameter; } ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Solution - C++/simpleNode.h ================================================ // // Copyright (C) // // File: simpleNode.h // // Dependency Graph Node: simpleNode // // Author: Maya Plug-in Wizard 2.0 // #pragma once //- Include Maya necessary headers for our class #include #include #include #include #include #include #include #include //- Derive a new class from the default Maya node proxy class. class simpleNode : public MPxNode { public: simpleNode() { //- Never do anything here which would affect Maya. //- Instead implement the virtual postConstructor() method. } virtual ~simpleNode() {} //- Declare the virtual compute() method. virtual MStatus compute( const MPlug& plug, MDataBlock& data ); //- Declare/implement the static creator method. //- This method exists to give Maya a way to create new objects //- of this type. static void* creator() { return new simpleNode(); } //- Declare the static initialize() method. static MStatus initialize(); public: // There needs to be a MObject handle declared for each attribute that // the node will have. These handles are needed for getting and setting // the values later. // static MObject input; // input attribute static MObject output; // output attribute static MObject descString; // Description string attribute describing the function of this node //- This is a unique node ID for your new node class. It is declared //- static because it is common to all instance of that class. //- //- The typeid is a unique 32bit identifier that describes this node. //- It is used to save and retrieve nodes of this type from the binary //- file format. If it is not unique, it will cause file IO problems. static MTypeId id; }; ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Solution - C++/simpleNode.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleNode", "simpleNode.vcxproj", "{439648C5-792B-4918-AC04-5B034F382742}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.ActiveCfg = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Debug|x64.Build.0 = Debug|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.ActiveCfg = Release|x64 {439648C5-792B-4918-AC04-5B034F382742}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Solution - C++/simpleNode.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {439648C5-792B-4918-AC04-5B034F382742} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ .mll /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\My Documents\maya\2009\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/simpleNode.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\simpleNode.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/simpleNode.pdb Debug/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/simpleNode.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\simpleNode.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/simpleNode.pdb Release/simpleNode.lib ================================================ FILE: 04_NodeAttributes/simpleNode - with Typed Attr/Solution - py/simpleNode.py ================================================ # # Copyright (C) # # File: simpleNode.cpp # # Dependency Graph Node: simpleNode # # Author: Maya Plug-in Wizard 2.0 # import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx #- Assing a unique node ID to your new node class. #- Ask ADN or Autodesk product support to reserve IDs for your company. You can #- reserve ID by block of 64, 128, 256, or 512 consecutive ID. #- #- 0x80001 is a temporary ID for reserved for development. Never use that ID in a #- production environement. kPluginNodeTypeName = "simpleNode" simpleNodeId = OpenMaya.MTypeId(0x80001) # Node definition class simpleNode(OpenMayaMPx.MPxNode): # Node attributes input = OpenMaya.MObject() output = OpenMaya.MObject() descString = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self,plug,dataBlock): if ( plug == simpleNode.output ): #- Get a handle to the input attribute that we will need for the #- computation. If the value is being supplied via a connection #- in the dependency graph, then this call will cause all upstream #- connections to be evaluated so that the correct value is supplied. inputData = dataBlock.inputValue( simpleNode.input ) #- Read the input value from the handle. result = inputData.asFloat() #- Get a handle to the output attribute. This is similar to the #- "inputValue" call above except that no dependency graph #- computation will be done as a result of this call. #- Get a handle on the aOutput attribute outputHandle = dataBlock.outputValue( simpleNode.output ) #- Set the new output value to the handle. outputHandle.setFloat( result * 2 ); #- Mark the destination plug as being clean. This will prevent the #- dependency graph from repeating this calculation until an input #- attribute of this node which affects this output attribute changes. #- Tell Maya the plug is now clean dataBlock.setClean( plug ) #- Tell Maya that we do not know how to handle this plug, but let give a chance #- to our parent class to evaluate it. return OpenMaya.kUnknownParameter # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( simpleNode() ) #- The initialize method is called to create and initialize all of the #- attributes and attribute dependencies for this node type. This is #- only called once when the node type is registered with Maya. #- def nodeInitializer(): #- Initialize a float input attribute using the MFnNumericAttribute #- class. Make that attribute definition saved into Maya file (setStorable), #- and selectable in the channel box (setKeyable). #- Create a generic attribute using MFnNumericAttribute nAttr = OpenMaya.MFnNumericAttribute() simpleNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will be written to files when this type of node is stored nAttr.setStorable(1) #- Attribute is keyable and will show up in the channel box nAttr.setKeyable(1) #- Initialize a float output attribute using the MFnNumericAttribute #- class. Make that attribute definition not saved into Maya file. simpleNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) #- Attribute will not be written to files when this type of node is stored nAttr.setStorable(0) #- Initialize a string output attribute using the MFnTypedAttribute #- class.In order to specify the attribute default value, you will need to #- use the MFnStringData class, before creating the attribute itself. #- Create a MFnTypedAttribute instance typedAttr = OpenMaya.MFnTypedAttribute() #- Use MFnStringData to create default value of this attribute fnStringData = OpenMaya.MFnStringData() defaultStringObj = fnStringData.create("description string for current node") simpleNode.descString = typedAttr.create("descString", "dStr", OpenMaya.MFnData.kString,defaultStringObj) #- Now add the attribute to your node definition using the addAttribute() #- method. #- Add the attributes we have created to the node simpleNode.addAttribute( simpleNode.input ); simpleNode.addAttribute( simpleNode.output ); #- Add the string attribute to the node type definition simpleNode.addAttribute(simpleNode.descString); #- Finally tell Maya how the information should flow through your node. #- This will also tell Maya how the dirty flag is propagated in your node #- and ultimatelly in the Maya DG. To do this, use the attributeAffects() #- method to link your node' attributes together. #- Set up a dependency between the input and the output. This will cause #- the output to be marked dirty when the input changes. The output will #- then be recomputed the next time the value of the output is requested. simpleNode.attributeAffects( simpleNode.input, simpleNode.output ); # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, simpleNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( simpleNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 05_DependencyGraph/retrieveWeight/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include "retrieveWeightCmd.h" #include MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); status = plugin.registerCommand( "retrieveWeight", retrieveWeightCmd::creator); if (!status) { status.perror("registerCommand"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterCommand( "retrieveWeight" ); if (!status) { status.perror("deregisterCommand"); return status; } return status; } ================================================ FILE: 05_DependencyGraph/retrieveWeight/Exercise - C++/retrieveWeight.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "retrieveWeight", "retrieveWeight.vcxproj", "{F784655E-05CD-477E-8AFD-79B576ED550B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {F784655E-05CD-477E-8AFD-79B576ED550B}.Debug|x64.ActiveCfg = Debug|x64 {F784655E-05CD-477E-8AFD-79B576ED550B}.Debug|x64.Build.0 = Debug|x64 {F784655E-05CD-477E-8AFD-79B576ED550B}.Release|x64.ActiveCfg = Release|x64 {F784655E-05CD-477E-8AFD-79B576ED550B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 05_DependencyGraph/retrieveWeight/Exercise - C++/retrieveWeight.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {F784655E-05CD-477E-8AFD-79B576ED550B} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\retrieveWeight.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\retrieveWeight.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 05_DependencyGraph/retrieveWeight/Exercise - C++/retrieveWeightCmd.cpp ================================================ // // Copyright (C) // // File: retrieveWeightCmd.cpp // // MEL Command: dagScan // // Author: Maya Plug-in Wizard 2.0 // #include "retrieveWeightCmd.h" #include #include #include #include MStatus retrieveWeightCmd::doIt(const MArgList&) { MStatus stat = MS::kSuccess; MObject blendShapeNode; MSelectionList selList; //- Get the selected blendShape node stat = MGlobal::getActiveSelectionList(selList); if(selList.length()!=0) { selList.getDependNode(0,blendShapeNode); MFnDependencyNode fnDep(blendShapeNode,&stat); //- TODO: Verify that the node is a Blend Shape if ( //... ) { MString attrName("weight"); MPlug weightArrayPlug = fnDep.findPlug(attrName,&stat); //- TODO: Find out if this plug is a multi plug if( //... ) { //- TODO: Get the name of the plug and print it MString plugName = //... cout<<"Plug "< class retrieveWeightCmd : public MPxCommand { public: retrieveWeightCmd() {} virtual ~retrieveWeightCmd() {} virtual MStatus doIt( const MArgList& ); static void * creator() { return new retrieveWeightCmd(); } }; ================================================ FILE: 05_DependencyGraph/retrieveWeight/Exercise - py/retrieveWeight.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys kPluginNodeTypeName = "retrieveWeight" # Node definition class retrieveWeight(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self, args): self.blendShapeNode = OpenMaya.MObject() selList = OpenMaya.MSelectionList() #- Get the selected blendShape node OpenMaya.MGlobal.getActiveSelectionList(selList) if selList.length()!=0: selList.getDependNode(0,self.blendShapeNode) fnDep = OpenMaya.MFnDependencyNode(self.blendShapeNode) #- TODO: Verify that the node is a Blend Shape if #... weightArrayPlug = fnDep.findPlug("weight") #- TODO: Find out if this plug is a multi plug if #... #- TODO: Get the name of the plug and print it plugName = #... print "Plug %s is an array plug." % plugName #- Find how many elements are in this multi plug numberOfElem = weightArrayPlug.numElements() print "This plug has %s elements." % numberOfElem #- Traverse all the element plugs for j in range(numberOfElem): #- You can also use like the following line, [], because bracket operator uses physical indexes #- MPlug elementPlug = weightArrayPlug [i] elementPlug = weightArrayPlug.elementByPhysicalIndex(j) #- Print out the element plug's physical index and logical index print "Physical index: %s; Logical index: %s" % (j, elementPlug.logicalIndex()) #- TODO: Get the value in every element plug valueElem = #... print "The value in this element plug is %f" % valueElem # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( retrieveWeight() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginNodeTypeName, nodeCreator) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginNodeTypeName ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 05_DependencyGraph/retrieveWeight/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include "retrieveWeightCmd.h" #include MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); status = plugin.registerCommand( "retrieveWeight", retrieveWeightCmd::creator); if (!status) { status.perror("registerCommand"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterCommand( "retrieveWeight" ); if (!status) { status.perror("deregisterCommand"); return status; } return status; } ================================================ FILE: 05_DependencyGraph/retrieveWeight/Solution - C++/retrieveWeight.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "retrieveWeight", "retrieveWeight.vcxproj", "{F784655E-05CD-477E-8AFD-79B576ED550B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {F784655E-05CD-477E-8AFD-79B576ED550B}.Debug|x64.ActiveCfg = Debug|x64 {F784655E-05CD-477E-8AFD-79B576ED550B}.Debug|x64.Build.0 = Debug|x64 {F784655E-05CD-477E-8AFD-79B576ED550B}.Release|x64.ActiveCfg = Release|x64 {F784655E-05CD-477E-8AFD-79B576ED550B}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 05_DependencyGraph/retrieveWeight/Solution - C++/retrieveWeight.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {F784655E-05CD-477E-8AFD-79B576ED550B} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\retrieveWeight.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\retrieveWeight.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 05_DependencyGraph/retrieveWeight/Solution - C++/retrieveWeightCmd.cpp ================================================ // // Copyright (C) // // File: retrieveWeightCmd.cpp // // MEL Command: retrieveWeight // // Author: Maya Plug-in Wizard 2.0 // #include "retrieveWeightCmd.h" #include #include #include #include MStatus retrieveWeightCmd::doIt(const MArgList&) { MStatus stat = MS::kSuccess; MObject blendShapeNode; MSelectionList selList; //- Get the selected blendShape node stat = MGlobal::getActiveSelectionList(selList); if(selList.length()!=0) { selList.getDependNode(0,blendShapeNode); MFnDependencyNode fnDep(blendShapeNode,&stat); //- Verify that the node is a Blend Shape if (blendShapeNode.apiType() == MFn::kBlendShape ) { MString attrName("weight"); MPlug weightArrayPlug = fnDep.findPlug(attrName,&stat); //- Find out if this plug is a multi plug if(weightArrayPlug.isArray(&stat)) { MString plugName = weightArrayPlug.name(&stat); cout<<"///////////////////////////////////////////////"< class retrieveWeightCmd : public MPxCommand { public: retrieveWeightCmd() {} virtual ~retrieveWeightCmd() {} virtual MStatus doIt( const MArgList& ); static void * creator() { return new retrieveWeightCmd(); } }; ================================================ FILE: 05_DependencyGraph/retrieveWeight/Solution - py/retrieveWeight.py ================================================ # # Copyright (C) # # File: retrieveWeight.py # # Dependency Graph Node: # # Author: Maya Plug-in Wizard 2.0 import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys kPluginNodeTypeName = "retrieveWeight" # Node definition class retrieveWeight(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self, args): self.blendShapeNode = OpenMaya.MObject() selList = OpenMaya.MSelectionList() #- Get the selected blendShape node OpenMaya.MGlobal.getActiveSelectionList(selList) if selList.length()!=0: selList.getDependNode(0,self.blendShapeNode) fnDep = OpenMaya.MFnDependencyNode(self.blendShapeNode) #- Verify that the node is a Blend Shape if self.blendShapeNode.apiType() == OpenMaya.MFn.kBlendShape: weightArrayPlug = fnDep.findPlug("weight") #- Find out if this plug is a multi plug if weightArrayPlug.isArray(): plugName = weightArrayPlug.name() print "Plug %s is an array plug." % plugName #- Find how many elements are in this multi plug numberOfElem = weightArrayPlug.numElements() print "This plug has %s elements." % numberOfElem #- Traverse all the element plugs for j in range(numberOfElem): #- You can also use like the following line, [], because bracket operator uses physical indexes #- MPlug elementPlug = weightArrayPlug [i] elementPlug = weightArrayPlug.elementByPhysicalIndex(j) #- Print out the element plug's physical index and logical index print "Physical index: %s; Logical index: %s" % (j, elementPlug.logicalIndex()) #- Print out the value in every element plug valueElem = elementPlug.asDouble() print "The value in this element plug is %f" % valueElem # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( retrieveWeight() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginNodeTypeName, nodeCreator) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginNodeTypeName ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 05_DependencyGraph/retrieveWeight/blendShape.ma ================================================ [File too large to display: 14.4 MB] ================================================ FILE: 06_MiscTools/sceneMsg/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "sceneMsgCmd.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand("sceneMsgCmd",sceneMsgCmd::creator); return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand("sceneMsgCmd"); //- TODO: You are responsible to remove all the callbacks you have registered in your plug-in code MCallbackIdArray tempIds = sceneMsgCmd::IDs; if (tempIds.length() != 0) status = //... return status; } ================================================ FILE: 06_MiscTools/sceneMsg/Exercise - C++/sceneMsgCmd.cpp ================================================ // // Copyright (C) // // File: // // Author: Maya Plug-in Wizard 2.0 // #include "sceneMsgCmd.h" /*static*/ MCallbackIdArray sceneMsgCmd::IDs; sceneMsgCmd::sceneMsgCmd() { //- Clean up callback id array IDs.clear(); } MStatus sceneMsgCmd::doIt(const MArgList & args) { return redoIt(); } MStatus sceneMsgCmd::redoIt() { MStatus stat = MS::kSuccess; //- TODO: Register callback for MSceneMessage::kBeforeOpen message MCallbackId openCallbackId = //... IDs.append(openCallbackId); //- TODO: Register callback for MSceneMessage::kAfterNew message MCallbackId newCallbackId = //... IDs.append(newCallbackId); //- TODO: Register callback for MSceneMessage::kBeforeSave message MCallbackId saveCheckCallbackId = //... IDs.append(saveCheckCallbackId); return stat; } MStatus sceneMsgCmd::undoIt() { MStatus stat = MS::kSuccess; // TODO: Remove all callbacks if(IDs.length()!= 0 ) stat = //... return stat; } //- Message callbacks void openCallback(void* clienData) { cout<<"The callback registered for MSceneMessage::kBeforeOpen is executed."< #include #include class sceneMsgCmd : public MPxCommand { public: sceneMsgCmd() ; virtual ~sceneMsgCmd() {} virtual MStatus doIt(const MArgList & args); virtual MStatus undoIt(); virtual MStatus redoIt(); virtual bool isUndoable() const { return (true) ; } static void * creator() { return new sceneMsgCmd(); } public: static MCallbackIdArray IDs; //- Member variable to record all callback Ids }; //- Message callbacks void openCallback(void* clienData); void newCallback(void* clienData); void saveCheckCallback(bool *retCode, void* clienData); ================================================ FILE: 06_MiscTools/sceneMsg/Exercise - C++/sceneMsgCmd.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sceneMsgCmd", "sceneMsgCmd.vcxproj", "{6598FA63-51E4-4A33-894E-DF4E5EF90A0F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Debug|x64.ActiveCfg = Debug|x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Debug|x64.Build.0 = Debug|x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Release|x64.ActiveCfg = Release|x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 06_MiscTools/sceneMsg/Exercise - C++/sceneMsgCmd.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/sceneMsgCmd.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/sceneMsgCmd.pdb Debug/sceneMsgCmd.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/sceneMsgCmd.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/sceneMsgCmd.pdb Debug/sceneMsgCmd.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/sceneMsgCmd.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/sceneMsgCmd.pdb Release/sceneMsgCmd.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/sceneMsgCmd.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/sceneMsgCmd.pdb Release/sceneMsgCmd.lib ================================================ FILE: 06_MiscTools/sceneMsg/Exercise - py/sceneMsgCmd.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys kPluginNodeTypeName = "sceneMsgCmd" IDs = OpenMaya.MCallbackIdArray() def removeCallback(ID): for i in range(ID.length()): try: #- TODO: You are responsible to remove all the callbacks you have registered in your plug-in code #... except: sys.stderr.write( "Failed to remove callback\n" ) raise def sceneMsgCmd(): #- Clean up callback id array IDs.clear() #- Message callbacks def openCallback(clienData): print "The callback registered for MSceneMessage::kBeforeOpen is executed." def newCallback(clienData): print "The callback registered for MSceneMessage::kAfterNew is executed." def saveCheckCallback(retCode, clienData): print "The callback registered for MSceneMessage::kBeforeSaveCheck is executed." #- Abort the operation by setting retCode to point to false retCode = False print "Abort current operations.../n" class sceneMsgCmd(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self,argList): return self.redoIt() def redoIt(self): #- TODO: Register callback for MSceneMessage::kBeforeOpen message openCallbackId = #... IDs.append(openCallbackId) #- TODO: Register callback for MSceneMessage::kAfterNew message newCallbackId = #... IDs.append(newCallbackId) #- TODO: Register callback for MSceneMessage::kBeforeSave message saveCheckCallbackId = #... IDs.append(saveCheckCallbackId) def undoIt(self): if IDs.length()!= 0: removeCallback(IDs) # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( sceneMsgCmd() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginNodeTypeName, nodeCreator) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): # Remove the callback if IDs.length()!= 0: removeCallback( IDs ) mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginNodeTypeName ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 06_MiscTools/sceneMsg/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "sceneMsgCmd.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand("sceneMsgCmd",sceneMsgCmd::creator); return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand("sceneMsgCmd"); //- You are responsible to remove all the callbacks you have registered in your plug-in code MCallbackIdArray tempIds = sceneMsgCmd::IDs; if (tempIds.length() != 0) status = MSceneMessage::removeCallbacks(sceneMsgCmd::IDs); return status; } ================================================ FILE: 06_MiscTools/sceneMsg/Solution - C++/sceneMsgCmd.cpp ================================================ // // Copyright (C) // // File: sceneMsgCmd.cpp // // Author: Maya Plug-in Wizard 2.0 // #include "sceneMsgCmd.h" /*static*/ MCallbackIdArray sceneMsgCmd::IDs; sceneMsgCmd::sceneMsgCmd() { //- Clean up callback id array IDs.clear(); } MStatus sceneMsgCmd::doIt(const MArgList & args) { return redoIt(); } MStatus sceneMsgCmd::redoIt() { MStatus stat = MS::kSuccess; //- Register callback for MSceneMessage::kBeforeOpen message MCallbackId openCallbackId = MSceneMessage::addCallback(MSceneMessage::kBeforeOpen,(MMessage::MBasicFunction)openCallback, NULL,&stat); IDs.append(openCallbackId); //- Register callback for MSceneMessage::kAfterNew message MCallbackId newCallbackId = MSceneMessage::addCallback(MSceneMessage::kAfterNew,(MMessage::MBasicFunction)newCallback, NULL,&stat); IDs.append(newCallbackId); //- Register callback for MSceneMessage::kBeforeSave message MCallbackId saveCheckCallbackId = MSceneMessage::addCheckCallback(MSceneMessage::kBeforeSaveCheck,(MMessage::MCheckFunction)saveCheckCallback, NULL,&stat); IDs.append(saveCheckCallbackId); return stat; } MStatus sceneMsgCmd::undoIt() { MStatus stat = MS::kSuccess; if(IDs.length()!= 0 ) stat = MSceneMessage::removeCallbacks(IDs); return stat; } //- Message callbacks void openCallback(void* clienData) { cout<<"The callback registered for MSceneMessage::kBeforeOpen is executed."< #include #include class sceneMsgCmd : public MPxCommand { public: sceneMsgCmd() ; virtual ~sceneMsgCmd() {} virtual MStatus doIt(const MArgList & args); virtual MStatus undoIt(); virtual MStatus redoIt(); virtual bool isUndoable() const { return (true) ; } static void * creator() { return new sceneMsgCmd(); } public: static MCallbackIdArray IDs; //- Member variable to record all callback Ids }; //- Message callbacks void openCallback(void* clienData); void newCallback(void* clienData); void saveCheckCallback(bool *retCode, void* clienData); ================================================ FILE: 06_MiscTools/sceneMsg/Solution - C++/sceneMsgCmd.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sceneMsgCmd", "sceneMsgCmd.vcxproj", "{6598FA63-51E4-4A33-894E-DF4E5EF90A0F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Debug|x64.ActiveCfg = Debug|x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Debug|x64.Build.0 = Debug|x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Release|x64.ActiveCfg = Release|x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 06_MiscTools/sceneMsg/Solution - C++/sceneMsgCmd.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {6598FA63-51E4-4A33-894E-DF4E5EF90A0F} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/sceneMsgCmd.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/sceneMsgCmd.pdb Debug/sceneMsgCmd.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/sceneMsgCmd.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/sceneMsgCmd.pdb Debug/sceneMsgCmd.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/sceneMsgCmd.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/sceneMsgCmd.pdb Release/sceneMsgCmd.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/sceneMsgCmd.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\sceneMsgCmd.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/sceneMsgCmd.pdb Release/sceneMsgCmd.lib ================================================ FILE: 06_MiscTools/sceneMsg/Solution - py/sceneMsgCmd.py ================================================ # # Copyright (C) # # File: sceneMsgCmd.py # # Dependency Graph Node: # # Author: Maya Plug-in Wizard 2.0 import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys kPluginNodeTypeName = "sceneMsgCmd" IDs = OpenMaya.MCallbackIdArray() def removeCallback(ID): for i in range(ID.length()): try: OpenMaya.MMessage.removeCallback( ID[i] ) except: sys.stderr.write( "Failed to remove callback\n" ) raise def sceneMsgCmd(): #- Clean up callback id array IDs.clear() #- Message callbacks def openCallback(clienData): print "The callback registered for MSceneMessage::kBeforeOpen is executed." def newCallback(clienData): print "The callback registered for MSceneMessage::kAfterNew is executed." def saveCheckCallback(retCode, clienData): print "The callback registered for MSceneMessage::kBeforeSaveCheck is executed." #- Abort the operation by setting retCode to point to false retCode = True # OpenMaya.MScriptUtil.setBool(retCode, False) print "Abort current operations.../n" class sceneMsgCmd(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self,argList): return self.redoIt() def redoIt(self): #- Register callback for MSceneMessage::kBeforeOpen message openCallbackId = OpenMaya.MSceneMessage.addCallback(OpenMaya.MSceneMessage.kBeforeOpen,openCallback, self) IDs.append(openCallbackId) #- Register callback for MSceneMessage::kAfterNew message newCallbackId = OpenMaya.MSceneMessage.addCallback(OpenMaya.MSceneMessage.kAfterNew,newCallback, self) IDs.append(newCallbackId) #- Register callback for MSceneMessage::kBeforeSave message saveCheckCallbackId = OpenMaya.MSceneMessage.addCheckCallback(OpenMaya.MSceneMessage.kBeforeSaveCheck,saveCheckCallback, self) IDs.append(saveCheckCallbackId) def undoIt(self): if IDs.length()!= 0: removeCallback(IDs) # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( sceneMsgCmd() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginNodeTypeName, nodeCreator) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): # Remove the callback if IDs.length()!= 0: removeCallback( IDs ) mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginNodeTypeName ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/AEtransCircleTemplate.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ //AEtransCircleTemplate.mel global proc AEtransCircleTemplate( string $nodeName ) { // Put our attributes into a scrolled layout field editorTemplate -beginScrollLayout; // The all go into the collapsable "Parameters" section editorTemplate -beginLayout "Parameters" -collapse false; // Add a "special" control for the scale attribute that allow // "quick set" options for scales of 5, 10, and 15. editorTemplate -callCustom "transCircleScaleNew" "transCircleScaleReplace" "scale"; // Add the default controls for the scale and frames attributes editorTemplate -addControl "scale"; editorTemplate -addControl "frames"; editorTemplate -endLayout; // Create an "Extras" section and also add controls for any // attributes we have not explicitly mentioned. editorTemplate -addExtraControls; editorTemplate -endScrollLayout; // Tell the attribute editor not to display the attributes we // don't care about. editorTemplate -suppress "inputTranslate"; editorTemplate -suppress "input"; editorTemplate -suppress "caching"; editorTemplate -suppress "nodeState"; } global proc transCircleScaleNew( string $attrName ) { // Maya the "quick set" control for the scale attribute radioButtonGrp -label "Quick Scale" -numberOfRadioButtons 3 -label1 "Five" -data1 5 -label2 "Ten" -data2 10 -label3 "Fifteen" -data3 15 scaleGrp; connectControl scaleGrp $attrName; } global proc transCircleScaleReplace( string $attrName ) { // Install the connection between the radioButtonGrp and the // actual scale attribute connectControl scaleGrp $attrName; } ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "setUpTransCircleCmd.h" #include "transCircleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand("setUpTransCircle",setUpTransCircle::creator); status = plugin.registerNode( "transCircle", transCircle::id,transCircle::creator, transCircle::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand("setUpTransCircle"); status = plugin.deregisterNode( transCircle::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/setUpTransCircle.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setUpTransCircle", "setUpTransCircle.vcxproj", "{01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Debug|x64.ActiveCfg = Debug|x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Debug|x64.Build.0 = Debug|x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Release|x64.ActiveCfg = Release|x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/setUpTransCircle.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\setUpTransCircle.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\setUpTransCircle.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/setUpTransCircleCmd.cpp ================================================ // // Copyright (C) // // File: setUpTransCircleCmd.cpp // // MEL Command: setUpTransCircle // #include "setUpTransCircleCmd.h" #include "transCircleNode.h" #include #include #include #include #include #include #include #include #include #include #include //- Here is what you need to set up the transCircle node //- createNode transCircle -n circleNode1; //- sphere -n sphere1 -r 1; //- sphere -n sphere2 -r 2; //- connectAttr sphere2.translate circleNode1.inputTranslate; //- connectAttr circleNode1.outputTranslate sphere1.translate; //- connectAttr time1.outTime circleNode1.input; MStatus setUpTransCircle::doIt( const MArgList& argList) { MStatus stat = MS::kSuccess; //- Create a transCircle node and two Nurbs spheres MString tranCircleType("transCircle"); //- TODO: Create a transCircle node MObject transCircle = //... //- TODO: Rename the node to "circleNode1" //... //- TODO: Use MDGMOdifier to simulate executing the following commands //- command "sphere -n sphere1 -r 1;" and command "sphere -n sphere2 -r 2;" //- TIPS: you should create a MString object first //... //... //... //... //- TODO: Now force these operation to be executed by calling the DG modifier doIt() method. //... //- The following code is one sample code if you want to simulate "sphere -n sphere1 -r 1" manually from MDGModifier and MDagModifier /* MObject testNode = dgMod.createNode(MString("makeNurbSphere"),&stat); MFnDependencyNode nurbsSphereFn(testNode); MPlug radiusPlug = nurbsSphereFn.findPlug("radius"); radiusPlug.setFloat(1.0f); dgMod.doIt(); MDagModifier dagMod; MObject nurbsTransform = dagMod.createNode("nurbsSurface"); dagMod.doIt(); MPlug outputPlug = nurbsSphereFn.findPlug("outputSurface"); MFnDagNode transformFn(nurbsTransform); MFnDagNode nurbsFn(transformFn.child(0)); MPlug createPlug = nurbsFn.findPlug("create"); dagMod.connect(outputPlug, createPlug); dagMod.doIt(); */ MSelectionList selList; //- Find the Nurbs sphere nodes and transCircle node MGlobal::getSelectionListByName(MString("sphere1"),selList); MObject sphereDep; selList.getDependNode(0,sphereDep); selList.clear(); MGlobal::getSelectionListByName(MString("sphere2"),selList); MObject sphereTwoDep; selList.getDependNode(0,sphereTwoDep); selList.clear(); //- Connect attributes between Nurbs sphere and transCircle node MFnDependencyNode fnSphere(sphereDep,&stat); MFnDependencyNode fnSphereTwo(sphereTwoDep,&stat); MFnDependencyNode fnTransCircleNode(transCircle,&stat); MObject inputTransAttr = fnTransCircleNode.attribute(MString("inputTranslate"),&stat); MObject sphereTwoTranslateAttr = fnSphereTwo.attribute(MString("translate"),&stat); dgMod.connect(sphereTwoDep,sphereTwoTranslateAttr,transCircle,inputTransAttr); //- TODO: Connect the "outputTranslate" circle node attribute with the "translate" "sphere1" node attribute //... //... //... //- Connect time1 node with transCircle node MObject timeNode; MGlobal::getSelectionListByName(MString("time1"),selList); selList.getDependNode(0,timeNode); selList.clear(); MFnDependencyNode fnTimeNode(timeNode); MObject timeAttr = fnTimeNode.attribute(MString("outTime"),&stat); MObject inputAttr = fnTransCircleNode.attribute(MString("input"),&stat); dgMod.connect(timeNode,timeAttr,transCircle,inputAttr); //- Now force these operation to be executed by calling the DG modifier doIt() method. stat = dgMod.doIt(); return stat; } MStatus setUpTransCircle::undoIt() { return dgMod.undoIt(); } MStatus setUpTransCircle::redoIt() { return dgMod.doIt(); } ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/setUpTransCircleCmd.h ================================================ // // Copyright (C) // // File: setUpTransCircleCmd.h // // MEL Command: setUpTransCircle // // Author: Maya Plug-in Wizard 2.0 // #pragma once #include #include class MArgList; class setUpTransCircle : public MPxCommand { public: setUpTransCircle() {} virtual ~setUpTransCircle() {} virtual MStatus doIt( const MArgList& ); virtual MStatus undoIt(); virtual MStatus redoIt(); virtual bool isUndoable() const { return (true); } static void* creator() { return new setUpTransCircle(); } private: MDGModifier dgMod; }; ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/transCircleNode.cpp ================================================ // // Copyright (C) // // File: transCircleNode.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include #include #include #include #include #include #include #include #include "transCircleNode.h" MTypeId transCircle::id( 0x80013 ); MObject transCircle::input; MObject transCircle::frames; MObject transCircle::scale; MObject transCircle::inputTranslate; MObject transCircle::outputTranslate; MObject transCircle::inputTranslateX; MObject transCircle::inputTranslateY; MObject transCircle::inputTranslateZ; MObject transCircle::outputTranslateX; MObject transCircle::outputTranslateY; MObject transCircle::outputTranslateZ; MStatus transCircle::initialize() { MFnNumericAttribute nAttr; MStatus stat; input = nAttr.create( "input", "in", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateX = nAttr.create( "inputTranslateX", "itX", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateY = nAttr.create( "inputTranslateY", "itY", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslate = nAttr.create( "inputTranslate", "it", inputTranslateX, inputTranslateY, inputTranslateZ ); nAttr.setStorable(true); nAttr.setDefault(0.0,0.0,0.0); outputTranslateX = nAttr.create( "outputTranslateX", "otX", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslateY = nAttr.create( "outputTranslateY", "otY", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslateZ = nAttr.create( "outputTranslateZ", "otZ", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslate = nAttr.create( "outputTranslate", "ot", outputTranslateX, outputTranslateY, outputTranslateZ ); nAttr.setWritable(false); nAttr.setStorable(true); nAttr.setDefault(0.0,0.0,0.0); scale = nAttr.create( "scale", "sc", MFnNumericData::kDouble, 10.0 ); nAttr.setStorable(true); frames = nAttr.create( "frames", "fr", MFnNumericData::kDouble, 48.0 ); nAttr.setStorable(true); addAttribute( inputTranslate ); addAttribute( input ); addAttribute( scale ); addAttribute( frames ); addAttribute( outputTranslate ); attributeAffects( inputTranslateX, outputTranslateX ); attributeAffects( inputTranslateY, outputTranslateY ); attributeAffects( inputTranslateZ, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslateX ); attributeAffects( inputTranslate, outputTranslateY ); attributeAffects( inputTranslate, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslate ); attributeAffects( input, outputTranslateX ); attributeAffects( input, outputTranslateY ); attributeAffects( scale, outputTranslateX ); attributeAffects( scale, outputTranslateY ); attributeAffects( frames, outputTranslateX ); attributeAffects( frames, outputTranslateY ); return MS::kSuccess; } MStatus transCircle::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; bool k = ( plug == outputTranslateX ) | ( plug == outputTranslateY ) | ( plug == outputTranslateZ ) | ( plug == outputTranslate ); if (!k) return MS::kUnknownParameter; MDataHandle inputData = data.inputValue( input, &stat ); MDataHandle scaleData = data.inputValue( scale, &stat ); MDataHandle framesData = data.inputValue( frames, &stat ); MDataHandle transData = data.inputValue( inputTranslate, &stat ); double3& iTranslate = transData.asDouble3(); double currentFrame = inputData.asDouble(); double scaleFactor = scaleData.asDouble(); double framesPerCircle = framesData.asDouble(); double angle = 6.2831853 * ( currentFrame/framesPerCircle ); double3 oTranslate; oTranslate[0] = iTranslate[0] + (sin( angle ) * scaleFactor); oTranslate[1] = iTranslate[1] + 1.0; oTranslate[2] = iTranslate[2] + (cos( angle ) * scaleFactor); MDataHandle otHandle = data.outputValue( outputTranslate ); otHandle.set( oTranslate[0], oTranslate[1], oTranslate[2] ); data.setClean(plug); return MS::kSuccess; } ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - C++/transCircleNode.h ================================================ // // Copyright (C) // // File: transCircleNode.h // // Author: Maya Plug-in Wizard 2.0 // #pragma once #include class transCircle : public MPxNode { public: transCircle() {} virtual ~transCircle() {} virtual MStatus compute( const MPlug& plug, MDataBlock& data ); static MStatus initialize(); static void* creator() { return new transCircle(); } public: static MObject input; // The input value. static MObject inputTranslateX; // The translate X value. (input) static MObject inputTranslateY; // The translate Y value. (input) static MObject inputTranslateZ; // The translate Z value. (input) static MObject inputTranslate; static MObject outputTranslateX; // The translate X value. (output) static MObject outputTranslateY; // The translate Y value. (output) static MObject outputTranslateZ; // The translate Z value. (output) static MObject outputTranslate; static MObject frames; // Number of frames for one circle. static MObject scale; // Size of circle. static MTypeId id; }; ================================================ FILE: 06_MiscTools/setUpTransCircle/Exercise - py/setUpTransCircle.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network # For this exercise, search for the TODO keywords and follow the instructions in # comments. If you are unsure of what you need to do, feel free to ask the instructor # or look into the solution folder. # Each #... line is a line of code you need to write or complete. import sys, math import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "transCircle" kPluginCmdTypeName = "setUpTransCircle" kPluginNodeId = OpenMaya.MTypeId(0x80013) # Node definition class transCircle(OpenMayaMPx.MPxNode): # class variables # Node attributes #- Compound attributes in Maya are build from several individual attributes. In #- our example the translation vector is made of the x,y,z attributes, and the #- compound attribute itself. aInput = OpenMaya.MObject() aFrames = OpenMaya.MObject() aScale = OpenMaya.MObject() aInputTranslate = OpenMaya.MObject() aInputTranslateX = OpenMaya.MObject() aInputTranslateY = OpenMaya.MObject() aInputTranslateZ = OpenMaya.MObject() aOutputTranslate = OpenMaya.MObject() aOutputTranslateX = OpenMaya.MObject() aOutputTranslateY = OpenMaya.MObject() aOutputTranslateZ = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self, plug, data): if (plug != transCircle.aOutputTranslateX and plug != transCircle.aOutputTranslateY and plug != transCircle.aOutputTranslateZ and plug != transCircle.aOutputTranslate): return OpenMaya.kUnknownParameter inputData = data.inputValue( transCircle.aInput ) scaleData = data.inputValue( transCircle.aScale ) framesData = data.inputValue( transCircle.aFrames ) currentFrame = inputData.asDouble() scaleFactor = scaleData.asDouble() framesPerCircle = framesData.asDouble() #- Retrieve values on individual input translate attribute inputTranslateXHandle = data.inputValue(transCircle.aInputTranslateX) inputTranslateXData = inputTranslateXHandle.asDouble() inputTranslateYHandle = data.inputValue(transCircle.aInputTranslateY) inputTranslateYData = inputTranslateYHandle.asDouble() inputTranslateZHandle = data.inputValue(transCircle.aInputTranslateZ) inputTranslateZData = inputTranslateZHandle.asDouble() #- Calculate corresponding angle based on current frame angle = 6.2831853 * ( currentFrame/framesPerCircle ) #- The value of output translate is input translate value plus the value of circular movement outputTranslateXData = inputTranslateXData + (math.sin( angle ) * scaleFactor) outputTranslateYData = inputTranslateYData + 1.0 outputTranslateZData = inputTranslateZData + (math.cos( angle ) * scaleFactor) #- Get a handle on the output attributes and set the new value. outputTranslateXHandle = data.outputValue( transCircle.aOutputTranslateX ) outputTranslateXHandle.setDouble(outputTranslateXData) outputTranslateYHandle = data.outputValue( transCircle.aOutputTranslateY ) outputTranslateYHandle.setDouble(outputTranslateYData) outputTranslateZHandle = data.outputValue( transCircle.aOutputTranslateZ ) outputTranslateZHandle.setDouble(outputTranslateZData) #- Tell Maya the plug is now clean data.setClean(plug) def nodeInitializer(): nAttr = OpenMaya.MFnNumericAttribute() transCircle.aInput = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) transCircle.aInputTranslateX = nAttr.create( "inputTranslateX", "itX", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) transCircle.aInputTranslateY = nAttr.create( "inputTranslateY", "itY", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) transCircle.aInputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) #- Create compound input translate attributes and add individual input translate attributes comAttr = OpenMaya.MFnCompoundAttribute() transCircle.aInputTranslate = comAttr.create("inputTranslate","it") comAttr.addChild(transCircle.aInputTranslateX) comAttr.addChild(transCircle.aInputTranslateY) comAttr.addChild(transCircle.aInputTranslateZ) comAttr.setStorable(True) transCircle.aOutputTranslateX = nAttr.create( "outputTranslateX", "otX", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(False) nAttr.setStorable(True) transCircle.aOutputTranslateY = nAttr.create( "outputTranslateY", "otY", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(False) nAttr.setStorable(True) transCircle.aOutputTranslateZ = nAttr.create( "outputTranslateZ", "otZ", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(False) nAttr.setStorable(True) #- Create compound output translate attributes and add individual output translate attributes transCircle.aOutputTranslate = comAttr.create("outputTranslate","ot") comAttr.addChild(transCircle.aOutputTranslateX) comAttr.addChild(transCircle.aOutputTranslateY) comAttr.addChild(transCircle.aOutputTranslateZ) comAttr.setWritable(False) comAttr.setStorable(True) transCircle.aScale = nAttr.create( "scale", "sc", OpenMaya.MFnNumericData.kDouble, 10.0 ) nAttr.setStorable(True) transCircle.aFrames = nAttr.create( "frames", "fr", OpenMaya.MFnNumericData.kDouble, 48.0 ) nAttr.setStorable(True) transCircle.addAttribute( transCircle.aInputTranslate ) transCircle.addAttribute( transCircle.aInput ) transCircle.addAttribute( transCircle.aScale ) transCircle.addAttribute( transCircle.aFrames ) transCircle.addAttribute( transCircle.aOutputTranslate ) transCircle.attributeAffects( transCircle.aInputTranslateX, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aInputTranslateY, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aInputTranslateZ, transCircle.aOutputTranslateZ ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslateZ ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslate ) transCircle.attributeAffects( transCircle.aInput, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aInput, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aScale, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aScale, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aFrames, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aFrames, transCircle.aOutputTranslateY ) # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( transCircle() ) # Creators def cmdCreator(): return OpenMayaMPx.asMPxPtr(setUpTransCircle()) #- Here is what you need to set up the transCircle node #- createNode transCircle -n circleNode1 #- sphere -n sphere1 -r 1 #- sphere -n sphere2 -r 2 #- connectAttr sphere2.translate circleNode1.inputTranslate #- connectAttr circleNode1.outputTranslate sphere1.translate #- connectAttr time1.outTime circleNode1.input class setUpTransCircle(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) self.__dgMod = OpenMaya.MDGModifier() def doIt(self,argList): global messageId #- Create a transCircle node and two Nurbs spheres transCircle = OpenMaya.MObject() transCircle = self.__dgMod.createNode("transCircle") #- TODO: Rename the node to "circleNode1" #... #- TODO: Use MDGMOdifier to simulate executing the following commands #- command "sphere -n sphere1 -r 1;" and command "sphere -n sphere2 -r 2;" #... #... #... #... #- TODO: Now force these operation to be executed by calling the DG modifier doIt() method. #... #- The following code is one sample code if you want to simulate "sphere -n sphere1 -r 1" manually from MDGModifier and MDagModifier ''' testNode = OpenMaya.MObject() testNode = self.__dgMod.createNode("makeNurbSphere") nurbsSphereFn = OpenMaya.MFnDependencyNode(testNode) radiusPlug = OpenMaya.MPlug() radiusPlug = nurbsSphereFn.findPlug("radius") radiusPlug.setFloat(1.0f) self.__dgMod.doIt() self.dagMod = OpenMaya.MDagModifier() nurbsTransform = OpenMaya.MObject() nurbsTransform = self.dagMod.createNode("nurbsSurface") self.dagMod.doIt() outputPlug = OpenMaya.MPlug() outputPlug = nurbsSphereFn.findPlug("outputSurface") transformFn = OpenMaya.MFnDagNode(nurbsTransform) nurbsFn = OpenMaya.MFnDagNode(transformFn.child(0)) createPlug = OpenMaya.MPlug() createPlug = nurbsFn.findPlug("create") self.dagMod.connect(outputPlug, createPlug) self.dagMod.doIt() ''' selList = OpenMaya.MSelectionList() #- Find the Nurbs sphere nodes and transCircle node OpenMaya.MGlobal.getSelectionListByName("sphere1",selList) sphereDep = OpenMaya.MObject() selList.getDependNode(0,sphereDep) selList.clear() OpenMaya.MGlobal.getSelectionListByName("sphere2",selList) sphereTwoDep = OpenMaya.MObject() selList.getDependNode(0,sphereTwoDep) selList.clear() #- Connect attributes between Nurbs sphere and transCircle node fnSphere= OpenMaya.MFnDependencyNode(sphereDep) fnSphereTwo = OpenMaya.MFnDependencyNode(sphereTwoDep) fnTransCircleNode= OpenMaya.MFnDependencyNode(transCircle) inputTransAttr = OpenMaya.MObject() inputTransAttr = fnTransCircleNode.attribute("inputTranslate") sphereTwoTranslateAttr = OpenMaya.MObject() sphereTwoTranslateAttr = fnSphereTwo.attribute("translate") self.__dgMod.connect(sphereTwoDep,sphereTwoTranslateAttr,transCircle,inputTransAttr) #- TODO: Connect the "outputTranslate" circle node attribute with the "translate" "sphere1" node attribute #... #... #... #- Connect time1 node with transCircle node timeNode = OpenMaya.MObject() OpenMaya.MGlobal.getSelectionListByName("time1",selList) selList.getDependNode(0,timeNode) selList.clear() fnTimeNode= OpenMaya.MFnDependencyNode(timeNode) timeAttr = OpenMaya.MObject() timeAttr = fnTimeNode.attribute("outTime") inputAttr = OpenMaya.MObject() inputAttr = fnTransCircleNode.attribute("input") self.__dgMod.connect(timeNode,timeAttr,transCircle,inputAttr) #- Now force these operation to be executed by calling the DG modifier doIt() method. self.__dgMod.doIt() def isUndoable(self): return True def undoIt(self): return self.__dgMod.undoIt() def redoIt(self): return self.__dgMod.doIt() # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, kPluginNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise try: mplugin.registerCommand( kPluginCmdTypeName, cmdCreator) except: sys.stderr.write( "Failed to register command: %s" % kPluginCmdTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( kPluginNodeId) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise try: mplugin.deregisterCommand( kPluginCmdTypeName ) except: sys.stderr.write( "Failed to deregister command: %s" % kPluginCmdTypeName ) raise ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/AEtransCircleTemplate.mel ================================================ //- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ //AEtransCircleTemplate.mel global proc AEtransCircleTemplate( string $nodeName ) { // Put our attributes into a scrolled layout field editorTemplate -beginScrollLayout; // The all go into the collapsable "Parameters" section editorTemplate -beginLayout "Parameters" -collapse false; // Add a "special" control for the scale attribute that allow // "quick set" options for scales of 5, 10, and 15. editorTemplate -callCustom "transCircleScaleNew" "transCircleScaleReplace" "scale"; // Add the default controls for the scale and frames attributes editorTemplate -addControl "scale"; editorTemplate -addControl "frames"; editorTemplate -endLayout; // Create an "Extras" section and also add controls for any // attributes we have not explicitly mentioned. editorTemplate -addExtraControls; editorTemplate -endScrollLayout; // Tell the attribute editor not to display the attributes we // don't care about. editorTemplate -suppress "inputTranslate"; editorTemplate -suppress "input"; editorTemplate -suppress "caching"; editorTemplate -suppress "nodeState"; } global proc transCircleScaleNew( string $attrName ) { // Maya the "quick set" control for the scale attribute radioButtonGrp -label "Quick Scale" -numberOfRadioButtons 3 -label1 "Five" -data1 5 -label2 "Ten" -data2 10 -label3 "Fifteen" -data3 15 scaleGrp; connectControl scaleGrp $attrName; } global proc transCircleScaleReplace( string $attrName ) { // Install the connection between the radioButtonGrp and the // actual scale attribute connectControl scaleGrp $attrName; } ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/pluginMain.cpp ================================================ // // Copyright (C) // // File: pluginMain.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include "setUpTransCircleCmd.h" #include "transCircleNode.h" MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); // Add plug-in feature registration here // status = plugin.registerCommand("setUpTransCircle",setUpTransCircle::creator); status = plugin.registerNode( "transCircle", transCircle::id,transCircle::creator, transCircle::initialize ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); // Add plug-in feature deregistration here // status = plugin.deregisterCommand("setUpTransCircle"); status = plugin.deregisterNode( transCircle::id ); if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/setUpTransCircle.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setUpTransCircle", "setUpTransCircle.vcxproj", "{01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Debug|x64.ActiveCfg = Debug|x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Debug|x64.Build.0 = Debug|x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Release|x64.ActiveCfg = Release|x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/setUpTransCircle.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {01F0506D-A851-4FE1-B0B9-30C6ABAE30FE} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.61030.0 Debug\ Debug\ C:\MayaAPITraining\plug-ins\ .mll Release\ Release\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\setUpTransCircle.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\setUpTransCircle.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/setUpTransCircleCmd.cpp ================================================ // // Copyright (C) // // File: setUpTransCircleCmd.cpp // // MEL Command: setUpTransCircle // #include "setUpTransCircleCmd.h" #include "transCircleNode.h" #include #include #include #include #include #include #include #include #include #include #include //- Here is what you need to set up the transCircle node //- createNode transCircle -n circleNode1; //- sphere -n sphere1 -r 1; //- sphere -n sphere2 -r 2; //- connectAttr sphere2.translate circleNode1.inputTranslate; //- connectAttr circleNode1.outputTranslate sphere1.translate; //- connectAttr time1.outTime circleNode1.input; MStatus setUpTransCircle::doIt( const MArgList& argList) { MStatus stat = MS::kSuccess; //- Create a transCircle node and two Nurbs spheres MString tranCircleType("transCircle"); MObject transCircle = dgMod.createNode(tranCircleType,&stat); dgMod.renameNode(transCircle,MString("circleNode1")); MString creatingSphereCommand("sphere -n sphere1 -r 1;"); dgMod.commandToExecute(creatingSphereCommand); MString creatingSphereTwoCommand("sphere -n sphere2 -r 2;"); dgMod.commandToExecute(creatingSphereTwoCommand); //- ATTENTION: The above operations has to be executed first to make the connecting plugs //- code work. //- Now force these operation to be executed by calling the DG modifier doIt() method. dgMod.doIt(); //- The following code is one sample code if you want to simulate "sphere -n sphere1 -r 1" manually from MDGModifier and MDagModifier /* MObject testNode = dgMod.createNode(MString("makeNurbSphere"),&stat); MFnDependencyNode nurbsSphereFn(testNode); MPlug radiusPlug = nurbsSphereFn.findPlug("radius"); radiusPlug.setFloat(1.0f); dgMod.doIt(); MDagModifier dagMod; MObject nurbsTransform = dagMod.createNode("nurbsSurface"); dagMod.doIt(); MPlug outputPlug = nurbsSphereFn.findPlug("outputSurface"); MFnDagNode transformFn(nurbsTransform); MFnDagNode nurbsFn(transformFn.child(0)); MPlug createPlug = nurbsFn.findPlug("create"); dagMod.connect(outputPlug, createPlug); dagMod.doIt(); */ MSelectionList selList; //- Find the Nurbs sphere nodes and transCircle node MGlobal::getSelectionListByName(MString("sphere1"),selList); MObject sphereDep; selList.getDependNode(0,sphereDep); selList.clear(); MGlobal::getSelectionListByName(MString("sphere2"),selList); MObject sphereTwoDep; selList.getDependNode(0,sphereTwoDep); selList.clear(); //- Connect attributes between Nurbs sphere and transCircle node MFnDependencyNode fnSphere(sphereDep,&stat); MFnDependencyNode fnSphereTwo(sphereTwoDep,&stat); MFnDependencyNode fnTransCircleNode(transCircle,&stat); MObject inputTransAttr = fnTransCircleNode.attribute(MString("inputTranslate"),&stat); MObject sphereTwoTranslateAttr = fnSphereTwo.attribute(MString("translate"),&stat); dgMod.connect(sphereTwoDep,sphereTwoTranslateAttr,transCircle,inputTransAttr); MObject outputTransAttr = fnTransCircleNode.attribute(MString("outputTranslate"),&stat); MObject sphereTranslateAttr = fnSphere.attribute(MString("translate"),&stat); dgMod.connect(transCircle,outputTransAttr,sphereDep,sphereTranslateAttr); //- Connect time1 node with transCircle node MObject timeNode; MGlobal::getSelectionListByName(MString("time1"),selList); selList.getDependNode(0,timeNode); selList.clear(); MFnDependencyNode fnTimeNode(timeNode); MObject timeAttr = fnTimeNode.attribute(MString("outTime"),&stat); MObject inputAttr = fnTransCircleNode.attribute(MString("input"),&stat); dgMod.connect(timeNode,timeAttr,transCircle,inputAttr); //- Now force these operation to be executed by calling the DG modifier doIt() method. stat = dgMod.doIt(); return stat; } MStatus setUpTransCircle::undoIt() { return dgMod.undoIt(); } MStatus setUpTransCircle::redoIt() { return dgMod.doIt(); } ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/setUpTransCircleCmd.h ================================================ // // Copyright (C) // // File: setUpTransCircleCmd.h // // MEL Command: setUpTransCircle // // Author: Maya Plug-in Wizard 2.0 // #pragma once #include #include class MArgList; class setUpTransCircle : public MPxCommand { public: setUpTransCircle() {} virtual ~setUpTransCircle() {} virtual MStatus doIt( const MArgList& ); virtual MStatus undoIt(); virtual MStatus redoIt(); virtual bool isUndoable() const { return (true); } static void* creator() { return new setUpTransCircle(); } private: MDGModifier dgMod; }; ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/transCircleNode.cpp ================================================ // // Copyright (C) // // File: transCircleNode.cpp // // Author: Maya Plug-in Wizard 2.0 // #include #include #include #include #include #include #include #include #include #include "transCircleNode.h" MTypeId transCircle::id( 0x80013 ); MObject transCircle::input; MObject transCircle::frames; MObject transCircle::scale; MObject transCircle::inputTranslate; MObject transCircle::outputTranslate; MObject transCircle::inputTranslateX; MObject transCircle::inputTranslateY; MObject transCircle::inputTranslateZ; MObject transCircle::outputTranslateX; MObject transCircle::outputTranslateY; MObject transCircle::outputTranslateZ; MStatus transCircle::initialize() { MFnNumericAttribute nAttr; MStatus stat; input = nAttr.create( "input", "in", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateX = nAttr.create( "inputTranslateX", "itX", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateY = nAttr.create( "inputTranslateY", "itY", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", MFnNumericData::kDouble, 0.0 ); nAttr.setStorable(true); inputTranslate = nAttr.create( "inputTranslate", "it", inputTranslateX, inputTranslateY, inputTranslateZ ); nAttr.setStorable(true); nAttr.setDefault(0.0,0.0,0.0); outputTranslateX = nAttr.create( "outputTranslateX", "otX", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslateY = nAttr.create( "outputTranslateY", "otY", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslateZ = nAttr.create( "outputTranslateZ", "otZ", MFnNumericData::kDouble, 0.0 ); nAttr.setWritable(false); nAttr.setStorable(true); outputTranslate = nAttr.create( "outputTranslate", "ot", outputTranslateX, outputTranslateY, outputTranslateZ ); nAttr.setWritable(false); nAttr.setStorable(true); nAttr.setDefault(0.0,0.0,0.0); scale = nAttr.create( "scale", "sc", MFnNumericData::kDouble, 10.0 ); nAttr.setStorable(true); frames = nAttr.create( "frames", "fr", MFnNumericData::kDouble, 48.0 ); nAttr.setStorable(true); addAttribute( inputTranslate ); addAttribute( input ); addAttribute( scale ); addAttribute( frames ); addAttribute( outputTranslate ); attributeAffects( inputTranslateX, outputTranslateX ); attributeAffects( inputTranslateY, outputTranslateY ); attributeAffects( inputTranslateZ, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslateX ); attributeAffects( inputTranslate, outputTranslateY ); attributeAffects( inputTranslate, outputTranslateZ ); attributeAffects( inputTranslate, outputTranslate ); attributeAffects( input, outputTranslateX ); attributeAffects( input, outputTranslateY ); attributeAffects( scale, outputTranslateX ); attributeAffects( scale, outputTranslateY ); attributeAffects( frames, outputTranslateX ); attributeAffects( frames, outputTranslateY ); return MS::kSuccess; } MStatus transCircle::compute( const MPlug& plug, MDataBlock& data ) { MStatus stat; bool k = ( plug == outputTranslateX ) | ( plug == outputTranslateY ) | ( plug == outputTranslateZ ) | ( plug == outputTranslate ); if (!k) return MS::kUnknownParameter; MDataHandle inputData = data.inputValue( input, &stat ); MDataHandle scaleData = data.inputValue( scale, &stat ); MDataHandle framesData = data.inputValue( frames, &stat ); MDataHandle transData = data.inputValue( inputTranslate, &stat ); double3& iTranslate = transData.asDouble3(); double currentFrame = inputData.asDouble(); double scaleFactor = scaleData.asDouble(); double framesPerCircle = framesData.asDouble(); double angle = 6.2831853 * ( currentFrame/framesPerCircle ); double3 oTranslate; oTranslate[0] = iTranslate[0] + (sin( angle ) * scaleFactor); oTranslate[1] = iTranslate[1] + 1.0; oTranslate[2] = iTranslate[2] + (cos( angle ) * scaleFactor); MDataHandle otHandle = data.outputValue( outputTranslate ); otHandle.set( oTranslate[0], oTranslate[1], oTranslate[2] ); data.setClean(plug); return MS::kSuccess; } ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - C++/transCircleNode.h ================================================ // // Copyright (C) // // File: transCircleNode.h // // Author: Maya Plug-in Wizard 2.0 // #pragma once #include class transCircle : public MPxNode { public: transCircle() {} virtual ~transCircle() {} virtual MStatus compute( const MPlug& plug, MDataBlock& data ); static MStatus initialize(); static void* creator() { return new transCircle(); } public: static MObject input; // The input value. static MObject inputTranslateX; // The translate X value. (input) static MObject inputTranslateY; // The translate Y value. (input) static MObject inputTranslateZ; // The translate Z value. (input) static MObject inputTranslate; static MObject outputTranslateX; // The translate X value. (output) static MObject outputTranslateY; // The translate Y value. (output) static MObject outputTranslateZ; // The translate Z value. (output) static MObject outputTranslate; static MObject frames; // Number of frames for one circle. static MObject scale; // Size of circle. static MTypeId id; }; ================================================ FILE: 06_MiscTools/setUpTransCircle/Solution - py/setUpTransCircle.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network import sys, math import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "transCircle" kPluginCmdTypeName = "setUpTransCircle" kPluginNodeId = OpenMaya.MTypeId(0x80013) # Node definition class transCircle(OpenMayaMPx.MPxNode): # class variables # Node attributes #- Compound attributes in Maya are build from several individual attributes. In #- our example the translation vector is made of the x,y,z attributes, and the #- compound attribute itself. aInput = OpenMaya.MObject() aFrames = OpenMaya.MObject() aScale = OpenMaya.MObject() aInputTranslate = OpenMaya.MObject() aInputTranslateX = OpenMaya.MObject() aInputTranslateY = OpenMaya.MObject() aInputTranslateZ = OpenMaya.MObject() aOutputTranslate = OpenMaya.MObject() aOutputTranslateX = OpenMaya.MObject() aOutputTranslateY = OpenMaya.MObject() aOutputTranslateZ = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- This method computes the value of the given output plug based #- on the values of the input attributes. #- Arguments: #- plug - the plug to compute #- data - object that provides access to the attributes for this node def compute(self, plug, data): if (plug != transCircle.aOutputTranslateX and plug != transCircle.aOutputTranslateY and plug != transCircle.aOutputTranslateZ and plug != transCircle.aOutputTranslate): return OpenMaya.kUnknownParameter inputData = data.inputValue( transCircle.aInput ) scaleData = data.inputValue( transCircle.aScale ) framesData = data.inputValue( transCircle.aFrames ) currentFrame = inputData.asDouble() scaleFactor = scaleData.asDouble() framesPerCircle = framesData.asDouble() #- Retrieve values on individual input translate attribute inputTranslateXHandle = data.inputValue(transCircle.aInputTranslateX) inputTranslateXData = inputTranslateXHandle.asDouble() inputTranslateYHandle = data.inputValue(transCircle.aInputTranslateY) inputTranslateYData = inputTranslateYHandle.asDouble() inputTranslateZHandle = data.inputValue(transCircle.aInputTranslateZ) inputTranslateZData = inputTranslateZHandle.asDouble() #- Calculate corresponding angle based on current frame angle = 6.2831853 * ( currentFrame/framesPerCircle ) #- The value of output translate is input translate value plus the value of circular movement outputTranslateXData = inputTranslateXData + (math.sin( angle ) * scaleFactor) outputTranslateYData = inputTranslateYData + 1.0 outputTranslateZData = inputTranslateZData + (math.cos( angle ) * scaleFactor) #- Get a handle on the output attributes and set the new value. outputTranslateXHandle = data.outputValue( transCircle.aOutputTranslateX ) outputTranslateXHandle.setDouble(outputTranslateXData) outputTranslateYHandle = data.outputValue( transCircle.aOutputTranslateY ) outputTranslateYHandle.setDouble(outputTranslateYData) outputTranslateZHandle = data.outputValue( transCircle.aOutputTranslateZ ) outputTranslateZHandle.setDouble(outputTranslateZData) #- Tell Maya the plug is now clean data.setClean(plug) def nodeInitializer(): nAttr = OpenMaya.MFnNumericAttribute() transCircle.aInput = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) transCircle.aInputTranslateX = nAttr.create( "inputTranslateX", "itX", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) transCircle.aInputTranslateY = nAttr.create( "inputTranslateY", "itY", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) transCircle.aInputTranslateZ = nAttr.create( "inputTranslateZ", "itZ", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setStorable(True) #- Create compound input translate attributes and add individual input translate attributes comAttr = OpenMaya.MFnCompoundAttribute() transCircle.aInputTranslate = comAttr.create("inputTranslate","it") comAttr.addChild(transCircle.aInputTranslateX) comAttr.addChild(transCircle.aInputTranslateY) comAttr.addChild(transCircle.aInputTranslateZ) comAttr.setStorable(True) transCircle.aOutputTranslateX = nAttr.create( "outputTranslateX", "otX", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(False) nAttr.setStorable(True) transCircle.aOutputTranslateY = nAttr.create( "outputTranslateY", "otY", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(False) nAttr.setStorable(True) transCircle.aOutputTranslateZ = nAttr.create( "outputTranslateZ", "otZ", OpenMaya.MFnNumericData.kDouble, 0.0 ) nAttr.setWritable(False) nAttr.setStorable(True) #- Create compound output translate attributes and add individual output translate attributes transCircle.aOutputTranslate = comAttr.create("outputTranslate","ot") comAttr.addChild(transCircle.aOutputTranslateX) comAttr.addChild(transCircle.aOutputTranslateY) comAttr.addChild(transCircle.aOutputTranslateZ) comAttr.setWritable(False) comAttr.setStorable(True) transCircle.aScale = nAttr.create( "scale", "sc", OpenMaya.MFnNumericData.kDouble, 10.0 ) nAttr.setStorable(True) transCircle.aFrames = nAttr.create( "frames", "fr", OpenMaya.MFnNumericData.kDouble, 48.0 ) nAttr.setStorable(True) transCircle.addAttribute( transCircle.aInputTranslate ) transCircle.addAttribute( transCircle.aInput ) transCircle.addAttribute( transCircle.aScale ) transCircle.addAttribute( transCircle.aFrames ) transCircle.addAttribute( transCircle.aOutputTranslate ) transCircle.attributeAffects( transCircle.aInputTranslateX, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aInputTranslateY, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aInputTranslateZ, transCircle.aOutputTranslateZ ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslateZ ) transCircle.attributeAffects( transCircle.aInputTranslate, transCircle.aOutputTranslate ) transCircle.attributeAffects( transCircle.aInput, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aInput, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aScale, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aScale, transCircle.aOutputTranslateY ) transCircle.attributeAffects( transCircle.aFrames, transCircle.aOutputTranslateX ) transCircle.attributeAffects( transCircle.aFrames, transCircle.aOutputTranslateY ) # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( transCircle() ) # Creators def cmdCreator(): return OpenMayaMPx.asMPxPtr(setUpTransCircle()) #- Here is what you need to set up the transCircle node #- createNode transCircle -n circleNode1 #- sphere -n sphere1 -r 1 #- sphere -n sphere2 -r 2 #- connectAttr sphere2.translate circleNode1.inputTranslate #- connectAttr circleNode1.outputTranslate sphere1.translate #- connectAttr time1.outTime circleNode1.input class setUpTransCircle(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) self.__dgMod = OpenMaya.MDGModifier() def doIt(self,argList): #- Create a transCircle node and two Nurbs spheres #transCircle = OpenMaya.MObject() transCircle = self.__dgMod.createNode("transCircle") self.__dgMod.renameNode(transCircle,"circleNode1") creatingSphereCommand = "sphere -n sphere1 -r 1" self.__dgMod.commandToExecute(creatingSphereCommand) creatingSphereTwoCommand = "sphere -n sphere2 -r 2" self.__dgMod.commandToExecute(creatingSphereTwoCommand) #- ATTENTION: The above operations has to be executed first to make the connecting plugs #- code work. #- Now force these operation to be executed by calling the DG modifier doIt() method. self.__dgMod.doIt() selList = OpenMaya.MSelectionList() #- Find the Nurbs sphere nodes and transCircle node OpenMaya.MGlobal.getSelectionListByName("sphere1",selList) sphereDep = OpenMaya.MObject() selList.getDependNode(0,sphereDep) selList.clear() OpenMaya.MGlobal.getSelectionListByName("sphere2",selList) sphereTwoDep = OpenMaya.MObject() selList.getDependNode(0,sphereTwoDep) selList.clear() #- Connect attributes between Nurbs sphere and transCircle node fnSphere= OpenMaya.MFnDependencyNode(sphereDep) fnSphereTwo = OpenMaya.MFnDependencyNode(sphereTwoDep) fnTransCircleNode= OpenMaya.MFnDependencyNode(transCircle) inputTransAttr = fnTransCircleNode.attribute("inputTranslate") sphereTwoTranslateAttr = fnSphereTwo.attribute("translate") self.__dgMod.connect(sphereTwoDep,sphereTwoTranslateAttr,transCircle,inputTransAttr) outputTransAttr = fnTransCircleNode.attribute("outputTranslate") sphereTranslateAttr = fnSphere.attribute("translate") self.__dgMod.connect(transCircle,outputTransAttr,sphereDep,sphereTranslateAttr) #- Connect time1 node with transCircle node timeNode = OpenMaya.MObject() OpenMaya.MGlobal.getSelectionListByName("time1",selList) selList.getDependNode(0,timeNode) selList.clear() fnTimeNode= OpenMaya.MFnDependencyNode(timeNode) timeAttr = OpenMaya.MObject() timeAttr = fnTimeNode.attribute("outTime") inputAttr = OpenMaya.MObject() inputAttr = fnTransCircleNode.attribute("input") self.__dgMod.connect(timeNode,timeAttr,transCircle,inputAttr) #- Now force these operation to be executed by calling the DG modifier doIt() method. self.__dgMod.doIt() def isUndoable(self): return True def undoIt(self): return self.__dgMod.undoIt() def redoIt(self): return self.__dgMod.doIt() # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, kPluginNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise try: mplugin.registerCommand( kPluginCmdTypeName, cmdCreator) except: sys.stderr.write( "Failed to register command: %s" % kPluginCmdTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( kPluginNodeId) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise try: mplugin.deregisterCommand( kPluginCmdTypeName ) except: sys.stderr.write( "Failed to deregister command: %s" % kPluginCmdTypeName ) raise ================================================ FILE: 07_Locator/arrowLocator/Exercise - C++/arrowLocator.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arrowLocator", "arrowLocator.vcxproj", "{2A76853E-2C9D-4719-B6C7-6A787EEED416}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Debug|x64.ActiveCfg = Debug|x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Debug|x64.Build.0 = Debug|x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Release|x64.ActiveCfg = Release|x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 07_Locator/arrowLocator/Exercise - C++/arrowLocator.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.50727.1 Debug\ Debug\ $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ Release\ Release\ $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2014\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;opengl32.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\arrowLocator.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib X64 /GR /GS /Gm /EHac /ZI /I "." /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaRender.lib;OpenMayaUI.lib;opengl32.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\arrowLocator.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib MachineX64 /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib X64 /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib MachineX64 ================================================ FILE: 07_Locator/arrowLocator/Exercise - C++/arrowLocatorNode.cpp ================================================ // // Copyright (C) // // File: arrowLocatorNode.cpp // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #include "arrowLocatorNode.h" #include #include #include #include #include #include #include #include #include //- Assign a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x80002 is a temporary ID for reserved for development. Never use that ID in a //- production environement. /*static*/MTypeId arrowLocator::id( 0x80002 ); //- Instantiate the static attribute of your node class. /*static*/MObject arrowLocator::windDirection; //- An array of points to draw our compass arrow in openGL static float arrow[][3] = { {2.00f, 0.0f, 0.0f} , {-3.0f, 0.0f, 2.0f} , {-2.0f, 0.0f, 0.0f} , {-3.0f, 0.0f, -2.0f}}; //- Indices into the arrow array static GLuint triangleIndices[] = {0,1,2,0,2,3}; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- /*static*/ MStatus arrowLocator::initialize() { //- Here we create a new attribute type that handles units: angle, distance or time MFnUnitAttribute uAttr; //- TODO: Create a angle attribute with long name "windDirection" and short name "wd" windDirection = //... uAttr.setStorable(true); uAttr.setWritable(true); uAttr.setReadable(true); uAttr.setKeyable(true); //- TODO: Set the min and max value this attribute can have 0, 2PI //... //... uAttr.setDefault(MAngle(0.0, MAngle::kRadians)); addAttribute(windDirection); return MS::kSuccess; } //- This method draw this locator in current scene by calling openGL functions // view -- 3D view that is being drawn into // path -- path to this locator in the DAG // style -- style to draw object in // status -- selection status of object // void arrowLocator::draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status) { //- TODO: Get a reference of current node MObject thisNode = //... //- We're in the draw routine, not the compute method //- therefore it is safe to grab plugs in the following way and //- get/set values. You would never do something like this in //- the compute method because it might start a cycle in the //- graph. Here we just need the value of our winddirection //- plug so that we can draw our arrow pointing the right way. //- TODO: Get the wind direction plug and get its angle value //... MAngle angle; //... //- Start drawing by OpenGL view.beginGL(); //- If the drawing style is shaded, set color and draw opaque shape if ( ( style == M3dView::kFlatShaded ) || ( style == M3dView::kGouraudShaded ) ) { //- Push to save current color settings glPushAttrib( GL_CURRENT_BIT ); if ( status == M3dView::kActive ) { view.setDrawColor( 13, M3dView::kActiveColors ); } else { view.setDrawColor( 13, M3dView::kDormantColors ); } //- Push the old matrix on the stack, rotate the current one, //- draw the shape, then pop the old matrix off the stack for //- maya to use again. glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); glPopAttrib(); } //- Draw the outline of the arrow shape glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_LINE_STRIP); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); view.endGL(); } //- This method return the bounding box for this locator shape, //- providing a bounding box routine makes refresh and selection more efficient. // MBoundingBox arrowLocator::boundingBox() const { MPoint upLeftCorner(-3.0, 0.0, -2.0); MPoint downRightCorner(2.0, 0.0, 2.0); MBoundingBox boundingArea(upLeftCorner,downRightCorner); return boundingArea; } void arrowLocator::getRotationAngle (arrowLocatorData * data){ // Retrieve value of the angle attribute from the node MStatus status ; MObject node = thisMObject(); MPlug wdPlug(node, windDirection); MAngle angle; wdPlug.getValue(angle); data->rotateAngle = angle; } class arrowLocatorOverride : public MHWRender::MPxDrawOverride { public: static MHWRender::MPxDrawOverride* Creator(const MObject& obj) { return new arrowLocatorOverride(obj); } virtual ~arrowLocatorOverride(); virtual MHWRender::DrawAPI supportedDrawAPIs() const; virtual bool isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MBoundingBox boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MUserData* prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData); static void draw( const MHWRender::MDrawContext& context, const MUserData* data); private: arrowLocatorOverride(const MObject& obj); }; arrowLocatorOverride::arrowLocatorOverride(const MObject& obj) : MHWRender::MPxDrawOverride(obj, arrowLocatorOverride::draw) { } arrowLocatorOverride::~arrowLocatorOverride() { } MHWRender::DrawAPI arrowLocatorOverride::supportedDrawAPIs() const { return MHWRender::kOpenGL; } bool arrowLocatorOverride::isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const { return true; } MBoundingBox arrowLocatorOverride::boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const { MStatus status; MFnDependencyNode node(objPath.node(), &status); arrowLocator* locatorNode = dynamic_cast(node.userNode()); return locatorNode->boundingBox(); } MUserData* arrowLocatorOverride::prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData) { // get the node MStatus status; MFnDependencyNode node(objPath.node(), &status); if (!status) return NULL; arrowLocator* locatorNode = dynamic_cast(node.userNode()); if (!locatorNode) return NULL; // access/create user data for draw callback arrowLocatorData* data = dynamic_cast(oldData); if (!data) { data = new arrowLocatorData(); } // compute data and cache it locatorNode->getRotationAngle(data) ; return data; } void arrowLocatorOverride::draw( const MHWRender::MDrawContext& context, const MUserData* data) { MAngle rotationAngle; float color [3] ={ 0.0f, 1.0f, 0.0f } ; // data MStatus status; MHWRender::MStateManager* stateMgr = context.getStateManager(); const arrowLocatorData* locatorData = dynamic_cast(data); if (!stateMgr || !locatorData) return; if ( locatorData ) rotationAngle = locatorData->rotateAngle; // matrices const MMatrix transform = context.getMatrix(MHWRender::MFrameContext::kWorldViewMtx, &status); if (status != MStatus::kSuccess) return; const MMatrix projection = context.getMatrix(MHWRender::MFrameContext::kProjectionMtx, &status); if (status != MStatus::kSuccess) return; // get renderer MHWRender::MRenderer *theRenderer =MHWRender::MRenderer::theRenderer () ; if ( !theRenderer ) return ; if ( theRenderer->drawAPIIsOpenGL () ) { glPushAttrib(GL_CURRENT_BIT); glColor4fv(color); glPushMatrix(); glRotated(-rotationAngle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_LINE_STRIP); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); } } MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); status = plugin.registerNode( "arrowLocator", arrowLocator::id, arrowLocator::creator, arrowLocator::initialize, MPxNode::kLocatorNode,&arrowLocator::drawDbClassification); status = MHWRender::MDrawRegistry::registerDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId, arrowLocatorOverride::Creator) ; if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( arrowLocator::id ); MHWRender::MDrawRegistry::deregisterDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId) ; if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 07_Locator/arrowLocator/Exercise - C++/arrowLocatorNode.h ================================================ // // Copyright (C) // // File: arrowLocatorNode.h // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #pragma once #include #include #include #include #include // Viewport 2.0 includes #include #include #include #include #include #include #include #include #include #include #include //- Macros to use to rotate the locator #define PI 3.14159265358979 #define toDegree(rot) rot*(180.0/PI) class arrowLocatorData : public MUserData { public: MAngle rotateAngle ; arrowLocatorData() : MUserData(false) {} // don't delete after draw virtual ~arrowLocatorData() {} }; class arrowLocator : public MPxLocatorNode { public: arrowLocator() {} virtual ~arrowLocator() {} virtual void draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status); virtual MBoundingBox boundingBox() const; virtual bool isBounded() const { return true; //- This method should be overridden to return true if the user supplies a bounding box routine. } void getRotationAngle (arrowLocatorData * data ); static MStatus initialize(); static void* creator() { return new arrowLocator(); } public: static MTypeId id; static MString drawDbClassification; static MString drawRegistrantId; static MObject windDirection; //- This is an attribute representing the rotation angle }; ================================================ FILE: 07_Locator/arrowLocator/Exercise - py/arrowLocator.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import sys, math import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import maya.OpenMayaRender as OpenMayaRender import maya.OpenMayaUI as OpenMayaUI kPluginNodeTypeName = "arrowLocator" kPluginNodeId = OpenMaya.MTypeId(0x80002) glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() glFT = glRenderer.glFunctionTable() #an array of points to draw our compass arrow in openGL arrow = ( [2.00, 0.0, 0.0], [-3.0, 0.0, 2.0], [-2.0, 0.0, 0.0], [-3.0, 0.0, -2.0]) #indices into the arrow array triangleIndices = [0,1,2,0,2,3] # Node definition class arrowLocator(OpenMayaMPx.MPxLocatorNode): windDirection = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxLocatorNode.__init__(self) def compute(self, plug, data): return OpenMaya.kUnknownParameter #- This method draw this locator in current scene by calling openGL functions #- #- Arguments: #- view -- 3D view that is being drawn into #- path -- path to this locator in the DAG #- style -- style to draw object in #- status -- selection status of object #- def draw(self, view, path, style, status): ##- TODO: Get a reference of current node thisNode = ##.. #We're in the draw routine, not the Compute method #therefore it is safe to grab plugs in the following way and #get/set values. You would never do something like this in #the compute method because it might start a cycle in the #graph. Here we just need the value of our winddirection #plug so that we can draw our arrow pointing the right way. ##- TODO: Get the wind direction plug and get its angle value ##... angle = plug.asMAngle() #start drawing by OpenGL view.beginGL() #If the drawing style is shaded, set color and draw opaque shape if ((style == OpenMayaUI.M3dView.kFlatShaded) or (style == OpenMayaUI.M3dView.kGouraudShaded)): #Push to save current color settings glFT.glPushAttrib(OpenMayaRender.MGL_CURRENT_BIT ) if (status == OpenMayaUI.M3dView.kActive): view.setDrawColor( 13, OpenMayaUI.M3dView.kActiveColors ) else: view.setDrawColor( 13, OpenMayaUI.M3dView.kDormantColors ) #push the old matrix on the stack, rotate the current one, #draw the shape, then pop the old matrix off the stack for #maya to use again. glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() glFT.glPopAttrib() #Draw the outline of the arrow shape glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() view.endGL() def isBounded(self): return True #- This method return the bounding box for this locator shape, #- providing a bounding box routine makes refresh and selection more efficient. # def boundingBox(self): upLeftCorner = OpenMaya.MPoint(-3.0, 0.0, -2.0) downRightCorner = OpenMaya.MPoint(2.0, 0.0, 2.0) boundingArea = OpenMaya.MBoundingBox(upLeftCorner,downRightCorner) return boundingArea # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( arrowLocator() ) # initializer def nodeInitializer(): #Here we create a new attribute type that handles units: angle, distance or time uAttr = OpenMaya.MFnUnitAttribute() ##TODO: Create a angle attribute with long name "windDirection" and short name "wd" arrowLocator.windDirection = ##... uAttr.setStorable(True) uAttr.setWritable(True) uAttr.setReadable(True) uAttr.setKeyable(True) ##- TODO: Set the min and max value this attribute can have 0, 2PI ##... ##... uAttr.setDefault(OpenMaya.MAngle(0.0, OpenMaya.MAngle.kDegrees)) arrowLocator.addAttribute(arrowLocator.windDirection) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kLocatorNode ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( kPluginNodeId ) except: sys.stderr.write( "Failed to deregister command: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 07_Locator/arrowLocator/Solution - C++/arrowLocator.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arrowLocator", "arrowLocator.vcxproj", "{2A76853E-2C9D-4719-B6C7-6A787EEED416}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Debug|x64.ActiveCfg = Debug|x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Debug|x64.Build.0 = Debug|x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Release|x64.ActiveCfg = Release|x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 07_Locator/arrowLocator/Solution - C++/arrowLocator.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {2A76853E-2C9D-4719-B6C7-6A787EEED416} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>11.0.50727.1 Debug\ Debug\ $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ Release\ Release\ $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2014\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;opengl32.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\arrowLocator.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib X64 /GR /GS /Gm /EHac /ZI /I "." /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaRender.lib;OpenMayaUI.lib;opengl32.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\arrowLocator.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/.pdb Debug/.lib MachineX64 /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib X64 /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2008\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;%(AdditionalDependencies) Release\.mll C:\Program Files\Autodesk\Maya2008\lib;%(AdditionalLibraryDirectories) Release/.pdb Release/.lib MachineX64 ================================================ FILE: 07_Locator/arrowLocator/Solution - C++/arrowLocatorNode.cpp ================================================ // // Copyright (C) // // File: arrowLocatorNode.cpp // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #include "arrowLocatorNode.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //- Assign a unique node ID to your new node class. //- Ask ADN or Autodesk product support to reserve IDs for your company. You can //- reserve ID by block of 64, 128, 256, or 512 consecutive ID. //- //- 0x80002 is a temporary ID for reserved for development. Never use that ID in a //- production environment. /*static*/MTypeId arrowLocator::id( 0x80002 ); MString arrowLocator::drawDbClassification("drawdb/geometry/arrowLocator"); MString arrowLocator::drawRegistrantId("arrowLocatorNodePlugin"); //- Instantiate the static attribute of your node class. /*static*/MObject arrowLocator::windDirection; //- An array of points to draw our compass arrow in openGL static float arrow[][3] = { {2.00f, 0.0f, 0.0f} , {-3.0f, 0.0f, 2.0f} , {-2.0f, 0.0f, 0.0f} , {-3.0f, 0.0f, -2.0f}}; //- Indices into the arrow array static GLuint triangleIndices[] = {0,1,2,0,2,3}; //- The initialize method is called to create and initialize all of the //- attributes and attribute dependencies for this node type. This is //- only called once when the node type is registered with Maya. //- Return Values: MS::kSuccess / MS::kFailure //- /*static*/ MStatus arrowLocator::initialize() { //- Here we create a new attribute type that handles units: angle, distance or time MFnUnitAttribute uAttr; windDirection = uAttr.create("windDirection", "wd", MFnUnitAttribute::kAngle, 0.0); uAttr.setStorable(true); uAttr.setWritable(true); uAttr.setReadable(true); uAttr.setKeyable(true); uAttr.setMin(0.0); uAttr.setMax(2*PI); uAttr.setDefault(MAngle(0.0, MAngle::kRadians)); addAttribute(windDirection); return MS::kSuccess; } //- This method draw this locator in current scene by calling openGL functions // view -- 3D view that is being drawn into // path -- path to this locator in the DAG // style -- style to draw object in // status -- selection status of object // void arrowLocator::draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status) { MObject thisNode = thisMObject(); //- We're in the draw routine, not the compute method //- therefore it is safe to grab plugs in the following way and //- get/set values. You would never do something like this in //- the compute method because it might start a cycle in the //- graph. Here we just need the value of our winddirection //- plug so that we can draw our arrow pointing the right way. MPlug wdPlug(thisNode, windDirection); MAngle angle; wdPlug.getValue(angle); //- Start drawing by OpenGL view.beginGL(); //- If the drawing style is shaded, set color and draw opaque shape if ( ( style == M3dView::kFlatShaded ) || ( style == M3dView::kGouraudShaded ) ) { //- Push to save current color settings glPushAttrib( GL_CURRENT_BIT ); if ( status == M3dView::kActive ) { view.setDrawColor( 13, M3dView::kActiveColors ); } else { view.setDrawColor( 13, M3dView::kDormantColors ); } //- Push the old matrix on the stack, rotate the current one, //- draw the shape, then pop the old matrix off the stack for //- maya to use again. glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); glPopAttrib(); } //- Draw the outline of the arrow shape glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_LINE_STRIP); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); view.endGL(); } //- This method return the bounding box for this locator shape, //- providing a bounding box routine makes refresh and selection more efficient. // MBoundingBox arrowLocator::boundingBox() const { MPoint upLeftCorner(-3.0, 0.0, -2.0); MPoint downRightCorner(2.0, 0.0, 2.0); MBoundingBox boundingArea(upLeftCorner,downRightCorner); return boundingArea; } void arrowLocator::getRotationAngle (arrowLocatorData * data){ // Retrieve value of the angle attribute from the node MStatus status ; MObject node = thisMObject(); MPlug wdPlug(node, windDirection); MAngle angle; wdPlug.getValue(angle); data->rotateAngle = angle; } class arrowLocatorOverride : public MHWRender::MPxDrawOverride { public: static MHWRender::MPxDrawOverride* Creator(const MObject& obj) { return new arrowLocatorOverride(obj); } virtual ~arrowLocatorOverride(); virtual MHWRender::DrawAPI supportedDrawAPIs() const; virtual bool isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MBoundingBox boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MUserData* prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData); static void draw( const MHWRender::MDrawContext& context, const MUserData* data); private: arrowLocatorOverride(const MObject& obj); }; arrowLocatorOverride::arrowLocatorOverride(const MObject& obj) : MHWRender::MPxDrawOverride(obj, arrowLocatorOverride::draw) { } arrowLocatorOverride::~arrowLocatorOverride() { } MHWRender::DrawAPI arrowLocatorOverride::supportedDrawAPIs() const { return MHWRender::kOpenGL; } bool arrowLocatorOverride::isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const { return true; } MBoundingBox arrowLocatorOverride::boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const { MStatus status; MFnDependencyNode node(objPath.node(), &status); arrowLocator* locatorNode = dynamic_cast(node.userNode()); return locatorNode->boundingBox(); } MUserData* arrowLocatorOverride::prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData) { // get the node MStatus status; MFnDependencyNode node(objPath.node(), &status); if (!status) return NULL; arrowLocator* locatorNode = dynamic_cast(node.userNode()); if (!locatorNode) return NULL; // access/create user data for draw callback arrowLocatorData* data = dynamic_cast(oldData); if (!data) { data = new arrowLocatorData(); } // compute data and cache it locatorNode->getRotationAngle(data) ; return data; } void arrowLocatorOverride::draw( const MHWRender::MDrawContext& context, const MUserData* data) { MAngle rotationAngle; float color [3] ={ 0.0f, 1.0f, 0.0f } ; // data MStatus status; MHWRender::MStateManager* stateMgr = context.getStateManager(); const arrowLocatorData* locatorData = dynamic_cast(data); if (!stateMgr || !locatorData) return; if ( locatorData ) rotationAngle = locatorData->rotateAngle; // matrices const MMatrix transform = context.getMatrix(MHWRender::MFrameContext::kWorldViewMtx, &status); if (status != MStatus::kSuccess) return; const MMatrix projection = context.getMatrix(MHWRender::MFrameContext::kProjectionMtx, &status); if (status != MStatus::kSuccess) return; // get renderer MHWRender::MRenderer *theRenderer =MHWRender::MRenderer::theRenderer () ; if ( !theRenderer ) return ; if ( theRenderer->drawAPIIsOpenGL () ) { glPushAttrib(GL_CURRENT_BIT); glColor4fv(color); glPushMatrix(); glRotated(-rotationAngle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_LINE_STRIP); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); } } MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); status = plugin.registerNode( "arrowLocator", arrowLocator::id, arrowLocator::creator, arrowLocator::initialize, MPxNode::kLocatorNode,&arrowLocator::drawDbClassification); status = MHWRender::MDrawRegistry::registerDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId, arrowLocatorOverride::Creator) ; if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( arrowLocator::id ); MHWRender::MDrawRegistry::deregisterDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId) ; if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 07_Locator/arrowLocator/Solution - C++/arrowLocatorNode.h ================================================ // // Copyright (C) // // File: arrowLocatorNode.h // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #pragma once #include #include #include #include #include // Viewport 2.0 includes #include #include #include #include #include #include #include #include #include #include #include //- Macros to use to rotate the locator #define PI 3.14159265358979 #define toDegree(rot) rot*(180.0/PI) class arrowLocatorData : public MUserData { public: MAngle rotateAngle ; arrowLocatorData() : MUserData(false) {} // don't delete after draw virtual ~arrowLocatorData() {} }; class arrowLocator : public MPxLocatorNode { public: arrowLocator() {} virtual ~arrowLocator() {} virtual void draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status); virtual MBoundingBox boundingBox() const; virtual bool isBounded() const { return true; //- This method should be overridden to return true if the user supplies a bounding box routine. } void getRotationAngle (arrowLocatorData * data ); static MStatus initialize(); static void* creator() { return new arrowLocator(); } public: static MTypeId id; static MString drawDbClassification; static MString drawRegistrantId; static MObject windDirection; //- This is an attribute representing the rotation angle }; ================================================ FILE: 07_Locator/arrowLocator/Solution - py/arrowLocator.py ================================================ # # Copyright (C) # # File: arrowLocator.py # # Dependency Graph Node: # # Author: Maya Plug-in Wizard 2.0 import sys, math import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import maya.OpenMayaRender as OpenMayaRender import maya.OpenMayaUI as OpenMayaUI kPluginNodeTypeName = "arrowLocator" kPluginNodeId = OpenMaya.MTypeId(0x80002) glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() glFT = glRenderer.glFunctionTable() #an array of points to draw our compass arrow in openGL arrow = ( [2.00, 0.0, 0.0], [-3.0, 0.0, 2.0], [-2.0, 0.0, 0.0], [-3.0, 0.0, -2.0]) #indices into the arrow array triangleIndices = [0,1,2,0,2,3] # Node definition class arrowLocator(OpenMayaMPx.MPxLocatorNode): windDirection = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxLocatorNode.__init__(self) def compute(self, plug, data): return OpenMaya.kUnknownParameter #- This method draw this locator in current scene by calling openGL functions #- #- Arguments: #- view -- 3D view that is being drawn into #- path -- path to this locator in the DAG #- style -- style to draw object in #- status -- selection status of object #- def draw(self, view, path, style, status): thisNode = self.thisMObject() #We're in the draw routine, not the Compute method #therefore it is safe to grab plugs in the following way and #get/set values. You would never do something like this in #the compute method because it might start a cycle in the #graph. Here we just need the value of our winddirection #plug so that we can draw our arrow pointing the right way. plug = OpenMaya.MPlug(thisNode, arrowLocator.windDirection) angle = plug.asMAngle() #start drawing by OpenGL view.beginGL() #If the drawing style is shaded, set color and draw opaque shape if ((style == OpenMayaUI.M3dView.kFlatShaded) or (style == OpenMayaUI.M3dView.kGouraudShaded)): #Push to save current color settings glFT.glPushAttrib(OpenMayaRender.MGL_CURRENT_BIT ) if (status == OpenMayaUI.M3dView.kActive): view.setDrawColor( 13, OpenMayaUI.M3dView.kActiveColors ) else: view.setDrawColor( 13, OpenMayaUI.M3dView.kDormantColors ) #push the old matrix on the stack, rotate the current one, #draw the shape, then pop the old matrix off the stack for #maya to use again. glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() glFT.glPopAttrib() #Draw the outline of the arrow shape glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() view.endGL() def isBounded(self): return True #- This method return the bounding box for this locator shape, #- providing a bounding box routine makes refresh and selection more efficient. # def boundingBox(self): upLeftCorner = OpenMaya.MPoint(-3.0, 0.0, -2.0) downRightCorner = OpenMaya.MPoint(2.0, 0.0, 2.0) boundingArea = OpenMaya.MBoundingBox(upLeftCorner,downRightCorner) return boundingArea # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( arrowLocator() ) # initializer def nodeInitializer(): #Here we create a new attribute type that handles units: angle, distance or time uAttr = OpenMaya.MFnUnitAttribute() arrowLocator.windDirection = uAttr.create("windDirection", "wd", OpenMaya.MFnUnitAttribute.kAngle) uAttr.setStorable(True) uAttr.setWritable(True) uAttr.setReadable(True) uAttr.setKeyable(True) uAttr.setMin(0.0) uAttr.setMax(2*math.pi) uAttr.setDefault(OpenMaya.MAngle(0.0, OpenMaya.MAngle.kDegrees)) arrowLocator.addAttribute(arrowLocator.windDirection) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kLocatorNode ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( kPluginNodeId ) except: sys.stderr.write( "Failed to deregister command: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 08_Manipulators/arrowLocatorManip/Exercise - C++/arrowLocatorManip.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arrowLocatorManip", "arrowLocatorManip.vcxproj", "{C05EECF5-6CF1-4302-A92B-24DDB374E61A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Debug|x64.ActiveCfg = Debug|x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Debug|x64.Build.0 = Debug|x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Release|x64.ActiveCfg = Release|x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 08_Manipulators/arrowLocatorManip/Exercise - C++/arrowLocatorManip.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ .mll /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/arrowLocatorManip.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenGL32.lib;%(AdditionalDependencies) Debug\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/arrowLocatorManip.pdb Debug/arrowLocatorManip.lib /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/arrowLocatorManip.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenMayaRender.lib;OpenGL32.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/arrowLocatorManip.pdb Debug/arrowLocatorManip.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/arrowLocatorManip.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenGL32.lib;%(AdditionalDependencies) Release\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Release/arrowLocatorManip.pdb Release/arrowLocatorManip.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/arrowLocatorManip.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenGL32.lib;%(AdditionalDependencies) Release\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Release/arrowLocatorManip.pdb Release/arrowLocatorManip.lib ================================================ FILE: 08_Manipulators/arrowLocatorManip/Exercise - C++/arrowLocatorManipNode.cpp ================================================ // // Copyright (C) // // File: arrowLocatorManipNode.cpp // // Dependency Graph Node: arrowLocatorManip // // Author: Maya Plug-in Wizard 2.0 // #include "arrowLocatorManipNode.h" #include #include #include #include #include #include #include //- You MUST change this to a unique value!!! The id is a 32bit value used //- to identify this type of node in the binary file format. //- //- change the following to a unique value and then erase this line MTypeId arrowLocatorManip::id( 0x00003 ); MDagPath arrowLocatorManip::fDiscManip; MDagPath arrowLocatorManip::fNodePath; arrowLocatorManip::arrowLocatorManip() {} arrowLocatorManip::~arrowLocatorManip() {} //- This method exists to give Maya a way to create new objects //- of this type. //- //- Return Value: //- a new object of this type //- void* arrowLocatorManip::creator() { return new arrowLocatorManip(); } //- This method is called to create and initialize all of the attributes //- and attribute dependencies for this node type. This is only called //- once when the node type is registered with Maya. //- //- Return Values: //- MS::kSuccess //- MS::kFailure MStatus arrowLocatorManip::initialize() { MStatus stat; stat = MPxManipContainer::initialize(); return stat; } //- Container manipulators are composed of one or more base manipulators. //- When base manipulators are added to a container manipulator, they are referred to //- as children of the container manipulator, and are added using the createChildren method. MStatus arrowLocatorManip::createChildren() { MStatus status = MStatus::kSuccess; //- TODO: Create a base disc manip and //- TODO: add it into this manip container, assign //- TODO: the returned value of the function call to member //- TODO: variable: "fDiscManip" //... //... //- Initialize the angle and starting position of this manipulator MPoint startPoint(0.0, 0.0, 0.0); MAngle startAngle(0.0,MAngle::kDegrees); MFnDiscManip fnDisc(fDiscManip,&status); fnDisc.setCenterPoint(startPoint); fnDisc.setAngle(startAngle); return status; } //- This function is responsible to make the connection (association) //- between manipulators and the affected attributes. When a node in a scene //- is selected and user click on show manipulator tool, //- this function is called with the selected node. //- Arguments: //- dependNode - the node which is selected MStatus arrowLocatorManip::connectToDependNode(const MObject &dependNode) { MStatus status = MStatus::kSuccess; //- Find the "windDirection" plug on the selected node, which is the custom //- locator node. MFnDependencyNode fnDepNode(dependNode); MPlug rotationPlug = fnDepNode.findPlug(MString("windDirection"),&status); //- TODO: Connect the "windDirection" plug with the disc manip //... //... //- Set up affecting relationship using conversion callback function //- We are using addPlugToManipConversionCallback so that whenever //- the custom locator moves, the dis manip moves with it. /* MFnDagNode fnDagNode(dependNode); fnDagNode.getPath(fNodePath); unsigned int centerPointIndex = fnDisc.centerIndex(&status); addPlugToManipConversionCallback(centerPointIndex,(plugToManipConversionCallback)&arrowLocatorManip::centerPointCallback); */ //- The following two functions are mandatory inside your //- connectToDependNode() function status = finishAddingManips(); status = MPxManipContainer::connectToDependNode(dependNode); return status; } //- This method is plugToManipConversionCallback function //- You implement it so that a specific component of the manipulator //- will be modified automatically when some plug value changes on //- the custom locator. //- Arguments: //- manipIndex - the index of the component on the manip you want to affect, //- in this case, it is the center point of this manip //- Return Values: //- MManipData object, which represents the updated value /*MManipData arrowLocatorManip::centerPointCallback(unsigned int manipIndex) { MStatus status; //Get parent transform node of the locator node MObject parentTransform = fNodePath.transform(&status); //Get the transform node DAG path MDagPath transformPath; MDagPath::getAPathTo(parentTransform,transformPath); //Retrieve world space translation MFnTransform fnTrans(transformPath,&status); MVector translation = fnTrans.getTranslation(MSpace::kWorld,&status); MFnNumericData numData; MObject numDataValue = numData.create(MFnNumericData::k3Double,&status); status = numData.setData3Double(translation.x,translation.y,translation.z); MManipData manipData(numDataValue); return manipData; } */ //- This method is an optional method, you can use it to customize //- the drawing of your manipulator. //- If you are overriding this function, most likely you will use OpenGL calls, //- so opengl32.lib should be included in the linking libraries. //- Arguments: //- view - the 3d view where the manipulator will be drawn //- path - the Dag path of this manipulator //- style - the displaying style of this manipulator //- status - the displaying status of this manipulator, for example, it is active or not void arrowLocatorManip::draw(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus status) { MPxManipContainer::draw(view,path,style,status); } // Viewport 2.0 manipulator draw overrides void arrowLocatorManip::preDrawUI( const M3dView &view ) { //Add code to prepare specific drawing } void arrowLocatorManip::drawUI( MHWRender::MUIDrawManager& drawManager, const MHWRender::MFrameContext& frameContext ) const { //Add your specific drawing here, for now, this is empty, as //there is no specific drawing for this manipulator } ================================================ FILE: 08_Manipulators/arrowLocatorManip/Exercise - C++/arrowLocatorManipNode.h ================================================ #ifndef _arrowLocatorManipNode #define _arrowLocatorManipNode // // Copyright (C) // // File: arrowLocatorManipNode.h // // Dependency Graph Node: arrowLocatorManip // // Author: Maya Plug-in Wizard 2.0 // #include #include class arrowLocatorManip : public MPxManipContainer { public: arrowLocatorManip(); virtual ~arrowLocatorManip(); static void* creator(); static MStatus initialize(); virtual MStatus createChildren(); virtual MStatus connectToDependNode(const MObject &dependNode); virtual void draw(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus status); // MManipData centerPointCallback(unsigned int manipIndex); //callback function to update manipulator position based on node position // Viewport 2.0 manipulator draw overrides virtual void preDrawUI( const M3dView &view ); virtual void drawUI( MHWRender::MUIDrawManager& drawManager, const MHWRender::MFrameContext& frameContext) const; public: static MTypeId id; static MDagPath fDiscManip; //This variable keeps a record of the base disc manip, which we add onto our manip container static MDagPath fNodePath; //This variable is very important, it is for getting a hold of the corresponding locator node }; #endif ================================================ FILE: 08_Manipulators/arrowLocatorManip/Exercise - C++/arrowLocatorNode.cpp ================================================ // // Copyright (C) // // File: arrowLocatorNode.cpp // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #include "arrowLocatorNode.h" #include "arrowLocatorManipNode.h" #include #include #include #include #include #include #include #include #include #include // You MUST change this to a unique value!!! The id is a 32bit value used // to identify this type of node in the binary file format. // //change the following to a unique value MTypeId arrowLocator::id( 0x00002 ); MString arrowLocator::drawDbClassification("drawdb/geometry/arrowLocator"); MString arrowLocator::drawRegistrantId("arrowLocatorNodePlugin"); MObject arrowLocator::windDirection; //an array of points to draw our compass arrow in openGL static float arrow[][3] = { {2.00f, 0.0f, 0.0f} , {-3.0f, 0.0f, 2.0f} , {-2.0f, 0.0f, 0.0f} , {-3.0f, 0.0f, -2.0f}}; //indices into the arrow array static GLuint triangleIndices[] = {0,1,2,0,2,3}; arrowLocator::arrowLocator() {} arrowLocator::~arrowLocator() {} MStatus arrowLocator::compute( const MPlug& plug, MDataBlock& data ) { return MS::kSuccess; } void* arrowLocator::creator() { return new arrowLocator(); } MStatus arrowLocator::initialize() { //Here we create a new attribute type that handles units: angle, distance or time MFnUnitAttribute uAttr; windDirection = uAttr.create("windDirection", "wd", MFnUnitAttribute::kAngle, 0.0); uAttr.setStorable(true); uAttr.setWritable(true); uAttr.setReadable(true); uAttr.setKeyable(true); uAttr.setDefault(MAngle(0.0, MAngle::kDegrees)); addAttribute(windDirection); //- TODO: To make connection between your custom node and your custom //- TODO: manipulator node, you need to name your custom manipulator //- TODO: after your custom node type name, also in your custom node's initialize() //- TODO: function, you need to call MPxManipContainer::addToManipConnectTable(). //- TODO: This method adds the user defined node as an entry in the manipConnectTable //- TODO: so that when this node is selected the user can use the show manip tool to //- TODO: get the user defined manipulator associated with this node. //... return MS::kSuccess; } //- This method draw this locator in current scene by calling openGL functions //- //- Arguments: //- view -- 3D view that is being drawn into //- path -- path to this locator in the DAG //- style -- style to draw object in //- status -- selection status of object //- void arrowLocator::draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status) { MObject thisNode = thisMObject(); //We're in the draw routine, not the Compute method //therefore it is safe to grab plugs in the following way and //get/set values. You would never do something like this in //the compute method because it might start a cycle in the //graph. Here we just need the value of our winddirection //plug so that we can draw our arrow pointing the right way. MPlug wdPlug(thisNode, windDirection); MAngle angle; wdPlug.getValue(angle); //start drawing by OpenGL view.beginGL(); //If the drawing style is shaded, set color and draw opaque shape if ( ( style == M3dView::kFlatShaded ) || ( style == M3dView::kGouraudShaded ) ) { //Push to save current color settings glPushAttrib( GL_CURRENT_BIT ); if ( status == M3dView::kActive ) { view.setDrawColor( 13, M3dView::kActiveColors ); }else { view.setDrawColor( 13, M3dView::kDormantColors ); } //push the old matrix on the stack, rotate the current one, //draw the shape, then pop the old matrix off the stack for //maya to use again. glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); glPopAttrib(); } //Draw the outline of the arrow shape glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_LINE_STRIP); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); view.endGL(); } //- This method should be overridden to return true if the user supplies a bounding box routine. bool arrowLocator::isBounded() const { return true; } //- This method return the bounding box for this locator shape, //- providing a bounding box routine makes refresh and selection more efficient. // MBoundingBox arrowLocator::boundingBox() const { MPoint upLeftCorner(-3.0, 0.0, -2.0); MPoint downRightCorner(2.0, 0.0, 2.0); MBoundingBox boundingArea(upLeftCorner,downRightCorner); return boundingArea; } void arrowLocator::getRotationAngle (arrowLocatorData * data){ // Retrieve value of the angle attribute from the node MStatus status ; MObject node = thisMObject(); MPlug wdPlug(node, windDirection); MAngle angle; wdPlug.getValue(angle); data->rotateAngle = angle; } class arrowLocatorOverride : public MHWRender::MPxDrawOverride { public: static MHWRender::MPxDrawOverride* Creator(const MObject& obj) { return new arrowLocatorOverride(obj); } virtual ~arrowLocatorOverride(); virtual MHWRender::DrawAPI supportedDrawAPIs() const; virtual bool isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MBoundingBox boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MUserData* prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData); static void draw( const MHWRender::MDrawContext& context, const MUserData* data); private: arrowLocatorOverride(const MObject& obj); }; arrowLocatorOverride::arrowLocatorOverride(const MObject& obj) : MHWRender::MPxDrawOverride(obj, arrowLocatorOverride::draw) { } arrowLocatorOverride::~arrowLocatorOverride() { } MHWRender::DrawAPI arrowLocatorOverride::supportedDrawAPIs() const { return MHWRender::kOpenGL; } bool arrowLocatorOverride::isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const { return true; } MBoundingBox arrowLocatorOverride::boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const { MStatus status; MFnDependencyNode node(objPath.node(), &status); arrowLocator* locatorNode = dynamic_cast(node.userNode()); return locatorNode->boundingBox(); } MUserData* arrowLocatorOverride::prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData) { // get the node MStatus status; MFnDependencyNode node(objPath.node(), &status); if (!status) return NULL; arrowLocator* locatorNode = dynamic_cast(node.userNode()); if (!locatorNode) return NULL; // access/create user data for draw callback arrowLocatorData* data = dynamic_cast(oldData); if (!data) { data = new arrowLocatorData(); } // compute data and cache it locatorNode->getRotationAngle(data) ; return data; } void arrowLocatorOverride::draw( const MHWRender::MDrawContext& context, const MUserData* data) { MAngle rotationAngle; float color [3] ={ 0.0f, 1.0f, 0.0f } ; // data MStatus status; MHWRender::MStateManager* stateMgr = context.getStateManager(); const arrowLocatorData* locatorData = dynamic_cast(data); if (!stateMgr || !locatorData) return; if ( locatorData ) rotationAngle = locatorData->rotateAngle; // matrices const MMatrix transform = context.getMatrix(MHWRender::MFrameContext::kWorldViewMtx, &status); if (status != MStatus::kSuccess) return; const MMatrix projection = context.getMatrix(MHWRender::MFrameContext::kProjectionMtx, &status); if (status != MStatus::kSuccess) return; // get renderer MHWRender::MRenderer *theRenderer =MHWRender::MRenderer::theRenderer () ; if ( !theRenderer ) return ; if ( theRenderer->drawAPIIsOpenGL () ) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadMatrixd(transform.matrix[0]); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadMatrixd(projection.matrix[0]); glPushAttrib(GL_CURRENT_BIT); glColor4fv(color); //- Draw the outline of the arrow shape glBegin( GL_LINE_STRIP); glRotated(-rotationAngle.asDegrees(), 0.0, 1.0, 0.0); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopAttrib(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } } MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); status = plugin.registerNode( "arrowLocator", arrowLocator::id, arrowLocator::creator, arrowLocator::initialize, MPxNode::kLocatorNode,&arrowLocator::drawDbClassification); status = MHWRender::MDrawRegistry::registerDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId, arrowLocatorOverride::Creator) ; if (!status) { status.perror("registerNode"); return status; } //- Register custom manipulator for your custom locator node. //- In order to make it work, you need to name your custom manipulator //- after your custom node type name, also in your custom node's initialize() //- function, you need to call MPxManipContainer::addToManipConnectTable() status = plugin.registerNode( "arrowLocatorManip", arrowLocatorManip::id, arrowLocatorManip::creator, arrowLocatorManip::initialize,MPxNode::kManipContainer ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( arrowLocatorManip::id ); if (!status) { status.perror("deregisterNode"); return status; } status = plugin.deregisterNode( arrowLocator::id ); MHWRender::MDrawRegistry::deregisterDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId) ; if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 08_Manipulators/arrowLocatorManip/Exercise - C++/arrowLocatorNode.h ================================================ #ifndef _arrowLocatorNode #define _arrowLocatorNode // // Copyright (C) // // File: arrowLocatorNode.h // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #include #include #include #include #include // Viewport 2.0 includes #include #include #include #include #include #include #include #include #include #include #include //- Macros to use to rotate the locator #define PI 3.14159265358979 #define toDegree(rot) rot*(180.0/PI) class arrowLocatorData : public MUserData { public: MAngle rotateAngle ; arrowLocatorData() : MUserData(false) {} // don't delete after draw virtual ~arrowLocatorData() {} }; class arrowLocator : public MPxLocatorNode { public: arrowLocator(); virtual ~arrowLocator(); MStatus compute( const MPlug& plug, MDataBlock& data ); virtual void draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status); virtual MBoundingBox boundingBox() const; virtual bool isBounded() const; void getRotationAngle (arrowLocatorData * data ); static MStatus initialize(); static void* creator(); static MTypeId id; static MString drawDbClassification; static MString drawRegistrantId; static MObject windDirection; //- This is an attribute representing the rotation angle }; #endif ================================================ FILE: 08_Manipulators/arrowLocatorManip/Exercise - py/arrowLocatorManip.py ================================================ # Copyright (C) # # Author: Autodesk Developer Network #For this exercise, search for the TODO keywords and follow the instructions in #comments. If you are unsure of what you need to do, feel free to ask the instructor #or look into the solution folder. #Each #... line is a line of code you need to write or complete. import sys, math import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import maya.OpenMayaRender as OpenMayaRender import maya.OpenMayaUI as OpenMayaUI kPluginManipNodeTypeName = "arrowLocatorManip" kPluginNodeTypeName = "arrowLocator" kPluginManipNodeId = OpenMaya.MTypeId(0x00003) kPluginNodeId = OpenMaya.MTypeId(0x00002) glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() glFT = glRenderer.glFunctionTable() #pi = 3.14159265358979 #an array of points to draw our compass arrow in openGL arrow = ( [2.00, 0.0, 0.0], [-3.0, 0.0, 2.0], [-2.0, 0.0, 0.0], [-3.0, 0.0, -2.0]) #indices into the arrow array triangleIndices = [0,1,2,0,2,3] #def toDegree(rot):= rot*(180.0/PI) class arrowLocatorManip(OpenMayaMPx.MPxManipContainer): def __init__(self): OpenMayaMPx.MPxManipContainer.__init__(self) self.fDiscManip = OpenMaya.MDagPath() self.fNodePath = OpenMaya.MDagPath() #- Container manipulators are composed of one or more base manipulators. #- When base manipulators are added to a container manipulator, they are referred to #- as children of the container manipulator, and are added using the createChildren method. def createChildren(self): try: #- TODO: Create a base disc manip and #- TODO: add it into this manip container, assign #- TODO: the returned value of the function call to member #- TODO: variable: "fDiscManip" #... #- Initialize the angle and starting position of this manipulator startPoint = OpenMaya.MPoint(0.0, 0.0, 0.0) startAngle = OpenMaya.MAngle(0.0,OpenMaya.MAngle.kDegrees) fnDisc = OpenMayaUI.MFnDiscManip(self.fDiscManip) fnDisc.setCenterPoint(startPoint) fnDisc.setAngle(startAngle) except: sys.stderr.write("ERROR: arrowLocatorManip.createChildren\n") raise #- This function is responsible to make the connection (association) #- between manipulators and the affected attributes. When a node in a scene #- is selected and user click on show manipulator tool, #- this function is called with the selected node. #- Arguments: #- dependNode - the node which is selected def connectToDependNode(self, node): try: #- Find the "windDirection" plug on the selected node, which is the custom #- locator node. fnDepNode = OpenMaya.MFnDependencyNode(node) rotationPlug = fnDepNode.findPlug("windDirection") #- TODO: Connect the "windDirection" plug with the disc manip #... #... #- Set up affecting relationship using conversion callback function #- We are using addPlugToManipConversionCallback so that whenever #- the custom locator moves, the dis manip moves with it. #fnDagNode = OpenMaya.MFnDagNode(node) #fnDagNode.getPath(self.fNodePath) #centerPointIndex = fnDisc.centerIndex() #self.addPlugToManipConversion(centerPointIndex) #- The following two functions are mandatory inside your #- connectToDependNode() function self.finishAddingManips() OpenMayaMPx.MPxManipContainer.connectToDependNode(self, node) except: sys.stderr.write("ERROR: arrowLocatorManip.connectToDependNode\n") raise #- This method is an optional method, you can use it to customize #- the drawing of your manipulator. #- If you are overriding this function, most likely you will use OpenGL calls, #- so opengl32.lib should be included in the linking libraries. #- Arguments: #- view - the 3d view where the manipulator will be drawn #- path - the Dag path of this manipulator #- style - the displaying style of this manipulator #- status - the displaying status of this manipulator, for example, it is active or not def draw(self, view, path, style, status): OpenMayaMPx.MPxManipContainer.draw(self, view, path, style, status) #- This method is plugToManipConversionCallback function #- You implement it so that a specific component of the manipulator #- will be modified automatically when some plug value changes on #- the custom locator. #- Arguments: #- manipIndex - the index of the component on the manip you want to affect, #- in this case, it is the center point of this manip #- Return Values: #- MManipData object, which represents the updated value '''def plugToManipConversion( self, manipIndex ): try: #Get parent transform node of the locator node parentTransform = self.fNodePath.transform() #Get the transform node DAG path transformPath = OpenMaya.MDagPath() OpenMaya.MDagPath.getAPathTo(parentTransform,transformPath) #Retrieve world space translation fnTrans = OpenMaya.MFnTransform(transformPath) translation = OpenMaya.MVector() translation = fnTrans.getTranslation(OpenMaya.MSpace.kWorld) numData = OpenMaya.MFnNumericData() numDataValue = numData.create(OpenMaya.MFnNumericData.k3Double) status = numData.setData3Double(translation.x,translation.y,translation.z) manipData = OpenMayaUI.MManipData(numDataValue) except: sys.stderr.write("ERROR: arrowManip.plugToManipConversion\n") raise return manipData''' # Node definition class arrowLocator(OpenMayaMPx.MPxLocatorNode): windDirection = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxLocatorNode.__init__(self) def compute(self, plug, data): return OpenMaya.kUnknownParameter #- This method draw this locator in current scene by calling openGL functions #- #- Arguments: #- view -- 3D view that is being drawn into #- path -- path to this locator in the DAG #- style -- style to draw object in #- status -- selection status of object #- def draw(self, view, path, style, status): thisNode = self.thisMObject() #We're in the draw routine, not the Compute method #therefore it is safe to grab plugs in the following way and #get/set values. You would never do something like this in #the compute method because it might start a cycle in the #graph. Here we just need the value of our winddirection #plug so that we can draw our arrow pointing the right way. plug = OpenMaya.MPlug(thisNode, arrowLocator.windDirection) angle = plug.asMAngle() #start drawing by OpenGL view.beginGL() #If the drawing style is shaded, set color and draw opaque shape if ((style == OpenMayaUI.M3dView.kFlatShaded) or (style == OpenMayaUI.M3dView.kGouraudShaded)): #Push to save current color settings glFT.glPushAttrib(OpenMayaRender.MGL_CURRENT_BIT ) if (status == OpenMayaUI.M3dView.kActive): view.setDrawColor( 13, OpenMayaUI.M3dView.kActiveColors ) else: view.setDrawColor( 13, OpenMayaUI.M3dView.kDormantColors ) #push the old matrix on the stack, rotate the current one, #draw the shape, then pop the old matrix off the stack for #maya to use again. glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() glFT.glPopAttrib() #Draw the outline of the arrow shape glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() view.endGL() def isBounded(self): return True #- This method return the bounding box for this locator shape, #- providing a bounding box routine makes refresh and selection more efficient. # def boundingBox(self): upLeftCorner = OpenMaya.MPoint(-3.0, 0.0, -2.0) downRightCorner = OpenMaya.MPoint(2.0, 0.0, 2.0) boundingArea = OpenMaya.MBoundingBox(upLeftCorner,downRightCorner) return boundingArea #- This method exists to give Maya a way to create new objects #- of this type. def ManipNodeCreator(): return OpenMayaMPx.asMPxPtr( arrowLocatorManip() ) #- This method is called to create and initialize all of the attributes #- and attribute dependencies for this node type. This is only called #- once when the node type is registered with Maya. def ManipNodeInitializer(): OpenMayaMPx.MPxManipContainer.initialize() # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( arrowLocator() ) # initializer def nodeInitializer(): #Here we create a new attribute type that handles units: angle, distance or time uAttr = OpenMaya.MFnUnitAttribute() arrowLocator.windDirection = uAttr.create("windDirection", "wd", OpenMaya.MFnUnitAttribute.kAngle) uAttr.setDefault(0.0) uAttr.setStorable(True) uAttr.setWritable(True) uAttr.setReadable(True) uAttr.setKeyable(True) uAttr.setDefault(OpenMaya.MAngle(0.0, OpenMaya.MAngle.kDegrees)) arrowLocator.addAttribute(arrowLocator.windDirection) #- TODO: To make connection between your custom node and your custom #- TODO: manipulator node, you need to name your custom manipulator #- TODO: after your custom node type name, also in your custom node's initialize() #- TODO: function, you need to call MPxManipContainer::addToManipConnectTable(). #- TODO: This method adds the user defined node as an entry in the manipConnectTable #- TODO: so that when this node is selected the user can use the show manip tool to #- TODO: get the user defined manipulator associated with this node. #... # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginManipNodeTypeName, kPluginManipNodeId, ManipNodeCreator, ManipNodeInitializer, OpenMayaMPx.MPxNode.kManipContainer ) except: sys.stderr.write( "Failed to register manip node: %s" % kPluginManipNodeTypeName ) raise try: mplugin.registerNode( kPluginNodeTypeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kLocatorNode ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( kPluginManipNodeId) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginManipNodeTypeName ) raise try: mplugin.deregisterNode( kPluginNodeId ) except: sys.stderr.write( "Failed to deregister command: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 08_Manipulators/arrowLocatorManip/Solution - C++/arrowLocatorManip.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arrowLocatorManip", "arrowLocatorManip.vcxproj", "{C05EECF5-6CF1-4302-A92B-24DDB374E61A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Debug|x64.ActiveCfg = Debug|x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Debug|x64.Build.0 = Debug|x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Release|x64.ActiveCfg = Release|x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: 08_Manipulators/arrowLocatorManip/Solution - C++/arrowLocatorManip.vcxproj ================================================  Debug Win32 Debug x64 Release Win32 Release x64 {C05EECF5-6CF1-4302-A92B-24DDB374E61A} DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 DynamicLibrary v110 <_ProjectFileVersion>10.0.40219.1 Debug\ Debug\ Release\ Release\ C:\MayaAPITraining\plug-ins\ .mll /GR /GS /Gm /EHac /ZI /I "." /D "WIN32" /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDebugDLL Debug/arrowLocatorManip.pch Level3 /subsystem:windows /dll /incremental:yes /debug /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenGL32.lib;%(AdditionalDependencies) Debug\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Debug/arrowLocatorManip.pdb false Debug/arrowLocatorManip.lib /GR /GS /Gm /EHac /ZI /I "." /D "_DEBUG" /RTC1 /c %(AdditionalOptions) Disabled C:\Program Files\Autodesk\Maya2015\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Debug/arrowLocatorManip.pch Level3 /subsystem:windows /dll /incremental:yes /debug /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaRender.lib;OpenMayaUI.lib;OpenGL32.lib;%(AdditionalDependencies) C:\MayaAPITraining\plug-ins\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2015\lib;%(AdditionalLibraryDirectories) Debug/arrowLocatorManip.pdb false Debug/arrowLocatorManip.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/arrowLocatorManip.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenGL32.lib;%(AdditionalDependencies) Release\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Release/arrowLocatorManip.pdb false Release/arrowLocatorManip.lib /GR /GS /EHac /I "." /c %(AdditionalOptions) MaxSpeed C:\Program Files\Autodesk\Maya2009\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_AFXDLL;_MBCS;NT_PLUGIN;REQUIRE_IOSTREAM;%(PreprocessorDefinitions) MultiThreadedDLL Release/arrowLocatorManip.pch Level3 /subsystem:windows /incremental:no /machine:I386 /export:initializePlugin /export:uninitializePlugin %(AdditionalOptions) Foundation.lib;OpenMaya.lib;OpenMayaUI.lib;OpenGL32.lib;%(AdditionalDependencies) Release\arrowLocatorManip.mll C:\Program Files\Autodesk\Maya2009\lib;%(AdditionalLibraryDirectories) Release/arrowLocatorManip.pdb false Release/arrowLocatorManip.lib ================================================ FILE: 08_Manipulators/arrowLocatorManip/Solution - C++/arrowLocatorManipNode.cpp ================================================ // // Copyright (C) // // File: arrowLocatorManipNode.cpp // // Dependency Graph Node: arrowLocatorManip // // Author: Maya Plug-in Wizard 2.0 // #include "arrowLocatorManipNode.h" #include #include #include #include #include #include #include //- You MUST change this to a unique value!!! The id is a 32bit value used //- to identify this type of node in the binary file format. //- //- change the following to a unique value and then erase this line MTypeId arrowLocatorManip::id( 0x00003 ); MDagPath arrowLocatorManip::fDiscManip; MDagPath arrowLocatorManip::fNodePath; arrowLocatorManip::arrowLocatorManip() {} arrowLocatorManip::~arrowLocatorManip() {} //- This method exists to give Maya a way to create new objects //- of this type. //- //- Return Value: //- a new object of this type //- void* arrowLocatorManip::creator() { return new arrowLocatorManip(); } //- This method is called to create and initialize all of the attributes //- and attribute dependencies for this node type. This is only called //- once when the node type is registered with Maya. //- //- Return Values: //- MS::kSuccess //- MS::kFailure MStatus arrowLocatorManip::initialize() { MStatus stat; stat = MPxManipContainer::initialize(); return stat; } //- Container manipulators are composed of one or more base manipulators. //- When base manipulators are added to a container manipulator, they are referred to //- as children of the container manipulator, and are added using the createChildren method. MStatus arrowLocatorManip::createChildren() { MStatus status = MStatus::kSuccess; //- Add a base disc manip into this manip container MString manipName("angleManip"); MString angleName("yRotation"); fDiscManip = addDiscManip(manipName,angleName); //- Initialize the angle and starting position of this manipulator MPoint startPoint(0.0, 0.0, 0.0); MAngle startAngle(0.0,MAngle::kDegrees); MFnDiscManip fnDisc(fDiscManip,&status); fnDisc.setCenterPoint(startPoint); fnDisc.setAngle(startAngle); return status; } //- This function is responsible to make the connection (association) //- between manipulators and the affected attributes. When a node in a scene //- is selected and user click on show manipulator tool, //- this function is called with the selected node. //- Arguments: //- dependNode - the node which is selected MStatus arrowLocatorManip::connectToDependNode(const MObject &dependNode) { MStatus status = MStatus::kSuccess; //- Find the "windDirection" plug on the selected node, which is the custom //- locator node. MFnDependencyNode fnDepNode(dependNode); MPlug rotationPlug = fnDepNode.findPlug(MString("windDirection"),&status); //- Connect the "windDirection" plug with the base disc manip MFnDiscManip fnDisc(fDiscManip,&status); status = fnDisc.connectToAnglePlug(rotationPlug); //- Set up affecting relationship using conversion callback function //- We are using addPlugToManipConversionCallback so that whenever //- the custom locator moves, the dis manip moves with it. MFnDagNode fnDagNode(dependNode); fnDagNode.getPath(fNodePath); unsigned int centerPointIndex = fnDisc.centerIndex(&status); addPlugToManipConversionCallback(centerPointIndex,(plugToManipConversionCallback)&arrowLocatorManip::centerPointCallback); //- The following two functions are mandatory inside your //- connectToDependNode() function status = finishAddingManips(); status = MPxManipContainer::connectToDependNode(dependNode); return status; } //- This method is plugToManipConversionCallback function //- You implement it so that a specific component of the manipulator //- will be modified automatically when some plug value changes on //- the custom locator. //- Arguments: //- manipIndex - the index of the component on the manip you want to affect, //- in this case, it is the center point of this manip //- Return Values: //- MManipData object, which represents the updated value MManipData arrowLocatorManip::centerPointCallback(unsigned int manipIndex) { MStatus status; //Get parent transform node of the locator node MObject parentTransform = fNodePath.transform(&status); //Get the transform node DAG path MDagPath transformPath; MDagPath::getAPathTo(parentTransform,transformPath); //Retrieve world space translation MFnTransform fnTrans(transformPath,&status); MVector translation = fnTrans.getTranslation(MSpace::kWorld,&status); MFnNumericData numData; MObject numDataValue = numData.create(MFnNumericData::k3Double,&status); status = numData.setData3Double(translation.x,translation.y,translation.z); MManipData manipData(numDataValue); return manipData; } //- This method is an optional method, you can use it to customize //- the drawing of your manipulator. //- If you are overriding this function, most likely you will use OpenGL calls, //- so opengl32.lib should be included in the linking libraries. //- Arguments: //- view - the 3d view where the manipulator will be drawn //- path - the Dag path of this manipulator //- style - the displaying style of this manipulator //- status - the displaying status of this manipulator, for example, it is active or not void arrowLocatorManip::draw(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus status) { MPxManipContainer::draw(view,path,style,status); } // Viewport 2.0 manipulator draw overrides void arrowLocatorManip::preDrawUI( const M3dView &view ) { //Add code to prepare specific drawing } void arrowLocatorManip::drawUI( MHWRender::MUIDrawManager& drawManager, const MHWRender::MFrameContext& frameContext ) const { //Add your specific drawing here, for now, this is empty, as //there is no specific drawing for this manipulator } ================================================ FILE: 08_Manipulators/arrowLocatorManip/Solution - C++/arrowLocatorManipNode.h ================================================ #ifndef _arrowLocatorManipNode #define _arrowLocatorManipNode // // Copyright (C) // // File: arrowLocatorManipNode.h // // Dependency Graph Node: arrowLocatorManip // // Author: Maya Plug-in Wizard 2.0 // #include #include class arrowLocatorManip : public MPxManipContainer { public: arrowLocatorManip(); virtual ~arrowLocatorManip(); static void* creator(); static MStatus initialize(); virtual MStatus createChildren(); virtual MStatus connectToDependNode(const MObject &dependNode); virtual void draw(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus status); MManipData centerPointCallback(unsigned int manipIndex); //callback function to update manipulator position based on node position // Viewport 2.0 manipulator draw overrides virtual void preDrawUI( const M3dView &view ); virtual void drawUI( MHWRender::MUIDrawManager& drawManager, const MHWRender::MFrameContext& frameContext) const; public: static MTypeId id; static MDagPath fDiscManip; //This variable keeps a record of the base disc manip, which we add onto our manip container static MDagPath fNodePath; //This variable is very important, it is for getting a hold of the corresponding locator node }; #endif ================================================ FILE: 08_Manipulators/arrowLocatorManip/Solution - C++/arrowLocatorNode.cpp ================================================ // // Copyright (C) // // File: arrowLocatorNode.cpp // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #include "arrowLocatorNode.h" #include "arrowLocatorManipNode.h" #include #include #include #include #include #include #include #include #include #include // You MUST change this to a unique value!!! The id is a 32bit value used // to identify this type of node in the binary file format. // //change the following to a unique value MTypeId arrowLocator::id( 0x00002 ); MString arrowLocator::drawDbClassification("drawdb/geometry/arrowLocator"); MString arrowLocator::drawRegistrantId("arrowLocatorNodePlugin"); MObject arrowLocator::windDirection; //an array of points to draw our compass arrow in openGL static float arrow[][3] = { {2.00f, 0.0f, 0.0f} , {-3.0f, 0.0f, 2.0f} , {-2.0f, 0.0f, 0.0f} , {-3.0f, 0.0f, -2.0f}}; //indices into the arrow array static GLuint triangleIndices[] = {0,1,2,0,2,3}; MStatus arrowLocator::compute( const MPlug& plug, MDataBlock& data ) { return MS::kSuccess; } MStatus arrowLocator::initialize() { //Here we create a new attribute type that handles units: angle, distance or time MFnUnitAttribute uAttr; windDirection = uAttr.create("windDirection", "wd", MFnUnitAttribute::kAngle, 0.0); uAttr.setStorable(true); uAttr.setWritable(true); uAttr.setReadable(true); uAttr.setKeyable(true); uAttr.setDefault(MAngle(0.0, MAngle::kDegrees)); addAttribute(windDirection); //- To make connection between your custom node and your custom //- manipulator node, you need to name your custom manipulator //- after your custom node type name, also in your custom node's initialize() //- function, you need to call MPxManipContainer::addToManipConnectTable(). //- This method adds the user defined node as an entry in the manipConnectTable //- so that when this node is selected the user can use the show manip tool to //- get the user defined manipulator associated with this node MPxManipContainer::addToManipConnectTable(id); return MS::kSuccess; } //- This method draw this locator in current scene by calling openGL functions //- //- Arguments: //- view -- 3D view that is being drawn into //- path -- path to this locator in the DAG //- style -- style to draw object in //- status -- selection status of object //- void arrowLocator::draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status) { MObject thisNode = thisMObject(); //We're in the draw routine, not the Compute method //therefore it is safe to grab plugs in the following way and //get/set values. You would never do something like this in //the compute method because it might start a cycle in the //graph. Here we just need the value of our winddirection //plug so that we can draw our arrow pointing the right way. MPlug wdPlug(thisNode, windDirection); MAngle angle; wdPlug.getValue(angle); //start drawing by OpenGL view.beginGL(); //If the drawing style is shaded, set color and draw opaque shape if ( ( style == M3dView::kFlatShaded ) || ( style == M3dView::kGouraudShaded ) ) { //Push to save current color settings glPushAttrib( GL_CURRENT_BIT ); if ( status == M3dView::kActive ) { view.setDrawColor( 13, M3dView::kActiveColors ); }else { view.setDrawColor( 13, M3dView::kDormantColors ); } //push the old matrix on the stack, rotate the current one, //draw the shape, then pop the old matrix off the stack for //maya to use again. glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_TRIANGLE_FAN ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); glPopAttrib(); } //Draw the outline of the arrow shape glPushMatrix(); glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_LINE_STRIP); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); view.endGL(); } //- This method should be overridden to return true if the user supplies a bounding box routine. bool arrowLocator::isBounded() const { return true; } //- This method return the bounding box for this locator shape, //- providing a bounding box routine makes refresh and selection more efficient. // MBoundingBox arrowLocator::boundingBox() const { MPoint upLeftCorner(-3.0, 0.0, -2.0); MPoint downRightCorner(2.0, 0.0, 2.0); MBoundingBox boundingArea(upLeftCorner,downRightCorner); return boundingArea; } void arrowLocator::getRotationAngle (arrowLocatorData * data){ // Retrieve value of the angle attribute from the node MStatus status ; MObject node = thisMObject(); MPlug wdPlug(node, windDirection); MAngle angle; wdPlug.getValue(angle); data->rotateAngle = angle; } class arrowLocatorOverride : public MHWRender::MPxDrawOverride { public: static MHWRender::MPxDrawOverride* Creator(const MObject& obj) { return new arrowLocatorOverride(obj); } virtual ~arrowLocatorOverride(); virtual MHWRender::DrawAPI supportedDrawAPIs() const; virtual bool isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MBoundingBox boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const; virtual MUserData* prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData); static void draw( const MHWRender::MDrawContext& context, const MUserData* data); private: arrowLocatorOverride(const MObject& obj); }; arrowLocatorOverride::arrowLocatorOverride(const MObject& obj) : MHWRender::MPxDrawOverride(obj, arrowLocatorOverride::draw) { } arrowLocatorOverride::~arrowLocatorOverride() { } MHWRender::DrawAPI arrowLocatorOverride::supportedDrawAPIs() const { return MHWRender::kOpenGL; } bool arrowLocatorOverride::isBounded( const MDagPath& objPath, const MDagPath& cameraPath) const { return true; } MBoundingBox arrowLocatorOverride::boundingBox( const MDagPath& objPath, const MDagPath& cameraPath) const { MStatus status; MFnDependencyNode node(objPath.node(), &status); arrowLocator* locatorNode = dynamic_cast(node.userNode()); return locatorNode->boundingBox(); } MUserData* arrowLocatorOverride::prepareForDraw( const MDagPath& objPath, const MDagPath& cameraPath, const MHWRender::MFrameContext& frameContext, MUserData* oldData) { // get the node MStatus status; MFnDependencyNode node(objPath.node(), &status); if (!status) return NULL; arrowLocator* locatorNode = dynamic_cast(node.userNode()); if (!locatorNode) return NULL; // access/create user data for draw callback arrowLocatorData* data = dynamic_cast(oldData); if (!data) { data = new arrowLocatorData(); } // compute data and cache it locatorNode->getRotationAngle(data) ; return data; } void arrowLocatorOverride::draw( const MHWRender::MDrawContext& context, const MUserData* data) { MAngle rotationAngle; float color [3] ={ 0.0f, 1.0f, 0.0f } ; // data MStatus status; MHWRender::MStateManager* stateMgr = context.getStateManager(); const arrowLocatorData* locatorData = dynamic_cast(data); if (!stateMgr || !locatorData) return; if ( locatorData ) rotationAngle = locatorData->rotateAngle; // matrices const MMatrix transform = context.getMatrix(MHWRender::MFrameContext::kWorldViewMtx, &status); if (status != MStatus::kSuccess) return; const MMatrix projection = context.getMatrix(MHWRender::MFrameContext::kProjectionMtx, &status); if (status != MStatus::kSuccess) return; // get renderer MHWRender::MRenderer *theRenderer =MHWRender::MRenderer::theRenderer () ; if ( !theRenderer ) return ; if ( theRenderer->drawAPIIsOpenGL () ) { glPushAttrib(GL_CURRENT_BIT); glColor4fv(color); glPushMatrix(); glRotated(-rotationAngle.asDegrees(), 0.0, 1.0, 0.0); glBegin( GL_LINE_STRIP); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]); glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]); glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]); glEnd(); glPopMatrix(); } } MStatus initializePlugin( MObject obj ) // // Description: // this method is called when the plug-in is loaded into Maya. It // registers all of the services that this plug-in provides with // Maya. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj, "", "2009", "Any"); status = plugin.registerNode( "arrowLocator", arrowLocator::id, arrowLocator::creator, arrowLocator::initialize, MPxNode::kLocatorNode,&arrowLocator::drawDbClassification); status = MHWRender::MDrawRegistry::registerDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId, arrowLocatorOverride::Creator) ; if (!status) { status.perror("registerNode"); return status; } //- Register custom manipulator for your custom locator node. //- In order to make it work, you need to name your custom manipulator //- after your custom node type name, also in your custom node's initialize() //- function, you need to call MPxManipContainer::addToManipConnectTable() status = plugin.registerNode( "arrowLocatorManip", arrowLocatorManip::id, arrowLocatorManip::creator, arrowLocatorManip::initialize,MPxNode::kManipContainer ); if (!status) { status.perror("registerNode"); return status; } return status; } MStatus uninitializePlugin( MObject obj) // // Description: // this method is called when the plug-in is unloaded from Maya. It // deregisters all of the services that it was providing. // // Arguments: // obj - a handle to the plug-in object (use MFnPlugin to access it) // { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( arrowLocatorManip::id ); if (!status) { status.perror("deregisterNode"); return status; } status = plugin.deregisterNode( arrowLocator::id ); MHWRender::MDrawRegistry::deregisterDrawOverrideCreator ( arrowLocator::drawDbClassification, arrowLocator::drawRegistrantId) ; if (!status) { status.perror("deregisterNode"); return status; } return status; } ================================================ FILE: 08_Manipulators/arrowLocatorManip/Solution - C++/arrowLocatorNode.h ================================================ #ifndef _arrowLocatorNode #define _arrowLocatorNode // // Copyright (C) // // File: arrowLocatorNode.h // // Dependency Graph Node: arrowLocator // // Author: Maya Plug-in Wizard 2.0 // #include #include #include #include #include // Viewport 2.0 includes #include #include #include #include #include #include #include #include #include #include #include //- Macros to use to rotate the locator #define PI 3.14159265358979 #define toDegree(rot) rot*(180.0/PI) class arrowLocatorData : public MUserData { public: MAngle rotateAngle ; arrowLocatorData() : MUserData(false) {} // don't delete after draw virtual ~arrowLocatorData() {} }; class arrowLocator : public MPxLocatorNode { public: arrowLocator() {} virtual ~arrowLocator() {} MStatus compute( const MPlug& plug, MDataBlock& data ); virtual void draw(M3dView &view,const MDagPath & path,M3dView::DisplayStyle style, M3dView::DisplayStatus status); virtual MBoundingBox boundingBox() const; virtual bool isBounded() const; void getRotationAngle (arrowLocatorData * data ); static MStatus initialize(); static void* creator() { return new arrowLocator(); } static MTypeId id; static MString drawDbClassification; static MString drawRegistrantId; static MObject windDirection; //- This is an attribute representing the rotation angle }; #endif ================================================ FILE: 08_Manipulators/arrowLocatorManip/Solution - py/arrowLocatorManip.py ================================================ # # Copyright (C) # # File: arrowLocatorManip.py # # Dependency Graph Node: # # Author: Maya Plug-in Wizard 2.0 import sys, math import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import maya.OpenMayaRender as OpenMayaRender import maya.OpenMayaUI as OpenMayaUI kPluginManipNodeTypeName = "arrowLocatorManip" kPluginNodeTypeName = "arrowLocator" kPluginManipNodeId = OpenMaya.MTypeId(0x00003) kPluginNodeId = OpenMaya.MTypeId(0x00002) glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() glFT = glRenderer.glFunctionTable() #an array of points to draw our compass arrow in openGL arrow = ( [2.00, 0.0, 0.0], [-3.0, 0.0, 2.0], [-2.0, 0.0, 0.0], [-3.0, 0.0, -2.0]) #indices into the arrow array triangleIndices = [0,1,2,0,2,3] class arrowLocatorManip(OpenMayaMPx.MPxManipContainer): def __init__(self): OpenMayaMPx.MPxManipContainer.__init__(self) self.fDiscManip = OpenMaya.MDagPath() self.fNodePath = OpenMaya.MDagPath() #- Container manipulators are composed of one or more base manipulators. #- When base manipulators are added to a container manipulator, they are referred to #- as children of the container manipulator, and are added using the createChildren method. def createChildren(self): try: #- Add a base disc manip into this manip container self.fDiscManip = self.addDiscManip("angleManip","yRotation") #- Initialize the angle and starting position of this manipulator startPoint = OpenMaya.MPoint(0.0, 0.0, 0.0) startAngle = OpenMaya.MAngle(0.0,OpenMaya.MAngle.kDegrees) fnDisc = OpenMayaUI.MFnDiscManip(self.fDiscManip) fnDisc.setCenterPoint(startPoint) fnDisc.setAngle(startAngle) except: sys.stderr.write("ERROR: arrowLocatorManip.createChildren\n") raise #- This function is responsible to make the connection (association) #- between manipulators and the affected attributes. When a node in a scene #- is selected and user click on show manipulator tool, #- this function is called with the selected node. #- Arguments: #- dependNode - the node which is selected def connectToDependNode(self, node): try: #- Find the "windDirection" plug on the selected node, which is the custom #- locator node. fnDepNode = OpenMaya.MFnDependencyNode(node) rotationPlug = fnDepNode.findPlug("windDirection") #- Connect the "windDirection" plug with the base disc manip fnDisc = OpenMayaUI.MFnDiscManip(self.fDiscManip) fnDisc.connectToAnglePlug(rotationPlug) #- Set up affecting relationship using conversion callback function #- We are using addPlugToManipConversionCallback so that whenever #- the custom locator moves, the dis manip moves with it. fnDagNode = OpenMaya.MFnDagNode(node) fnDagNode.getPath(self.fNodePath) centerPointIndex = fnDisc.centerIndex() #NOT Available in Python. self.addPlugToManipConversion(centerPointIndex) #- The following two functions are mandatory inside your #- connectToDependNode() function self.finishAddingManips() OpenMayaMPx.MPxManipContainer.connectToDependNode(self, node) except: sys.stderr.write("ERROR: arrowLocatorManip.connectToDependNode\n") raise #- This method is an optional method, you can use it to customize #- the drawing of your manipulator. #- If you are overriding this function, most likely you will use OpenGL calls, #- so opengl32.lib should be included in the linking libraries. #- Arguments: #- view - the 3d view where the manipulator will be drawn #- path - the Dag path of this manipulator #- style - the displaying style of this manipulator #- status - the displaying status of this manipulator, for example, it is active or not def draw(self, view, path, style, status): OpenMayaMPx.MPxManipContainer.draw(self, view, path, style, status) #- This method is plugToManipConversionCallback function #- You implement it so that a specific component of the manipulator #- will be modified automatically when some plug value changes on #- the custom locator. #- Arguments: #- manipIndex - the index of the component on the manip you want to affect, #- in this case, it is the center point of this manip #- Return Values: #- MManipData object, which represents the updated value def plugToManipConversion( self, manipIndex ): try: #Get parent transform node of the locator node parentTransform = self.fNodePath.transform() #Get the transform node DAG path transformPath = OpenMaya.MDagPath() OpenMaya.MDagPath.getAPathTo(parentTransform,transformPath) #Retrieve world space translation fnTrans = OpenMaya.MFnTransform(transformPath) translation = OpenMaya.MVector() translation = fnTrans.getTranslation(OpenMaya.MSpace.kWorld) numData = OpenMaya.MFnNumericData() numDataValue = numData.create(OpenMaya.MFnNumericData.k3Double) status = numData.setData3Double(translation.x,translation.y,translation.z) manipData = OpenMayaUI.MManipData(numDataValue) except: sys.stderr.write("ERROR: arrowManip.plugToManipConversion\n") raise return manipData # Node definition class arrowLocator(OpenMayaMPx.MPxLocatorNode): windDirection = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxLocatorNode.__init__(self) def compute(self, plug, data): return OpenMaya.kUnknownParameter #- This method draw this locator in current scene by calling openGL functions #- #- Arguments: #- view -- 3D view that is being drawn into #- path -- path to this locator in the DAG #- style -- style to draw object in #- status -- selection status of object #- def draw(self, view, path, style, status): thisNode = self.thisMObject() #We're in the draw routine, not the Compute method #therefore it is safe to grab plugs in the following way and #get/set values. You would never do something like this in #the compute method because it might start a cycle in the #graph. Here we just need the value of our winddirection #plug so that we can draw our arrow pointing the right way. plug = OpenMaya.MPlug(thisNode, arrowLocator.windDirection) angle = plug.asMAngle() #start drawing by OpenGL view.beginGL() #If the drawing style is shaded, set color and draw opaque shape if ((style == OpenMayaUI.M3dView.kFlatShaded) or (style == OpenMayaUI.M3dView.kGouraudShaded)): #Push to save current color settings glFT.glPushAttrib(OpenMayaRender.MGL_CURRENT_BIT ) if (status == OpenMayaUI.M3dView.kActive): view.setDrawColor( 13, OpenMayaUI.M3dView.kActiveColors ) else: view.setDrawColor( 13, OpenMayaUI.M3dView.kDormantColors ) #push the old matrix on the stack, rotate the current one, #draw the shape, then pop the old matrix off the stack for #maya to use again. glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_TRIANGLE_FAN ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() glFT.glPopAttrib() #Draw the outline of the arrow shape glFT.glPushMatrix() glFT.glRotated(-angle.asDegrees(), 0.0, 1.0, 0.0) glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glVertex3f(arrow[1][0],arrow[1][1],arrow[1][2]) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glEnd() glFT.glBegin( OpenMayaRender.MGL_LINE_STRIP ) glFT.glVertex3f(arrow[2][0],arrow[2][1],arrow[2][2]) glFT.glVertex3f(arrow[3][0],arrow[3][1],arrow[3][2]) glFT.glVertex3f(arrow[0][0],arrow[0][1],arrow[0][2]) glFT.glEnd() glFT.glPopMatrix() view.endGL() def isBounded(self): return True #- This method return the bounding box for this locator shape, #- providing a bounding box routine makes refresh and selection more efficient. # def boundingBox(self): upLeftCorner = OpenMaya.MPoint(-3.0, 0.0, -2.0) downRightCorner = OpenMaya.MPoint(2.0, 0.0, 2.0) boundingArea = OpenMaya.MBoundingBox(upLeftCorner,downRightCorner) return boundingArea #- This method exists to give Maya a way to create new objects #- of this type. def ManipNodeCreator(): return OpenMayaMPx.asMPxPtr( arrowLocatorManip() ) #- This method is called to create and initialize all of the attributes #- and attribute dependencies for this node type. This is only called #- once when the node type is registered with Maya. def ManipNodeInitializer(): OpenMayaMPx.MPxManipContainer.initialize() # Creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( arrowLocator() ) # initializer def nodeInitializer(): #Here we create a new attribute type that handles units: angle, distance or time uAttr = OpenMaya.MFnUnitAttribute() arrowLocator.windDirection = uAttr.create("windDirection", "wd", OpenMaya.MFnUnitAttribute.kAngle) uAttr.setDefault(0.0) uAttr.setStorable(True) uAttr.setWritable(True) uAttr.setReadable(True) uAttr.setKeyable(True) uAttr.setDefault(OpenMaya.MAngle(0.0, OpenMaya.MAngle.kDegrees)) arrowLocator.addAttribute(arrowLocator.windDirection) #- To make connection between your custom node and your custom #- manipulator node, you need to name your custom manipulator #- after your custom node type name, also in your custom node's initialize() #- function, you need to call MPxManipContainer::addToManipConnectTable(). #- This method adds the user defined node as an entry in the manipConnectTable #- so that when this node is selected the user can use the show manip tool to #- get the user defined manipulator associated with this node OpenMayaMPx.MPxManipContainer.addToManipConnectTable(kPluginNodeId) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginManipNodeTypeName, kPluginManipNodeId, ManipNodeCreator, ManipNodeInitializer, OpenMayaMPx.MPxNode.kManipContainer ) except: sys.stderr.write( "Failed to register manip node: %s" % kPluginManipNodeTypeName ) raise try: mplugin.registerNode( kPluginNodeTypeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kLocatorNode ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( kPluginManipNodeId) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginManipNodeTypeName ) raise try: mplugin.deregisterNode( kPluginNodeId ) except: sys.stderr.write( "Failed to deregister command: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 09_PythonAPI/helloWorld/Exercise - py/helloWorldCmd.py ================================================ # # Copyright (C) # # File: helloWorld.py # # Dependency Graph Node: arrowLocator # # Author: # #- Python script to execute to test the sample in the Maya script editor # import maya # maya.cmds.loadPlugin("helloWorldCmd.py") # maya.cmds.spHelloWorld() #- TODO: Import all the necessary modules here #import sys #import maya.OpenMaya as OpenMaya #import maya.OpenMayaMPx as OpenMayaMPx kPluginCmdName = "spHelloWorld" # Command class scriptedCommand(OpenMayaMPx.MPxCommand): #- TODO: Add Implementation of __init__(self) and doIt(self,argList) # def __init__(self): # OpenMayaMPx.MPxCommand.__init__(self) # # def doIt(self,argList): # print "Hello World!" # Creator def cmdCreator(): #- TODO: Implement the creator and apply asMPxPtr() to it # return OpenMayaMPx.asMPxPtr( scriptedCommand() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Register this custom command # mplugin.registerCommand( kPluginCmdName, cmdCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Deregister this custom command # mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) raise ================================================ FILE: 09_PythonAPI/helloWorld/Solution - py/helloWorldCmd.py ================================================ # # Copyright (C) # # File: helloWorld.py # # Dependency Graph Node: arrowLocator # # Author: # #- Python script to execute to test the sample in the Maya script editor # import maya # maya.cmds.loadPlugin("helloWorldCmd.py") # maya.cmds.spHelloWorld() #- Import all the necessary modules here import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginCmdName = "spHelloWorld" # Command class scriptedCommand(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self,argList): print "Hello World!" # Creator def cmdCreator(): return OpenMayaMPx.asMPxPtr( scriptedCommand() ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) raise ================================================ FILE: 09_PythonAPI/sineNode/Exercise - py/sineNode.py ================================================ # # Copyright (C) # # File: sineNode.py # # Dependency Graph Node: sineNode # # Author: # #- TODO: Import all the necessary modules here #import math, sys #import maya.OpenMaya as OpenMaya #import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "spSineNode" #- TODO: Allocate a type id for your custom node #sineNodeId = OpenMaya.MTypeId(0x87000) # Node definition class sineNode(OpenMayaMPx.MPxNode): #- TODO: Define your class variables # input = OpenMaya.MObject() # output = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) #- TODO: Add Implementation of compute # def compute(self,plug,dataBlock): if ( plug == sineNode.output ): #- TODO: Get handle of input attribute and data from the handle # dataHandle = dataBlock.inputValue( sineNode.input ) # inputFloat = dataHandle.asFloat() result = math.sin( inputFloat ) * 10.0 outputHandle = dataBlock.outputValue( sineNode.output ) outputHandle.setFloat( result ) dataBlock.setClean( plug ) return OpenMaya.kUnknownParameter # creator def nodeCreator(): #- TODO: Implement the creator and apply asMPxPtr() to it # return OpenMayaMPx.asMPxPtr( sineNode() ) # initializer def nodeInitializer(): # input #- TODO: Create an input attribute with name "input" # nAttr = OpenMaya.MFnNumericAttribute() # sineNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) # output nAttr = OpenMaya.MFnNumericAttribute() sineNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) nAttr.setWritable(1) #- TODO: Add attributes and set up relationship # sineNode.addAttribute( sineNode.input ) # sineNode.addAttribute( sineNode.output ) # sineNode.attributeAffects( sineNode.input, sineNode.output ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Register this custom node # mplugin.registerNode( kPluginNodeTypeName, sineNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: #- TODO: Deregister this custom node # mplugin.deregisterNode( sineNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 09_PythonAPI/sineNode/Solution - py/sineNode.py ================================================ # # Copyright (C) # # File: sineNode.py # # Dependency Graph Node: sineNode # # Author: # import math, sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "spSineNode" sineNodeId = OpenMaya.MTypeId(0x87000) # Node definition class sineNode(OpenMayaMPx.MPxNode): # class variables input = OpenMaya.MObject() output = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) def compute(self,plug,dataBlock): if ( plug == sineNode.output ): dataHandle = dataBlock.inputValue( sineNode.input ) inputFloat = dataHandle.asFloat() result = math.sin( inputFloat ) * 10.0 outputHandle = dataBlock.outputValue( sineNode.output ) outputHandle.setFloat( result ) dataBlock.setClean( plug ) return OpenMaya.kUnknownParameter # creator def nodeCreator(): return OpenMayaMPx.asMPxPtr( sineNode() ) # Initializer def nodeInitializer(): # input nAttr = OpenMaya.MFnNumericAttribute() sineNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) # output nAttr = OpenMaya.MFnNumericAttribute() sineNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1) nAttr.setWritable(1) # add attributes sineNode.addAttribute( sineNode.input ) sineNode.addAttribute( sineNode.output ) sineNode.attributeAffects( sineNode.input, sineNode.output ) # Initialize the script plug-in def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode( kPluginNodeTypeName, sineNodeId, nodeCreator, nodeInitializer ) except: sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName ) raise # Uninitialize the script plug-in def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode( sineNodeId ) except: sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName ) raise ================================================ FILE: 09_PythonAPI/sineNode/sineNode-setup.mel ================================================ polySphere; createNode spSineNode -n sine1; connectAttr time1.outTime sine1.input; connectAttr time1.outTime pSphere1.translateX; connectAttr sine1.output pSphere1.translateY; ================================================ FILE: 10_PythonAdvanced/examples/ShotServer.py ================================================ #- # ========================================================================== # Copyright (C) 2008 Autodesk, Inc. and/or its licensors. All # rights reserved. # # The coded instructions, statements, computer programs, and/or related # material (collectively the "Data") in these files contain unpublished # information proprietary to Autodesk, Inc. ("Autodesk") and/or its # licensors, which is protected by U.S. and Canadian federal copyright # law and by international treaties. # # The Data is provided for use exclusively by You. You have the right # to use, modify, and incorporate this Data into other products for # purposes authorized by the Autodesk software license agreement, # without fee. # # The copyright notices in the Software and this entire statement, # including the above license grant, this restriction and the # following disclaimer, must be included in all copies of the # Software, in whole or in part, and all derivative works of # the Software, unless such copies or derivative works are solely # in the form of machine-executable object code generated by a # source language processor. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY # OR PROBABILITY OF SUCH DAMAGES. # # ========================================================================== #+ # This is a simple example of how to set up a client/server system within # Python. The example server takes requests for shots to work on and # responds with the information for a new shot. # # To try out the example, do the following: # # 1) Change the SERVER setting below to reflect the system on which you # will run the server. # # 2) On the server system, execute the startServer() function. # # 3) On a client system, create a Shot instance to serve as your "old" # shot (you can use the 'makeSampleShot' function if you're lazy) # and pass it to the requestNewShot() function. That will send your # request to the server and return a new Shot instance from the server. # # 4) Print the 'shot' field of the returned Shot and you'll see that it # is different from the old shot. # # 5) On any system, execute the stopServer() function to shut down the # server. # # In addition, saveShotDefaults() can be used to save a shot to the # 'shotDefaults' file in the user's home directory. You can then exit # Maya/Python and the next time you run it use loadShotDefaults() to # get the shot info back. # The SERVER setting below assumes that the server and the clients are # all running on the same machine. If that is not the case then change # then set SERVER to be either the name or IP address of the machine on # which the server is running. SERVER = 'localhost' PORT = 50507 import cPickle import os import socket #----------------- Classes ------------------------ class Shot: def __init__(self): self.user = None self.production = None self.sequence = None self.scene = None self.shot = None class ShotRequest: def __init__(self): self.type = None self.shot = None #----------------- Save/Restore Shot Info --------- # Save the shot to the user's 'shotDefaults' file. def saveShotDefaults(shotInfo): try: home = os.environ['HOME'] fileName = os.path.join(home, 'shotDefaults') file = open(fileName, 'wb') pickler = cPickle.Pickler(file, 2) pickler.dump(shotInfo) file.close() except: pass # Load the shot info from the user's 'shotDefaults' file. def loadShotDefaults(): try: home = os.environ['HOME'] fileName = os.path.join(home, 'shotDefaults') file = open(fileName, 'rb') unpickler = cPickle.Unpickler(file) shotInfo = unpickler.load() file.close() except: # We couldn't get the user's defaults so # let's just create an empty Shot. shotInfo = Shot() return shotInfo #----------------- Server Functions --------------- # Start the shot server. def startServer(): # Create a socket for listening for requests. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = '' port = PORT s.bind((host, port)) s.listen(5) while True: # Wait for a sender to connect. conn, sender = s.accept() # Get the request string and unpickle it. requestStr = conn.recv(4096) request = cPickle.loads(requestStr) # Handle the request. if request.type == 'Stop': conn.close() break elif request.type == 'NewShot': newShot = _getNextShot(request.shot) # Pickle the new shot into a string # and send it back to the requestor. responseStr = cPickle.dumps(newShot) conn.send(responseStr) # Close the connection to the client. conn.close() # Close our listening socket. s.close() # Shut down the shot server. def stopServer(): # Connect to the server's socket. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = SERVER port = PORT s.connect((host, port)) # Create a stop request. request = ShotRequest() request.type = 'Stop' # Pickle the request into a string and send it # to the server. requestStr = cPickle.dumps(request, 2) s.send(requestStr) # There won't be a response, so close the connection. s.close() # Trivial implementation which simply increments # the shot and scene fields. A proper implementation # would maintain a database of shots and search it # for the next available one. def _getNextShot(oldShot): if oldShot.shot == None: oldShot.shot = 1 else: print "%s completed shot (%s, %d, %d, %d)" % (oldShot.user, oldShot.production, oldShot.scene, oldShot.sequence, oldShot.shot) oldShot.shot += 1 if oldShot.shot > 8: oldShot.shot = 1 if oldShot.scene == None: oldShot.scene = 1 else: oldShot.scene += 1 print "%s assigned shot (%s, %d, %d, %d)" % (oldShot.user, oldShot.production, oldShot.scene, oldShot.sequence, oldShot.shot) return oldShot #----------------- Client Functions --------------- # Convenience function to generate a sample Shot. def makeSampleShot(): shot = Shot() shot.user = "Kristine Middlemiss" shot.production = "2009 Games Developer Conference" shot.sequence = 1 shot.scene = 1 shot.shot = 0 return shot # Convenience function to display a Shot object's contents. def dumpShot(shot): print print "User: %s" % shot.user print "Production: %s" % shot.production print "Scene: %d" % shot.scene print "Sequence: %d" % shot.sequence print "Shot: %d" % shot.shot print # Request a new shot to work on. You have to pass in your old # shot so that the server can give you a shot which is close # to it. (E.g. same scene) def requestNewShot(oldShot): if oldShot == None: raise ValueError, 'Old shot is not valid.' # Create the request object. request = ShotRequest() request.type = 'NewShot' request.shot = oldShot # Create a socket and connect it to the server. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = SERVER port = PORT s.connect((host, port)) # Pickle the request into a string and send it # to the server. requestStr = cPickle.dumps(request, 2) s.send(requestStr) # Read the server's response into a string and # unpickle it into a Shot object. responseStr = s.recv(4096) newShot = cPickle.loads(responseStr) s.close() return newShot ================================================ FILE: 10_PythonAdvanced/examples/alt_str.py ================================================ #- # ========================================================================== # Copyright (C) 2008 Autodesk, Inc. and/or its licensors. All # rights reserved. # # The coded instructions, statements, computer programs, and/or related # material (collectively the "Data") in these files contain unpublished # information proprietary to Autodesk, Inc. ("Autodesk") and/or its # licensors, which is protected by U.S. and Canadian federal copyright # law and by international treaties. # # The Data is provided for use exclusively by You. You have the right # to use, modify, and incorporate this Data into other products for # purposes authorized by the Autodesk software license agreement, # without fee. # # The copyright notices in the Software and this entire statement, # including the above license grant, this restriction and the # following disclaimer, must be included in all copies of the # Software, in whole or in part, and all derivative works of # the Software, unless such copies or derivative works are solely # in the form of machine-executable object code generated by a # source language processor. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY # OR PROBABILITY OF SUCH DAMAGES. # # ========================================================================== #+ # This example shows how to override a class's __str__() method so that # it displays its contents in a more readable manner. import maya.OpenMaya as om # -------------- MVector -------------------- # Print out an MVector using its default __str__() method. v = om.MVector(1, 2, 3) print "With it's default __str__() method an MVector prints like this:", v # Define a method to format an MVector into a string. def MVector_str(self): return "(%g, %g, %g)" % (self.x, self.y, self.z) # Save MVector's existing __str__() method. oldMVector_str = om.MVector.__str__ # Replace MVector's __str__() method with our own. om.MVector.__str__ = MVector_str # Try printing the vector again. print "With our replacement __str__() method it prints like this:", v # Restore the original __str__() method. om.MVector.__str__ = oldMVector_str print # -------------- MIntArray ------------------ # Print out a sparse MIntArray using its default __str__() method. sparse = om.MIntArray(100) sparse[7] = -3 sparse[20] = 13 sparse[82] = 6 print "A sparse MIntArray of 100 elements prints like this:", sparse # Replacement for MIntArray's __str__() method # which compresses long sequences of identical values. def compressedMIntArray_str(self): s = "[" count = 0 prev = None for i in self: if i == prev: count += 1 else: if prev != None: s += compressSeq(count, prev) + ", " count = 1 prev = i s += compressSeq(count, prev) + "]" return s # Helper function which returns a string containing # 'count' copies of 'value'. # If 'count' is three or less then they are returned as # a comma-separated list, otherwise they are returned # in 'value * count' notation. E.g. '3*24' means a # sequence of 24 values of 3. def compressSeq(count, value): if count > 0: if count > 3: s = str(value) + "*" + str(count) else: s = str(value) for i in range(1, count): s += ", " + str(value) else: s = "" return s # Save MIntArray's existing __str__() method. oldMIntArray_str = om.MIntArray.__str__ # Replace MIntArray's __str__() method with our own. om.MIntArray.__str__ = compressedMIntArray_str # Try printing the array again. print "With our replacement __str__() method it prints like this:", sparse # Restore the original __str__() method. om.MIntArray.__str__ = oldMIntArray_str ================================================ FILE: 10_PythonAdvanced/examples/cppCentroid.cpp ================================================ //- // ========================================================================== // Copyright (C) 2008 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ #include #include #include #include #include #include static PyObject* cppCentroid_mesh(PyObject*, PyObject* args) { // Retrieve the name of the mesh from the argument list. const char* meshName; if (!PyArg_ParseTuple(args, "s:mesh", &meshName)) { return NULL; } // Get the mesh's dag path. MSelectionList slist; slist.add(meshName); MDagPath path; slist.getDagPath(0, path); if (!path.hasFn(MFn::kMesh)) { return PyErr_Format(PyExc_ValueError, "'%s' is not a mesh.", meshName); } // Get the mesh's vertex positions. MFnMesh meshFn(path); MPointArray verts; meshFn.getPoints(verts, MSpace::kWorld); unsigned int numVerts = verts.length(); if (numVerts == 0) { return PyErr_Format(PyExc_ValueError, "Mesh '%s' has no vertices.", meshName); } // Add all the vertex positions together. double x = 0.0; double y = 0.0; double z = 0.0; for (unsigned int i = 0; i < numVerts; ++i) { MPoint& p = verts[i]; x += p.x; y += p.y; z += p.z; } // Calculate the average position. double divisor = 1.0 / (double)numVerts; x *= divisor; y *= divisor; z *= divisor; // Return a tuple containing the average of the vertex positions. return Py_BuildValue("(ddd)", x, y, z); } static PyMethodDef cppCentroidMethods[] = { { "mesh", cppCentroid_mesh, METH_VARARGS, "Find the centroid of a mesh." }, { NULL, NULL, 0, NULL } }; extern "C" PyMODINIT_FUNC initcppCentroid() { Py_InitModule("cppCentroid", cppCentroidMethods); } ================================================ FILE: 10_PythonAdvanced/examples/dist.py ================================================ # Simple test function for demonstrating pdb debugger. def distance(p1, p2): dist = 0 if len(p1) == len(p2): for i in range(0, len(p1)): diff = p1[i] - p2[i] dist += diff*diff dist = dist**0.5 return dist ================================================ FILE: 10_PythonAdvanced/examples/guipdb.py ================================================ #- # ========================================================================== # Copyright (C) 2008 Autodesk, Inc. and/or its licensors. All # rights reserved. # # The coded instructions, statements, computer programs, and/or related # material (collectively the "Data") in these files contain unpublished # information proprietary to Autodesk, Inc. ("Autodesk") and/or its # licensors, which is protected by U.S. and Canadian federal copyright # law and by international treaties. # # The Data is provided for use exclusively by You. You have the right # to use, modify, and incorporate this Data into other products for # purposes authorized by the Autodesk software license agreement, # without fee. # # The copyright notices in the Software and this entire statement, # including the above license grant, this restriction and the # following disclaimer, must be included in all copies of the # Software, in whole or in part, and all derivative works of # the Software, unless such copies or derivative works are solely # in the form of machine-executable object code generated by a # source language processor. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY # OR PROBABILITY OF SUCH DAMAGES. # # ========================================================================== #+ # This example demonstrates how to provide Python's pdb debugger with # a basic graphical interface when run within Maya. # # To use it, execute the 'run' with an argument consisting of the # function call to be debugged, as a string. E.g: # # guipdb.run('myFunc(12, "hello")') import pdb import sys import os import maya.cmds as cmds # All that pdb requires of its input object are 'read' and 'readline' # methods. # # This class is a drop-in replacement for Maya's sys.stdin which will # bring up a GUI customized for use with pdb. class DebuggerStandardInput: def readline( self ): return self._getUserDebugResponse() def read( self ): return self._getUserDebugResponse() def _getUserDebugResponse(self): result = cmds.promptDialog( title='Simple Debugger', message='Debugger command:', button=['Step Into', 'Step Over','Command'], defaultButton='StepInto') if result == 'Command': result = cmds.promptDialog(query=True, text=True) elif result == 'Step Over': result = 'n' elif result == 'Step Into': result = 's' return result # All that pdb requires of its output object are 'write', 'writeline' # and 'flush' methods. # # This class is a drop-in replacement for Maya's sys.stdout which will # filter out unwanted prompts from pdb. class DebuggerStandardOutput: def __init__(self, orig_stdout): self.orig_stdout = orig_stdout def write(self, msgoutput): line = msgoutput.strip() # If this is a pdb prompt, toss it away. if line[:5] == "(Pdb)": line = "\n" self.orig_stdout.write(line) def writelines(self, msgSeq): for l in msgSeq: self.write(l) def flush(self): return None # Run our GUI version of pdb on a command string. def run(command): # Save Maya's current stdin and stdout. orig_stdin = sys.stdin orig_stdout = sys.stdout # Replace stdin and stdout with instances of our own classes. sys.stdin = DebuggerStandardInput() sys.stdout = DebuggerStandardOutput(orig_stdout) # Run pdb. pdb.run(command) # Restore Maya's original stdin and stdout. sys.stdin = orig_stdin sys.stdout = orig_stdout ================================================ FILE: 10_PythonAdvanced/examples/guipdb1.py ================================================ #- # ========================================================================== # Copyright (C) 2008 Autodesk, Inc. and/or its licensors. All # rights reserved. # # The coded instructions, statements, computer programs, and/or related # material (collectively the "Data") in these files contain unpublished # information proprietary to Autodesk, Inc. ("Autodesk") and/or its # licensors, which is protected by U.S. and Canadian federal copyright # law and by international treaties. # # The Data is provided for use exclusively by You. You have the right # to use, modify, and incorporate this Data into other products for # purposes authorized by the Autodesk software license agreement, # without fee. # # The copyright notices in the Software and this entire statement, # including the above license grant, this restriction and the # following disclaimer, must be included in all copies of the # Software, in whole or in part, and all derivative works of # the Software, unless such copies or derivative works are solely # in the form of machine-executable object code generated by a # source language processor. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY # OR PROBABILITY OF SUCH DAMAGES. # # ========================================================================== #+ # This example demonstrates how to provide Python's pdb debugger with # a basic graphical interface when run within Maya. # # To use it, execute the 'run' with an argument consisting of the # function call to be debugged, as a string. E.g: # # guipdb.run('myFunc(12, "hello")') import pdb import sys import os import maya.cmds as cmds # All that pdb requires of its input object are 'read' and 'readline' # methods. # # This class is a drop-in replacement for Maya's sys.stdin which will # bring up a GUI customized for use with pdb. class DebuggerStandardInput: def readline( self ): if 'MAYA_IGNORE_DIALOGS' in os.environ: return '\n' else: return self._getUserDebugResponse() def read( self ): return self._getUserDebugResponse() def _getUserDebugResponse(self): result = cmds.promptDialog( title='Simple Debugger', message='Debugger command:', button=['Step Into', 'Step Over','Command'], defaultButton='Command') if result == 'Command': result = cmds.promptDialog(query=True, text=True) elif result == 'Step Over': result = 'n' elif result == 'Step Into': result = 's' return result # All that pdb requires of its output object are 'write', 'writeline' # and 'flush' methods. # # This class is a drop-in replacement for Maya's sys.stdout which will # filter out unwanted prompts from pdb. class DebuggerStandardOutput: def __init__(self, orig_stdout): self.orig_stdout = orig_stdout def write(self, msgoutput): line = msgoutput.strip() # If this is a pdb prompt, toss it away. if line[:5] == "(Pdb)": line = "\n" self.orig_stdout.write(line) def writelines(self, msgSeq): for l in msgSeq: self.write(l) def flush(self): return None # Run our GUI version of pdb on a command string. def run(command): # Save Maya's current stdin and stdout. orig_stdin = sys.stdin orig_stdout = sys.stdout # Replace stdin and stdout with instances of our own classes. sys.stdin = DebuggerStandardInput() # Run pdb. pdb.run(command) # Restore Maya's original stdin and stdout. sys.stdin = orig_stdin sys.stdout = orig_stdout ================================================ FILE: 10_PythonAdvanced/examples/pyCentroid.py ================================================ #- # ========================================================================== # Copyright (C) 2008 Autodesk, Inc. and/or its licensors. All # rights reserved. # # The coded instructions, statements, computer programs, and/or related # material (collectively the "Data") in these files contain unpublished # information proprietary to Autodesk, Inc. ("Autodesk") and/or its # licensors, which is protected by U.S. and Canadian federal copyright # law and by international treaties. # # The Data is provided for use exclusively by You. You have the right # to use, modify, and incorporate this Data into other products for # purposes authorized by the Autodesk software license agreement, # without fee. # # The copyright notices in the Software and this entire statement, # including the above license grant, this restriction and the # following disclaimer, must be included in all copies of the # Software, in whole or in part, and all derivative works of # the Software, unless such copies or derivative works are solely # in the form of machine-executable object code generated by a # source language processor. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY # OR PROBABILITY OF SUCH DAMAGES. # # ========================================================================== #+ import maya.OpenMaya as om # Return the centroid of a mesh. def mesh(meshName): # Get the mesh's dag path. sList = om.MSelectionList() sList.add(meshName) path = om.MDagPath() sList.getDagPath(0, path) if not path.hasFn(om.MFn.kMesh): raise ValueError, "'" + meshName + "' is not a mesh." # Get the mesh's vertex positions. meshFn = om.MFnMesh(path) verts = om.MPointArray() meshFn.getPoints(verts, om.MSpace.kWorld) numVerts = verts.length() if numVerts == 0: raise ValueError, "Mesh '" + meshName + "' has no vertices." # Add all the vertex positions together. x = 0.0 y = 0.0 z = 0.0 for i in range(0, numVerts): pt = verts[i] x += pt.x y += pt.y z += pt.z # Calculate the average position. divisor = 1.0 / numVerts x *= divisor y *= divisor z *= divisor return (x, y, z) ================================================ FILE: README.md ================================================ Maya-Training-Material ====================== About this materials... ----------------------- This is the Maya API training material we are using to train people on the Maya C++/Python API. * Materials provided here are from our two day classroom trainings. You can also use this for self-learning. * This is to introduce you to the fundamentals of Maya API to get you started. (Not meant to provide a complete coverage of Maya API nor C++/Python/.NET Framework.) * Materials are in Python and C++. Labs exercises are provided in two languages. Powerpoint presentation is mainly Python unless C++ specific. * Disclaimer: We are aware that materials is not free of errors. We intend to correct them as we encounter. We hope this will be still useful for you to get started with Maya API programming. Good luck! -------- ## License This sample is licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT). Please see the [LICENSE](LICENSE) file for full details. ## Written by Autodesk Developer Network
March 2013
http://www.autodesk.com/adn