Extension Attribute of MPxData

122 views
Skip to first unread message

Arnon Marcus

unread,
Sep 12, 2015, 5:25:23 PM9/12/15
to Python Programming for Autodesk Maya
I'm writing a C++ plugin using the Maya API.
I have a custom data-type, that I want to expose to all Dag nodes as an extension-attribute.

I've searched the documentation, the DevKit examples, in forums and just by google search. I couldn't find any example of how to do that (I'm starting to think that what I'm trying to do is not possible or not supported by Maya).

There are examples on how to add dynamic-attributes, but that is not what I'm after.
I've been able to expose it as a dynamic-attribute, but I then need to add it to every node that is being queried/edited, if it doesn't exist, and this gets complicated when supporting undo (even using MDGModifier).

According to the Maya documentations, there should be 3 ways to add extension-attributes:
1. Using 'addExtensios' MEL command
2. Using MNodeClass::addExtensionAttribute(<attr>)
3. Using MDGModifier::addExtensionAttribute(<node-class>,<attr>)

I put the code that adds the extension-attribute in the plugin's -initialization function, and a corresponding code for deleting it in the plugin's uninitialize function.

I am able to use the MEL option with:
MGlobal::executeCommand("addExtension -nt dagNode -sn S -ln L -dt T;");
(where: 'S' and 'L' are the attr-name, and 'T' is my datat-type's name)
The attribute even shows-up in the attribute-editor of all dag-nodes inthe 'Extended' section.
But then when I try to get the value of it later, it fails.

The code I'm using to get the data is taken from the blindComlexData example.
Within a MItSelectionList itereator, I do (satus-handling code excluded for clarity):

MObject node;
iter.getDependNode(node); 

MFnDependencyNode fnNode;
fnNode.setObject(node);

plug = fnNode.findPlug(S, false);

MObject sData;
plug.getValue(sData);
MFnPluginData fnData(sData);

data = (MyMPx*)fnData.constData();

(Where: 'S' is the short-name of the attribute, and MyMPx is my custom-data class)


The last-line fails, when it tries to case the data back to my custom-class.


When using the other two options, I can't even initialize the plugin if I use status-checking code - and there are absolutly no examples about how to do that anywhere (not that I could find, and I think I can search pretty well).

I've tried everythin I can think of, and then some guess-work.. (a LOT actually..)

I first have to define/create an attribute, of-course, before I pass it along to any of the functions that would add it as an extension attribute.

I actually found out that it doesn't matter what kind of attribute I created, using MFnTypedAttribute - even creating a built-in attribute-type, causes the same kind of failure:

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MFnStringData::kString);

BTW, if I add this right after: MFnData::Type t = fnAttr.attrType();
Then 't' is 'kInvalid', which I find odd - can't I even create a normal typed-attribute properly?

If I do this, though, then 't' is 'kString':

MFnTypedAttribute fnAttr;
MString defaultString("");
MFnStringData defaultTextData;
MObject defaultTextAttr = defaultTextData.create(defaultString);
MObject attr = fnAttr.create(L, S, MFnStringData::kString, defaultTextAttr, &status);
MFnData::Type t = fnAttr.attrType();

Using MNodeClass, I've tried doing:

MTypeId mDagNodeTypeID(MFn::kDagNode);
const MNodeClass mnDagNodeClass(mDagNodeTypeID);
status = mnDagNodeClass.addExtensionAttribute(attr);
CHECK_MSTATUS_AND_RETURN_IT(status);

The status-check fails and returns immediately.

Using MDGModifier, I've tried doing:

MTypeId mDagNodeTypeID(MFn::kDagNode);
const MNodeClass mnDagNodeClass(mDagNodeTypeID);
MDGModifier mDgMod;
status = mDgMod.addExtensionAttribute(mnDagNodeClass, attr);
CHECK_MSTATUS_AND_RETURN_IT(status);

The status-check fails and returns immediately.

So it can't even be the way I try to create my custom-typed attribute.
But just for completion-sake, here is what I've tried:

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MyMPx::id);
MFnData::Type t = fnAttr.attrType();

Doesn't work...
't' is 'kInvalid', and trying to add the attribute later as an extension-attribute (using either MNodeType or MDGModifier), fails the next status-check.

I then though, maybe it needs a default-value, so I first try:

MObject attr = fnAttr.create(L, S, MyMPx::id, MObject::kNullObj, &status); 
CHECK_MSTATUS_AND_RETURN_IT(status);
MFnData::Type t = fnAttr.attrType();

Status-check passes, but 't' is still 'kInavalid', and again, can't add it as an extension-attribute later.

Lastly then tried:

MFnPluginData fnData;
MObject defaultData = fnData.create(MyMPx::id);
MTypeId tPluginData(MFnData::kPlugin);
MObject attr = fnAttr.create(L, S, tPluginData, defaultData, &status); 
CHECK_MSTATUS_AND_RETURN_IT(status);
MFnData::Type t = fnAttr.attrType();

...

At this point, I am out of creative ideas...

Any help would be appreciated! 

Arnon Marcus

unread,
Sep 14, 2015, 2:15:29 PM9/14/15
to Python Programming for Autodesk Maya
Ok, I figured it out:

I don't know what about the MEL approach (I didn't like it anyway).
But as for the 2 other approaches, the problem was the way I instantiated MNodeClass.
I thought I was giving it a NoteTypeID, but I was actually trying to instantiate is with an MFnTypeID which doesn't work...
I found that out by trying to get it's TypeName afer instanciating it, and the AttributeCound, and I got invalid results...
Until I tried to just pass it a NoteTypeName, like "transform" (all lower-case), and suddenly it started working.
Eventually, I used "dagNode" (with this exact casing), so I could add the extension-attribute to all DAG-nodes.
It also works with my custom MPxData-type, just as well as with the StringData.
I didn't end-up having to wrap it in MFnPluginData for this to work - I just pass MyMPx::id to the attribute-creation function, and it works.
So, this is how it looks when it works:

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MyMPx::id); // or: MObject attr = fnAttr.create(L, S, MyMPx::id, MObject::kNullObj, &status); 
MNodeClass mnDagNodeClass("dagNode");
status = mnDagNodeClass.addExtensionAttribute(attr);

Realistically, I actually did have to use MFnPluginData in order to pre-generate a default-value for my attribute:

MFnPluginData fnData;
MObject defaultValue = fnData.create(MyMPx::id, &status);
CHECK_MSTATUS_AND_RETURN_IT(status);

MFnTypedAttribute fnAttr;
MObject attr = fnAttr.create(L, S, MyMPx::id, defaultValue, &status);
MNodeClass mnDagNodeClass("dagNode");
status = mnDagNodeClass.addExtensionAttribute(attr);

I haven't tried to use the MDGModifier approach, but I would guess it would work out just as well, with a proper MNodeClass instance..

I wish there was an easier way to find-out, when trying to instantiate MNodeClass, when it doesn't actually work...
I also wish there was a list somewhere of node-names and type-ids...

Anyway, anyone reading this, who wants to write a plugin with this use-case, now you know how.

f.michal

unread,
Sep 14, 2015, 2:18:05 PM9/14/15
to python_in...@googlegroups.com
Thanks for letting us know. This is something I might be looking into in near future.

W dniu 2015-09-14 o 20:15, Arnon Marcus pisze:
--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/93d9261e-42f0-4a52-8110-2b524b7754eb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages