Sign in to follow this  
Flawe

Maya api: MFnSet::create

Recommended Posts

I'm trying to create a set through the Maya API and I'm getting MStatus::kSuccess, but no set is created. MFnSet set; MObject dagSet = set.create(selectionList, MFnSet::kNone, status); The selection list is a list of all selected meshes in the scene and dagSet.isNull() is always true. Anyone have any ideas what I'm doing wrong?

Share this post


Link to post
Share on other sites
Alright, heh, this was fun...

The above line actually has to be

MObject dagSet = set.create(selectionList, MFnSet::kNone, &status);

since it needs the pointer to the status variable. Not sending the reference caused an old, obsolete method to be called instead of the one that works. Nothing about it in the documentation, oh well...

Share this post


Link to post
Share on other sites
Still got some troubles with this. It seems that the set is created alright. It shows up in the outliner and it can be manipulated as a set created from within Maya. Though if I save the scene and re-open it, the set disappears. No traces of it whatsoever.

MFnSet::create is supposed to add the object to the dependency graph, according to the documentation. Anyone knows if there's something else I need to do?

Share this post


Link to post
Share on other sites
It should work fine? (I've never had any problems with it anyway). I guess maya might strip it out if there are no objects contained within the set, but I'd be suprised if that was the case. There's always the sets mel command you can fall back on, but typically that just exposes the MFnSet funcs to mel... So it should work the same.

have you tried an

ls -type objectSet

to see if the set is there (and just not displayed in the outliner?)

Share this post


Link to post
Share on other sites
Yeah, I really can't imagine what could go wrong.

I tried your line above and my set seems to be listed there. And it does have meshes inside, as I create it based on the current selection.

Still nothing, if I save the scene and open it again, it's like the set never existed.


EDIT: I've tried using mel commands and I get the same result. I can create the sets, add the attributes I want and change them however I want. All sets disappear after a save/load.

[Edited by - Flawe on July 8, 2008 8:17:52 AM]

Share this post


Link to post
Share on other sites
hmmm... well, I've tried this code and it works for me fine. (and you can re-load)

class SetTest
: public MPxCommand
{
public:
virtual bool isUndoable() const ;
MStatus doIt(const MArgList& args);
static void* creator();
private:
};

bool SetTest::isUndoable() const
{
return false;
}
void* SetTest::creator()
{
return new SetTest;
}
MStatus SetTest::doIt(const MArgList& args)
{
// the return status
MStatus status = MS::kSuccess;
MFnSet fn;
MSelectionList sl;
status = MGlobal::getActiveSelectionList(sl);
if (status != MS::kSuccess)
{
return status;
}
MObject oset = fn.create(sl,MFnSet::kNone,false,&status);
return status;
}

#ifdef WIN32
#define MLL_EXPORT __declspec(dllexport)
#else
#define MLL_EXPORT
#endif

MLL_EXPORT MStatus initializePlugin(MObject obj)
{
MFnPlugin plugin( obj, "SetTest", "1.0", "Any");
return plugin.registerCommand("setTest",SetTest::creator);
}
MLL_EXPORT MStatus uninitializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj);
return plugin.deregisterCommand( "setTest" );
}



Have you made sure that:

1. The file is not set to read only?
2. You are writing to the file you think you are? (not reading from scenes dir, writing to another dir?)
3. Is it being created as a display layer? (passing false as the third param of MFnSet::create should make sure...)

Share this post


Link to post
Share on other sites
Rob, thank you for your reply.

The file is not read only as all other changes are saved except for the sets created through the api. I have checked several times for any mistakes and I'm not saving/loading different files.

This is how I do it...



MSelectionList selectionList;
if( MStatus::kFailure == MGlobal::getActiveSelectionList( selectionList ) ) {
return MStatus::kFailure;
}

MObjectArray selectedSets;
MGlobal::getAssociatedSets( selectionList, selectedSets );
if( selectedSets.length() == 0 ) {
MStatus status;
MFnSet set;
MObject dagSet = set.create( selectionList, MFnSet::kNone, false, &status );
if( status == MStatus::kFailure || dagSet.isNull() ) {
return MStatus::kFailure;
}
}




I'm starting to think it's some small thing I've overlooked. Maya 2008 API btw, if that makes any difference.

EDIT: I see you have yours as a command plugin. The way I'm implementing this is through an exporter plugin. I've also seen that Maya sometimes creates transparent sets while you work which are removed on save/load. Could the way I create the sets cause Maya to handle them like those temporary sets perhaps?

Share this post


