[Closed] Move ojbects in a group to a specified layer
Is there a way to automate this process after selecting the group:
Select a group – Open the group (and any subgroups so that there are no closed groups in the selection) – select all objects within the group – move all selected objects from whatever layer they are on to the active layer (or a specified layer)?
I’m still pretty new to MaxScript, and am picking up a bit at a time as I am able and trying to decipher code through Max Listener, but I am kind of stumped on this one. It sounds (to me) like it ought to be something pretty simple, but I’m just not finding (or understanding) the relevant info in the help file.
Example of the problem – I have no problem moving a group into a new layer if all the objects in the group are in the same layer to begin with. However, if I have a group of objects (with objects on several different layers within the group) and I try to add the entire group to a layer (new or existing) either some of the objects will be added or none of the objects will be added.
Hi Jessup3D.
I’ve just had a quick play around trying a few things…now I don’t know if I fully understand your problem, so this is what I did…
I create a number of layers…
I create a number of objects, spread across those layers
I grouped a small number of the objects together
I grouped the remaining objects and the first group together
I then run a script, which basically, located all the group heads, opened all the groups, moved ALL the objects to the target layer and then reclosed all the groups.
This worked fine for me, indeed, I discovered, I didn’t even need to open the groups, I could move all the objects to the target layer without issue.
(
local lstGrpHeads = #()
-- Scan all objects for the group heads in the scene
-- You might need to change this to match your selection...
for node in objects do (
if (isGroupHead node) then (
append lstGrpHeads node
)
)
-- Open all the group heads
for gHead in lstGrpHeads do (
format "Openning %
" gHead
setGroupOpen gHead true
)
-- Locate our target layer...
local target = LayerManager.getLayerFromName "Layer05"
-- Depending on what you need, you will need to
-- change the reference to the "objects" collection
for node in objects do (
-- Add all the objects in the scene to the target layer
target.addNode node
)
-- Re-close the heads...
for gHead in lstGrpHeads do (
setGroupOpen gHead false
)
)
Okay, I think I’m halfway there, I have a code that will open a group and select it’s components as well as opening nested groups till there are no closed groups and all the objects in that group are selected;
Selection = #()
GroupedObj = #()
for s = 1 to Selection.count do (if isGroupMember Selection[s] then (append GroupedObj Selection[s]) else false)
for GroupedObj in Selection where isGroupMember GroupedObj AND (NOT isOpenGroupMember GroupedObj) do setGroupOpen GroupedObj.parent true
This seems to work for the first part of the problem. Does anyone know how to get a selection assigned to a specific layer (ideally, to give a pop-up that lets you select a layer to place the selection into)?
I’ll preface this response by saying I realize I’m not necessarily being helpful and it’s just a workaround…
but it seems to me like you’re looking to create a dialog that would display available layers and then pick one of those to assign your current selection to, which is basically what the layer manager already does, if i were in your situation (which I halfway am because I deal with this same issue, moving all group members to a new layer, all the time) I’d just use what you have already written to open/select the group members properly, then I’d just press the “add selected objects to highlighted layer” button.
is there a reason, besides just wanting to learn how to script it, not to do it that way?
SnipeyX – Yeah, part of this is just me wanting to know how to do it as I am learning (I’ve used Max for years but am just getting into scripting).
I’m basing the requirements of the script on what one of my bosses wants… basically shortening the process by a step or two without changing which layer is active or which is the highlighted layer. He wants to select a group that has objects in different layers and move them all to a specified layer and then continue on right where he left off originally with as few extra steps as possible. This will work, but he will be happier if I can automate the whole process.
I haven’t played around with anything, so I can’t give you feedback on your groups, but, you will want to take a look at “Interface: LayerManager”, in particular, getLayer, getLayerFromName (and possible newLayerFromName)…these return a reference to “Interface: LayerProperties” that represents the layer in question.
This interface has a wounderful method call “addNode”
Don’t know if you were up to speed with that or not…
Shane
I’ve been messing around with the addNode method, but my understanding of the logic of the scripting language is lacking, so I’m not using it correctly (getting lots of errors).
In an older post on this forum, I found this code;
LayerManager.newLayerFromName “testLayer”;
addNodesToLayer “testLayer” (selection as array);
Which should create a layer and add the selection to the layer, but as yet I have not been able to get that to work. If I can make that work, I’d like to at least be able to assign the new layer name manually, but the best option would be to have a pop-up menu that I could choose the destination layer from.
I could be very mistaken, but “addNodesToLayer” is not a function that is native to maxscript…obviously if you have the code then it should be fine…
I’d imagine it would look something like this…
mapped fn addNodesToLayer node layerName (
local target = LayerManager.getLayerFromName layerName
if target != undefined do (
target.addNode node
)
)
Now I’m assuming a lot here…
I’ve only ever used mapped a couple of times, so my understanding of it may not be correct.
I’ve switch the parameters, because, as I read it, the docs say
Using the mapped prefix on a function definition marks this function to be automatically mapped over collections. This means the function will be automatically called repeatedly on the elements of a collection if the collection is given as the first argument to the function. This allows you to define scripted functions that behave in a similar manner to the mapped built-in functions, such as copy, delete, move, and so on, which can be applied to an object set, path name pattern, or array. See Collections for more information.
This basically says, that if the first parameter to the function is an array/collection, then this function will be automatically called for each element in the array.
This allows you specify either a single node or an array for nodes…this is un-tested, so it may not work…but what’s life without a little adventure…
Hope all this is helping…
Shane
Okay, one more update…I’ve tried it with the selection collection as well…
This will basically scan the selection for all the group heads, open the groups, scan the selection again, moving all the “group members” to the target layer.
This has the interesting effect of moving the sub-groups head node to the target layer, but not the main groups…thought that was kinda cool, but not sure if that is what you want…
(
local lstGrpHeads = #()
-- Scan all objects for the group heads in the scene
-- You might need to change this to match your selection...
for node in selection do (
if (isGroupHead node) then (
append lstGrpHeads node
)
)
-- Open all the group heads
for gHead in lstGrpHeads do (
format "Openning %
" gHead
setGroupOpen gHead true
)
-- Locate our target layer...
local target = LayerManager.getLayerFromName "Layer05"
-- Depending on what you need, you will need to
-- change the reference to the "objects" collection
for node in selection do (
if (isGroupMember node) then (
-- Add all the objects in the scene to the target layer
target.addNode node
)
)
-- Re-close the heads...
for gHead in lstGrpHeads do (
setGroupOpen gHead false
)
)
So, if you want to move “everything” in the selection to the new layer…you could do
for node in selection do (
if (isGroupMember node) or (isGroupHead node)then (
-- Add all the objects in the scene to the target layer
target.addNode node
)
)
Else, if you only wanted to move the physical objects and NOT effect the group nodes…
for node in selection do (
if (isGroupMember node) and not (isGroupHead node) then (
-- Add all the objects in the scene to the target layer
target.addNode node
)
)
Should work.
I hope that gives you some ideas…
Shane
ps I’m using max9
First off, I really appreciate the help. I’ve tried several combinations of code like you’ve listed and I’m just not getting things to work right (most likely because I’m not sure how MaxScript needs to be worded).
I either get an error stating “– Syntax error: at ), expected <factor>”
or “– Unknown property: “addNode” in undefined”
I really need some help with knowing what I’m looking at and why it works the way it does.
(Also Using Max9)
Edit:
Okay… what am I doing wrong here?
Here’s what I’ve got so far;
ActiveSelection = #()
GroupedObj = #()
for s = 1 to ActiveSelection.count do (if isGroupMember Selection[s] then (append GroupedObj ActiveSelection[s]) else false)
for GroupedObj in Selection where isGroupMember GroupedObj AND (NOT isOpenGroupMember GroupedObj) do setGroupOpen GroupedObj.parent true
function addNodesToLayer str_layerName inputNodes =
(
if str_layerName == undefined or inputNodes == undefined then return undefined;
if (classof inputNodes) != array then inputNodes = #(inputNodes);
local inputLayer = (LayerManager.getLayerFromName str_layerName);
for eachObj in inputNodes do
(
inputLayer.addnode eachObj;
);
);
LayerManager.newLayerFromName "New Layer"; addNodesToLayer "New Layer" (selection as array);
If I run just the first part of the code that says;
ActiveSelection = #()
GroupedObj = #()
for s = 1 to ActiveSelection.count do (if isGroupMember Selection[s] then (append GroupedObj ActiveSelection[s]) else false)
for GroupedObj in Selection where isGroupMember GroupedObj AND (NOT isOpenGroupMember GroupedObj) do setGroupOpen GroupedObj.parent true
I get my group and all nested groups to open and I retain all of it as a selection.
When I add the rest of the script, it does generate a new layer, but the group stays closed and nothing gets added to the new layer. I also get an error that says;
<MixinInterface:LayerProperties>
-- Type error: Call needs function or class, got: undefined
I new enough to scripting that I’m probably missing something that’s glaringly obvious, but I have no idea what it is.
This is a complete pain to track down, cause you need to count all the brackets in your script and determine which one you’ve missed…pain
or "-- Unknown property: "addNode" in undefined"
This would suggest that the layer you’ve specified does not exist. In your “addNodesToLayer” function you should add a check:
if inputLayer != undefined then (
-- Continue adding nodes to the layer
) else (
-- Handle the error in what ever way you see fit...I like throwing an exception
)
I run your script, as you presented, and it worked fine for me ... I even tried and empty selection and it worked fine...
I might suggest adding some additional brackets around your where statement, eg:
for GroupedObj in Selection where [b](isGroupMember GroupedObj)[/b] AND (NOT isOpenGroupMember GroupedObj) do setGroupOpen GroupedObj.parent true
But otherwise I did not have any problems…
I new enough to scripting that I’m probably missing something that’s glaringly obvious, but I have no idea what it is.
We’re all noods at some level
Shane
edt: I’m using max 9 64, I need to reinstall the 32bit to test, but it shouldn’t make any difference…do you have a test scene I might be able to work against?!
I run your script, once again, but I took out the pre-amble about openning the group and it works fine…
I spread a series of objects over a number of layers, grouped them and run
function addNodesToLayer str_layerName inputNodes =
(
if str_layerName == undefined or inputNodes == undefined then return undefined;
if (classof inputNodes) != array then inputNodes = #(inputNodes);
local inputLayer = (LayerManager.getLayerFromName str_layerName);
for eachObj in inputNodes do
(
inputLayer.addnode eachObj;
);
);
LayerManager.newLayerFromName "New Layer"; addNodesToLayer "New Layer" (selection as array);
And had no problems. Everything move to the “New Layer”
Shane
Again, I really appreciate the help and I’m trying the advice you’ve posted but for some reason or other I’m just not getting it to work (I know… my noob-ness is showing). I’m not only trying to get this to work, but I’m trying to understand what is going wrong when it doesn’t work. For example, every time I place a ) on it’s own line, it gives me an error that says;
-- Syntax error: at ), expected <factor>
-- In line: )
I tried running the code you provided on a test scene (just a bunch of boxes with nested groups several layers deep) and I got a a ‘False” response in the listener. I tried it with the group closed as well as with all groups open and got the same result. The new layer didn’t show up and nothing seems to have changed in my scene.
My latest stab at this was using this code;
ActiveSelection = #()
GroupedObj = #()
for s = 1 to ActiveSelection.count do (if isGroupMember Selection[s] then (append GroupedObj ActiveSelection[s]) else false)
for GroupedObj in Selection where isGroupMember GroupedObj AND (NOT isOpenGroupMember GroupedObj) do setGroupOpen GroupedObj.parent true
(
LayerOne = LayerManager.NewLayer()
LayerOne.addnode Selection
Two of the three seperate parts of this code seem to work – running the part about opening all the groups in the selection works by itself and creating a new layer works by itself. The part about adding the selection to the new layer doesn’t work, but I’m not sure why.
Running it all at the same time gives me an error stating that “addnode is undefined” or “Unable to convert: $selection to type: <node>”
I figure your code should work, but I must still be missing something in there too. I don’t understand your code as clearly as what I’ve currently got (not because yours is confusing, but because my maxscript vocabulary is limited)
This problem is really hard to track down, adding and removing brackets randomly won’t help, you need to find out which one you’re missing, and open bracket or a closed bracket. I find cutting my code it segements and testing it usually works…
ActiveSelection = #() GroupedObj = #() for s = 1 to ActiveSelection.count do (if isGroupMember Selection[s] then (append GroupedObj ActiveSelection[s]) else false) for GroupedObj in Selection where isGroupMember GroupedObj AND (NOT isOpenGroupMember GroupedObj) do setGroupOpen GroupedObj.parent true ( LayerOne = LayerManager.NewLayer() LayerOne.addnode Selection
Running it all at the same time gives me an error stating that “addnode is undefined” or “Unable to convert: $selection to type: “
This won’t work because addNode expects a single node, not a collection or array…besides, if it was that simple, then you wouldn’t need to go to all the hassels you are…also, you are creating a new layer for each object in the selection and then, I assume, adding that object to it’s own layer by it self…
I figure your code should work, but I must still be missing something in there too. I don’t understand your code as clearly as what I’ve currently got (not because yours is confusing, but because my maxscript vocabulary is limited)
That’s okay, I don’t always understand it either
Here’s a simple one for ya. I took your sample scene and run this script on it:
-- Create a new layer
-- Keep a copy of the newly created interface
layer = LayerManager.newLayerFromName "Testing..."
-- Loop through the selection and add each node in the selection to the new layer
for node in selection do (
layer.addNode node
)
This worked fine…All the objects and the group helpers moved to the dynamically created layer…See if that helps
Shane
edt: Works in both max 9 x32 and x64