[Closed] $…* = everything in scene????
I thought $…* = selection and its children and its childrens children, ect
Am I doing something wrong to get the current selected objects entire hierarchy?
or is this a bug with some versions of max?
ok so I can’t use the current selection and get the children of it without specifying the node, so cant use $…* then right, also cant use something like
x = selection
select x…*
or
x = $
select x…*
or
x = selection as array
for i in x do i…*
or anything like that, we must put in the specific node, seems kind of silly for a maxscript but what do i know…
any other way? like
allthehierarchy = #()
for x in selection do
(
if x.children != undefined do
(
selectmore x.children
append allthehierarchy x.children
)
)
just trying to find a way to get all the children of the selected node.
You want to avoid selecting stuff in the viewport as that is slow.
You will need to use a recursive function to recurse down the hierarchy of children.
Something like this: (iv not got max on this machine so cant check if this is working)
(
local childArr = #()
fn getAllTheChildren obj = (
for a in obj.children do (
append childArr a
getAllTheChildren a
)
)
--this function will only work with one object selected, but can easily be changed to allow more
getAllTheChildren $
--array of all children
print childArr
)
try this example
(
clearlistener()
-- this array in this cast , before function
NodesHandles = #()
NodesHyerarchy = #()
function AppendRecursiveChildren parent level=
(
append NodesHandles parent.handle
append NodesHyerarchy level
-- store handles integer is more memory friendly , if no children the recursive function exit
for child in parent.children do AppendRecursiveChildren child (level+1)
)
mainNodes = selection as array
for main in mainNodes do AppendRecursiveChildren main 0
-- for other methods you can utilize all numbers's array tools esample : makeuniquearray NodesHandles
-- but in this case you can't find duplicate
for i=1 to NodesHandles.count do
(
h = NodesHandles[i]
l = NodesHyerarchy[i]
format "[%]" (formattedprint h format:"04i")
for j=1 to l do format " "
format "%
" (maxops.getnodebyhandle h).name
)
clearSelection()
for i=1 to NodesHandles.count do NodesHandles[i] = maxops.getnodebyhandle NodesHandles[i]
select NodesHandles
)
actually collect node handles is much more expensive than collect nodes:
(
delete objects
for k=1 to 1000 do box()
t1 = timestamp()
m1 = heapfree
for k=1 to 1000 collect objects[k]
format "Collect Nodes >> time:% memory:%
" (timestamp() - t1) (m1 - heapfree)
t1 = timestamp()
m1 = heapfree
for k=1 to 1000 collect objects[k].inode.handle
format "Collect Handles >> time:% memory:%
" (timestamp() - t1) (m1 - heapfree)
)
i made a script that manage a lot of nodes (1000-2000) and i see a difference passing elements of array as node, the first evaluation “thenode.handle” is slow but “maxops.getnodebyhandle handle” is more fast than using directly the node reference.
And using:
t1 = timestamp()
m1 = heapfree
arr = dotnetobject "System.int32[]" 1000
for k=1 to 1000 do arr.setValue (objects[k].inode.handle) (k-1)
format "Build dotnet array >> time:% memory:%
" (timestamp() - t1) (m1 - heapfree)
made this result :
Collect Nodes >> time:28 memory:192L
Collect Handles >> time:72 memory:272192L
Build dotnet array >> time:174 memory:80256L
so nodes are the best
You could use that approach, but would need to build a string and execute it. For example:
if selection.count == 1 do (
nm = selection[1].name
execute ("select $"+nm+"...*")
)
-Eric
Ok thanks very much all, I ended up using:
getselectionshierarchyarray = #()
if selection.count >= 1 do
(
for x = 1 to selection.count do
(
nm = selection[x].name
execute ("append getselectionshierarchyarray $"+nm+"...*")
)
for i in getselectionshierarchyarray do
(
print i
)
)
based from pixelmonkeys code.
just wondering why does it work if its
execute ("append getselectionshierarchyarray $"+nm+"...*")
and not when its
append getselectionshierarchyarray $"+nm+"...*
srry just trying to understand execute a bit better, if someone could try to explain it to me i’d appreciate it.
Execute takes a compiled string and runs it as direct maxscript code. So if you assume for simplicity sake selection[1] is $Sphere001 then the following is true:
nm = “Sphere001”
execute (“append getselectionshierarchyarray $”+nm+”…“) would become:
execute (“append getselectionshierarchyarray $”+“Sphere001”+”…“) or:
[color=RoyalBlue]execute (“append getselectionshierarchyarray $Sphere001…“)[/color]
when run it would execute:
append getselectionshierarchyarray $Sphere001…
while:
append getselectionshierarchyarray $”+nm+”…* would become:
append getselectionshierarchyarray $”+“Sphere001”+”…* and error because of how it is laid out
append getselectionshierarchyarray $””+“Sphere001”+”…” would execute:
append getselectionshierarchyarray $”Sphere001…“, which isn’t a valid object.
Hope that helps,
-Eric
ok thanks that helps me understand a bit better, but I’m wondering why this dont work now
getselectionshierarchyarray = #()
if selection.count >= 1 do
(
for x = 1 to selection.count do
(
nm = selection[x].name
execute ("append getselectionshierarchyarray $"+nm+"...*")
)
for i in getselectionshierarchyarray do
(
print i.parent
)
)
returns unknown property.
or even if i try to print the i.name instead of i.parent it returns the same error like they no longer have properties?
the access to INode interface takes a time and a memory use. It might be cheaper to collect and store Integers than Pointers to a node (but i’m not absolutely sure, probably in both cases it’s 4bytes in 32 system and 8bytes in 64). The difference might be if mxs integer is still stored as 4bytes value in 64 system. Well.
about the using of “dotnetobject “System.Int32[]”. It’s not more friendly than msx array if you only use it as a storage. It will be slower and will use more memory.
about inode.handle… the better way is to use Anim Handle. It works fast for both get and find by. see the mxs help AnimHandle system.