I recently found out that if you duplicate an object that is a member of a Set, by default the new object becomes a member of the Set too. This is not always desirable.
When trying to find a workaround that prohibits Maya from assigning objects to a Set, I reached a dead-end trying to query the names of objects created by the 'duplicate' command. Until a colleague showed me how to use the Python API to work around the problem.
Here's how we did it....
Put simply, I want to be able to prevent Maya adding objects to a given Set without my consent.
My first thought was to add an attribute to my Set allowing me to 'lock' it. A boolean will do.
The desirable outcome would be that if a Set has an attribute 'locked' set to ON, duplication of one of its members should not result in the duplicate object getting added to the Set.
Or put another way, if a duplicate object belongs to any Sets that are 'locked', then remove the new objects from these Sets.
1) The problem:
- Create a cube.
- With the cube selected, create a Set.
- In the Outliner, expand the Set to show its members.
- Duplicate pCube1 and notice that pCube2 is added to set1.
2) The solution:
Since the default behaviour is for Maya to assign duplicate objects to whatever Sets the original object belongs to, the question I asked myself was this: do I try to prevent new objects from ever becoming members of a 'locked' Set, or do I let Maya do its thing, then remove them ?
The second option seems the easiest to implement: let Maya do its thing and then remove the newest objects from Sets that are 'locked'.
It would be straightforward to run a script after the duplication that scans for connections between the new objects and Sets, and disconnects the objects from any Sets with the attribute 'locked' set to ON. You would use a scriptJob event "DagObjectCreated.
- duplicate an object
- use a scriptJob event "DagObjectCreated" to trigger..
- ...a script that removes the newest objects from Sets you don't want them to belong to.
3) The script:
The third item on my list clearly needs some fleshing out. Here is what I wrote on my napkin at lunchtime:
Assign the list to an array
Loop through the array of objects
Assign these Sets to an array
Loop through the array of Sets
Back in our Maya scene, add a Boolean attribute to set1, called "locked". Set it to ON. This will help us test our script.
select -r -ne set1 ;
addAttr -ln "locked" -at bool set1;
setAttr -e-keyable true set1.locked;
setAttr "set1.locked" 1;
At this point I'm already struggling to find a way to query the names of objects created as a result of a duplication...but I can test the rest of the script if I use pCube2 as a test dummy.
// ..if setx.locked is set to 1
string $dups[] = `ls -sl`;
for ($obj in $dups)
{
string $sets[] = `listConnections -type "objectSet"
$obj`;
string $plugs[] = `listConnections -type "objectSet"
-plugs 1 $obj`;
if (`size $sets`!=0)
{
for ($i=0; $i<`size $sets`; $i++)
{
if (`attributeQuery -exists -node $sets[$i]
"locked"`==1)
{
if (`getAttr ($sets[$i]+".locked")`==1)
disconnectAttr ($obj+".instObjGroups")
$plugs[$i];
}
}
}
}
Running this script - with pCube2 selected - disconnects the object from set1, effectively removing it as a Set member.
OK so it works if we spoon feed it....but how to query those new object names....?
3) You say 'procedure', I say 'method':
It's easy enough to follow the logic of the script, and he's written it so elegantly that I don't need to go into too much detail. Basically, this is what the script does:
- a pre-duplication callback executes procedure (method) A
- method A : set the global variable doingDup to 1
- a 'nodeAdded' callback - similar to the MEL scriptJob event - executes method B
- method B : if the global variable doingDup is 1, then put the names of all new objects in an array
- a post-duplication callback executes method C
- method C : remove objects from unwanted Sets; set the global variable doingDup back to 0; empty my object array
Download Dean's script here - make sure you rename the file as dupeNoSets.py
4) Move over MEL:
Let's test Dean's script to see how it behaves.
Reading it through, I'm expecting it to print a message that includes the names of all new objects that result from a duplication.
Put the script dupeNoSets.py in the folder: C:/My Documents/maya/2010/scripts
And edit the userSetup.mel file as follows:
// declare the python scripts
python "import dupeNoSets";
// execute the method setup() to create the callbacks
python "dupeNoSets.setup()";
Now, re-open Maya and repeat these steps:
- Create a cube.
- Duplicate pCube1
- You should read the following in the Script Editor:
Removing |pCube2 from unwanted sets.
Removing |pCube2|pCubeShape2 from unwanted sets.
5) Putting it together:
So now I have all the elements we need, we just need to put it all together.
All that's left to do is include the script I outlined in section 3. If you're new to Python, it's a recommended exercise...you can convert the MEL commands directly into Maya Python commands.
Or you can download the final script here.
The beauty if this is that this new functionality is transparent to the user....all you have to do is add the attribute 'locked' to a Set for this to work.
Enjoy !
Owen





Subscribe
I just ran into this same problem earlier in the week, and wrote some code to solve for it. It presumes you know that the nodes in questions are in a set (but won't hurt them if they're not) so you run this code instead of the standard duplicate code. I tried posting the code here, but it killed the formatting, find it on my wiki:
http://mayamel.tiddlyspot.com/#[[How%20can%20I%20duplicate%20nodes%2C%20but%20not%20have%20them%20added%20to%20the%20original%20nodes%20set%3F]]
Posted by: Eric Pavey | 06/11/2009 at 06:29 PM