190 likes | 504 Views
Introduction to the Maya C++ API. Brent Haley The Ohio State University (bhaley@accad.ohio-state.edu). Topics. Mud Plugin Introduction How to Create a MLL Command Basics Node Basics. Programming for Maya. The Book (Complete Maya Programming) MEL Scripts Can be really easy to test
E N D
Introduction to the Maya C++ API Brent Haley The Ohio State University (bhaley@accad.ohio-state.edu)
Topics • Mud Plugin Introduction • How to Create a MLL • Command Basics • Node Basics
Programming for Maya • The Book (Complete Maya Programming) • MEL Scripts • Can be really easy to test • Can see how Maya does its own with echo • Hard to get complex data structures • Slow, due to interpretation • C++ API Plugins • Very confusing at first (and later), hard to find help / concise examples • Fast, due to machine language
Particles in Maya • Maya has a built in particle system • Can exploit this to build a particle based fluid dynamics system • I took a procedural rather than physically based approach
Particle Based Fluid • Idea • Use maya particle dynamics to create the fluid • Have a voxelized force field, with a different force in each voxel • Force depends on particles as well as constants
Plugin Realization • Needs • Command to create the mud system • Node(s) to do the computations • Visual cues to locate where the field is • Go FAST (so I used the API + split particle system)
Topics • Mud Plugin Introduction • How to Create a MLL • Command Basics • Node Basics
Create a Visual C++ Project • The project creation wizard is not installed • Make a Win32Project • Under application settings, choose dll and empty project
Open the Project Properties Note: make sure you apply the settings on the next slide to both the debug and release versions (all configs should work).
Set the Project Properties • C/C++ -> General -> Additional Include Directories: C:\Program Files\AliasWavefront\Maya6.0\include • C/C++ -> CommandLine -> Additional Options: /I "C:\Program Files\AliasWavefront\Maya6.0\include“ • C/C++ -> Preprocessor -> Preprocessor Definitions: WIN32;NDEBUG;_WINDOWS;NT_PLUGIN • Linker -> General -> Output File: change the .dll to .mll • Linker -> Input -> Additional Dependencies: opengl32.lib Foundation.lib OpenMaya.lib OpenMayaUI.lib OpenMayaAnim.lib OpenMayaFX.lib OpenMayaRender.lib • Linker -> CommandLine -> Additional Options: /LIBPATH:"C:\Program Files\AliasWavefront\Maya6.0\lib" /export:initializePlugin /export:uninitializePlugin
#include <maya/MFnPlugin> #include <maya/MObject> #include <maya/MStatus> MStatus initializePlugin(MObject obj) { MStatus stat; MFnPlugin plugin(obj, "Brent Haley", "2.2.1", "5.0.1"); return(stat); } MStatus unintializePlugin(MObject obj) { MStatus stat; MFnPlugin plugin(obj); return(stat); } Initialize plugin procedure is an entry point that gets called when you load your plugin in Maya Uninitialize plugin procedure is an entry point that gets called when you unload your plugin from Maya Remember these were specified under the project settings Through these entry points we tell Maya what Nodes and Commands our Plugin has Required Code
Topics • Mud Plugin Introduction • How to Create a MLL • Command Basics • Node Basics
Specification class MudBoxCommand : public MPxCommand { public: //creator function static void *creator(); //command execution functions virtual MStatus doIt(const MArgList &args); virtual MStatus redoIt(); virtual MStatus undoIt(); virtualbool isUndoable() const; private: //graph modifier, used to support undo and redo MDagModifier dagMod; }; Implementation (except doIt) void *MudBoxCommand::creator() { returnnew MudBoxCommand; } MStatus MudBoxCommand::redoIt() { //commit the work set in doIt MStatus stat = dagMod.doIt(); return(stat); } MStatus MudBoxCommand::undoIt() { //erase any work set in doIt MStatus stat = dagMod.undoIt(); return(stat); } bool MudBoxCommand::isUndoable() const {return(true);} Example Command
doIt • Where the actual work is done • Changes made to the graph • Get nodes through selection • Get data through those nodes “plugs” • Be careful not to setup a cyclic graph • See examples (mud & joint extractor plugins, note the joint extract is a LOT simpler to script)
(De)Register the Command • Register commands in the initializePlugin procedure (from the required bit of code) stat = plugin.registerCommand( "makeMud", MudBoxCommand::creator); if (!stat) MGlobal::displayError("register MudBoxCommand failed"); • Deregister commands in the unitializePlugin procedure stat = plugin.deregisterCommand("makeMud"); if (!stat) MGlobal::displayError("deregister MudBoxCommand failed");
Topics • Mud Plugin Introduction • How to Create a MLL • Command Basics • Node Basics
Specification class MudBoxNode : public MPxNode { public: //identifier static MTypeId id; //attributes static MObject boxCenterX; … //creator function static void *creator(); //initializer for the node static MStatus initialize(); //computational function to do the real work virtual MStatus compute (const MPlug &plug, MDataBlock &data); private: … }; Implementation (except for compute) void *MudBoxNode::creator() { returnnew MudBoxNode; } MStatus MudBoxNode::initialize() { //create the attributes for spacial subdivision MFnNumericAttribute boxAttributes; boxCenterX = boxAttributes.create("boxCenterX", "bcx", MFnNumericData::kDouble, 0.0); ... //add the attributes to the node addAttribute(boxCenterX); ... //specify attribute relations attributeAffects(boxCenterX, boxData); ... //return without error return(MS::kSuccess); } Example Node
Compute • Where the actual work is done • See examples (mud plugin) MStatus MudBoxNode::compute (const MPlug &plug, MDataBlock &data) { MStatus stat; //determine which output plug needs to be computed if (plug == boxData) { //get input data handles MDataHandle boxCenterXData = data.inputValue(boxCenterX); ... //turn input handles into data double bcx = boxCenterXData.asDouble(); ... //get output data handles MDataHandle outputBoxData = data.outputValue(boxData); //turn output handles into data <SNIP> //set the output data and mark the plug outputBoxData.set(ssbDataFn.object()); data.setClean(plug);} else //the plug is for an ancestor, return unknown stat = MS::kUnknownParameter; return(stat);}
(De)Register the Node • Register nodes in the initializePlugin procedure stat = plugin.registerNode( "MudBoxNode", MudBoxNode::id, &MudBoxNode::creator, &MudBoxNode::initialize, MPxNode::kDependNode ); if (!stat) MGlobal::displayError("register MudBoxNode failed"); • Deregister nodes in the uninitializePlugin procedure stat = plugin.deregisterNode(MudBoxNode::id); if (!stat) MGlobal::displayError("deregister MudBoxNode failed");