Monday
May092011

MRampAttributes without creating an AETemplate file

I wanted to see if there was a way to initialize MRampAttributes without the need for the AETemplateFile. 

I ended up using this solution. 

First I define my AETemplate inside my plugin by calling MGlobal::executeCommand(); I pass it a couple of commands to intialize my ramp.

This function gets run inside myNode::initialize() function, after I've defined my ramps.

MStatus myNode::initializeAETemplate()
{

	MString attributeTemplate;

	attributeTemplate += "global proc AEmyNodeTemplate( string $nodeName )"
	attributeTemplate += "{";
	attributeTemplate += "editorTemplate -beginScrollLayout;";
	attributeTemplate += "editorTemplate -beginLayout \"ramps\" -collapse 0;";
	attributeTemplate += "AEaddRampControl \"myRamp\";";
	attributeTemplate += "editorTemplate -endLayout;";
	attributeTemplate += "AEdependNodeTemplate $nodeName;";
	attributeTemplate += "editorTemplate -addExtraControls;";
	attributeTemplate += "editorTemplate -endScrollLayout;";
    attributeTemplate += "}";
	MGlobal::executeCommand(attributeTemplate);


	return MS::kSuccess;
}

Nicely written my string looks like this:

    global proc AEmyNodeTemplate( string $nodeName );
    {
        editorTemplate -beginScrollLayout;
        editorTemplate -beginLayout "ramps" -collapse 0;
        AEaddRampControl "myRamp";
        editorTemplate -endLayout;
        AEdependNodeTemplate $nodeName;
        editorTemplate -addExtraControls;
        editorTemplate -endScrollLayout;
    }

The most important line is this one.

AEaddRampControl "myRamp";

In mel this makes the AEtemplate recognize my custom ramp attribute. You can add this line for as many ramps as you have on your node. Without this defined in an AETemplate, Maya does not draw your ramp attribute properly in the Attribute Editor.

Also make sure the the procedure's name matches the node name. If my node name was registered as nodeName then my procedure name would be: AEnodeNameTemplate

This procedure runs every time you load the node in maya's attribute editor. So we can't initialize the ramp's values here.

We can do this in our node's postConstructor. Here I define a color ramp's default values.

This sort of method can also be applied to curve ramps

void myNode::postConstructor()
{
	MColor defaultColor(0.5,0.5,0.5);

	MPlug myRampPlug(myNode::thisMObject(), myRamp);
	MColor color1(1.0, 0.0, 0.0);
	MColor color2(1.0, 1.0, 0.0);
	
	addColorRampSlot(myRampPlug, 0, 0.0, defaultColor, 2);
	addColorRampSlot(myRampPlug, 1, 0.5, color1, 2);
	addColorRampSlot(myRampPlug, 2, 1.0, color2, 2);
}

And finally, here is my function addColorRampSlot:

void addColorRampSlot(MPlug rampAttributePlug, int index, float position, MColor color, int interpType)
{	
	
	MPlug entryPlug = rampAttributePlug.elementByLogicalIndex(index);
	MPlug posPlug = entryPlug.child(0);
	posPlug.setDouble(position);

	MPlug valuePlug = entryPlug.child(1);
	valuePlug.child(0).setFloat(color.r);
	valuePlug.child(1).setFloat(color.g);
	valuePlug.child(2).setFloat(color.b);

	MPlug interpPlug = entryPlug.child(2);
	interpPlug.setInt(interpType);
}

By going through the MPlug documentation you can figure out exactly what all this means.

Monday
Apr252011

Compiling multiple maya api plugins in one.

Say you have a stressMap node and a stretchySpine node that you've written in Maya's C++ API.

You will need a header file and a cpp file. The header file should contain the class definition and the cpp file should contain the compute method, so on and so forth. Refer to the devkit folder that comes with maya to see examples of api nodes that have both a header file and a cpp file. ..\maya_dir\devkit\plug-ins.

The benefit of using header files means we can create an initialize.cpp file that registers multiple MPx plugins.

Here is an example. StressMapNode and strechySpineNode MPxNode class would be defined in their respective header file.

 

#include maya/MFnPlugin.h;

//because we've created header files for our plugins we can include them here.
#include stressMapNode.h
#include strechySpineNode.h


MStatus initializePlugin( MObject obj )
{
    MStatus result;

    //define the plugin
    MFnPlugin plugin( obj, "MySpecialCompany", "1.0", "2011");

    //register stressMapNode,
    //which is defined in stressMapNode.h
    result = plugin.registerNode( "stressMapNode",
                                   stressMapNode::id,
                                   stressMapNode::creator,
                                   stressMapNode::initialize,
                                   MPxNode::kDeformerNode );

    if (! result) return MS::kUnknownParameter;

    //register stretchySpineNode, 
    //which is defined in stretchySpineNode.h

    result = plugin.registerNode("stretchySpineNode",
                                  stretchySpineNode::id,
                                  stretchySpineNode::creator,
                                  strechySpineNode::initialize,
                                  MPxNode::kDependNode);

    if (! result) return MS::kUnknownParameter;

    return result;
}

MStatus uninitializePlugin( MObject obj)
{
    MStatus result;
    MFnPlugin plugin( obj );

    //deregister our 2 plugins
    result = plugin.deregisterNode( stressMapNode::id );
    if (! result) return MS::kUnknownParameter;

    result = plugin.deregisterNode( stretchySpineNode::id );
    if (! result) return MS::kUnknownParameter;

    return result;
}
This is a great way to package a suite of plugins!

 

Thursday
Jan132011

OPENMAYA_EXPORT.h

All you have to do to use functions found in OPENMAYA_EXPORT.h is create and include a header that defines what it is.

Your header code should look something like this:

 

#ifndef OPENMAYA_EXPORT
#define OPENMAYA_EXPORT _declspec( dllimport )
#endif

 

 

include this in your plugin and you can then access things like the slerp method documented in MQuaternion's help. 

 

Thursday
Dec092010

closest point and ray casting in the Maya API

Maya's API has a couple ways to help out with ray casting and closest point calculations.

MFnMesh::anyIntersection takes one variable of type MMeshIsectAccelParams.

There's no real documentation on what that attribute means but if you look in MFnMesh's static public member functions you'll find:

static MMeshIsectAccelParams unifromGridParams ( int xDiv, int yDiv, int zDiv )

static MMeshIsectAccelParams autoUnifromGridParams()

These return MMeshIsectAccelParams. You merely need to initialize one and feed the result back into MFnMesh::anyIntersection. This should speed up ray casting calculations significantly if you were leaving that parameter out before. 

Also check out:

MNurbsIntersector

MMeshIntersector