Link to post
Share on other sites
Don't test for the failure condition, test to see if it's not a success (since failure is only returned for a very small number of failures, it's normally other things like invalid operation, out of memory etc). It's normally a good idea to propogate those errors back via return args (and a CHECK_STATUS macro makes life a lot easier for debugging - i.e. print out the line and file it failed in). It's Generally a good idea to test every single returned status, since failures do not terminate execution, but normally just generate a tonne more errors for you....

I'm also not entirely sure why you are testing to see if the returned set is null? If the create method succeeded, it's going to be valid...


MSelectionList selectionList;
status = MGlobal::getActiveSelectionList(selectionList);
if( MStatus::kSuccess != status )
return status;

MObjectArray selectedSets;
status = MGlobal::getAssociatedSets(selectionList,selectedSets);
if(status != MStatus::kSuccess)
return status;

if( selectedSets.length() == 0 )
{
MStatus status;
MFnSet set;
MObject dagSet = set.create(selectionList,MFnSet::kNone,false,&status);
if(status != MStatus::kSuccess)
return status;
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Flawe
EDIT: I see you have yours as a command plugin. The way I'm implementing this is through an exporter plugin. I've also seen that Maya sometimes creates transparent sets while you work which are removed on save/load. Could the way I create the sets cause Maya to handle them like those temporary sets perhaps?


It shouldn't make too much difference, though Maya may do funny things if your export process fails and returns a fail code. Generally that's why i test every single return arg....

Share this post


Link to post
Share on other sites
That's a good idea, to test for success only. Didn't really think of that.

I was testing dagSet for null since I had some troubles before when I forgot to send status as a reference. It would then call an obsolete create method which would return null but give MStatus::kSuccess.

Share this post


Link to post
Share on other sites
Heh, I've managed to find a couple of errors that were overlooked by changing to testing for success only, so thanks for that. Though still the same problems with the sets. I have no clue where I'm doing wrong with this.

Share this post


Link to post
Share on other sites
It's probably something else you are creating that's unable to be re-connected properly, and is then erroring during the load. That *could* make the set not re-appear since the file load bombs out before it gets to the objectSet. (at a guess)

Share this post


Link to post
Share on other sites
I tried saving to ascii format and I couldn't find the set there. So it disappears already during the save process.

I guess it has something to do with how I create everything from within the writer method of the exporter. Or perhaps I'm forgetting something. I'll try and create a command plugin from your example and see if I can get it to work.

Share this post


Link to post
Share on other sites
There we go. I finally got it to work.

Apparently this was caused by creating and manipulating the set from within the writer function. If I execute the mel commands by using executeCommandOnIdle(), everything works just fine.

But this means that I have to use mel and the executeCommandOnIdle() function. Can this be done with the c++ api somehow? Without having to mess around with different threads and such?

Share this post


Link to post
Share on other sites
Quote:
Original post by Flawe
Apparently this was caused by creating and manipulating the set from within the writer function.


Uhm.Why are you creating nodes in the writer function? That does kind of fly in the face of the purpose behind an exporter no? By any chance were you using MDgModifier to create that data?

Quote:
Original post by Flawe
But this means that I have to use mel and the executeCommandOnIdle() function. Can this be done with the c++ api somehow? Without having to mess around with different threads and such?


Probably easiest to go with mel. Alternatively you can use an MMessage derived class to generate a C++ message. Possibly MSceneMessage::kAfterExport or something similar.

Share this post


Link to post
Share on other sites
Quote:
Original post by RobTheBloke
Uhm.Why are you creating nodes in the writer function? That does kind of fly in the face of the purpose behind an exporter no? By any chance were you using MDgModifier to create that data?


Um yeah, it sure does. The goal was to arrange the meshes into sets based on how they are exported. In case a scene would have a lot of different meshes that would be exported to different models.

I didn't use an MDGModifier, I used the exact code I posted above. You reckon it would have worked with a dg modifier instead?

That MSceneMessage looks interesting. It would probably produce much cleaner code.

Share this post


Link to post
Share on other sites
Quote:
Original post by Flawe
Um yeah, it sure does. The goal was to arrange the meshes into sets based on how they are exported. In case a scene would have a lot of different meshes that would be exported to different models.


Once i was flown back from holiday about 2 days into a 2 week break because the pipeline needed to be modified inside of some game specific export code (and no one else knew how to use the Maya API). Putting that game specific stuff in a mel script and allowing it to be modifed would have prevented that.

More or less my entire export pipeline is configurable now and has a pretty fine grained level of control for just that reason. Are you sure you don't want to put that in a mel script :p

Quote:
Original post by Flawe
I didn't use an MDGModifier, I used the exact code I posted above. You reckon it would have worked with a dg modifier instead?


Just wondering that's all. I've never actually tried creating data within a write method - it sounds like you'd be wondering into the land of the undefined however you did it tbh.

Quote:
That MSceneMessage looks interesting. It would probably produce much cleaner code.


Maybe, though i get scared of those sorts of uses... and take care to clean it up properly - and take care that it doesn't get created if your export fails.

imo, arrangeMeshesIntoExportSets is a different operation to export.

my £0.02 ...

Share this post


Link to post
Share on other sites
Thanks very much for all your help.

It does make sense to put stuff into mel script. I don't have much Maya coding experience but most of the problems I've had were caused by the api and were easily fixed with mel.

The only reason why I thought it would be a good idea to merge the set creation and exporting together was to make it more transparent for the artists. Not give them a few extra steps of creating and arranging the sets in their workflow.

Share this post


Link to post
Share on other sites
Quote:
Original post by Flawe
The only reason why I thought it would be a good idea to merge the set creation and exporting together was to make it more transparent for the artists. Not give them a few extra steps of creating and arranging the sets in their workflow.


You can do that in other ways, for example it's pretty trivial to modify the export menu item callback to call your script, then the exporter. see this for starters....

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this