PDA

View Full Version : Groups & opening...


AJ
09-21-2007, 10:29 AM
Hello!

I've (very poorly) written a script that selects objects by the active material, sorts those that are in a group, opens those groups & then finally re-selects them.
Mat = meditmaterials[medit.GetActiveMtlSlot()]
MatObj = #()

-- Collect all objects with material applied

for i in $* do
(
if i.material == Mat then append MatObj i
)
if MatObj.count == 0 then print "Nothing has this material you fool!"

-- Seperate objects that are in a group

ObjNum = MatObj.count
GroupedObj = #()
for s = 1 to ObjNum do
(
if isGroupMember MatObj[s] then (append GroupedObj MatObj[s]) else false
)

-- Opens all groups

ObjCount = GroupedObj.count
progressStart "Opening Groups"

for y = 1 to ObjCount do
(
select MatObj
max group open
progressupdate (100.0*y/ObjCount)
)
progressEnd()
select MatObj

It works, but I know that the last part (Opens all groups) isn't as efficient as it should be.

Firstly it loops through the MatObj array & tries to open the selection for every grouped object - not for every group.

Secondly, I couldn't find a cleaner way to open a group other than 'max group open'. Is there any way to select/find the group node & manipulate it?

Thirdly, I am terrible at maxscript, I was only able to cobble this together thanks to Bobo's fantastic 'Maxscript for the Masses' DVD... So any other improvements or advice would be greatly appreciated.

Thanks!

Gravey
09-21-2007, 03:36 PM
there are a few things you can do to make your code more efficient. The following code will do what you require and in only 4 lines! mat = meditmaterials[medit.GetActiveMtlSlot()]
matObj = for o in objects where (superclassof o == GeometryClass OR superclassof o == Shape) AND o.material == mat collect o
for m in matObj where isGroupMember m AND (NOT isOpenGroupMember m) do setGroupOpen m.parent true
select matObj The first line defines 'mat' the same way you have.

Next line loops through all objects that are either geometry or shape objects (incase you are using renderable splines) and has the material 'mat' and collects that object into an array and the result is stored in the variable 'matObj'. The collect function is faster than append and you can use 'where' as I have to subsitute for your if statement which i believe would also be faster.

Then loop through matObj looking for groupmembers that are part of a group that has not already been opened, and then of course, open the group. Skipping groupMembers that are in a group that is already open saves time as you can imagine.

Finally, select the objects with the given material

I hope this all makes sense. If not let me know specifics and I'll try to explain them better.
I recommend you watch bobo's dvd again and again and just practice scripting with small projects that make simple repetative tasks easier for yourself.

AJ
09-21-2007, 04:36 PM
Oh that's wonderful - thank you!

I will keep trying... I tend to fall into the trap of plotting out each task I need a script to perform in the order & in the method I would manually in Max - so even though it's 'doing the work for me', it's going around the horn to get there.

Once again, thank you.

AJ
09-21-2007, 05:20 PM
One quick question, the script is very fast but I've tried it on a scene in production (lots of nested groups...etc.) recieved the following error:

--Runtime error: Not a valid group head: $Dummy:Dummy @ (and then some point3 coords)

What could cause this?

Gravey
09-22-2007, 01:17 AM
not sure, i did some quick tests and it seemed to work fine. Maybe try adding the following code in between ... (NOT isOpenGroupMember m) ... and ... do setGroupOpen ...
AND isGroupHead m.parent I could look at your scene but since its a production scene i doubt that'd b possible. Let me know if this doesnt fix the problem

AJ
09-24-2007, 11:28 AM
I found the problem, the objects inside the group are all parented to a dummy, also inside the group. So the hierarchy went

Group01
->Dummy
-->Object01
-->Object02
-->Object03

So the script errors because it only 'steps up' the chain to Object01's parent, instead of the top of the chain.

Your code "AND isGroupHead m.parent" helps stop the error - which is great, but I'm now trying find a way to use it to tell Max to traverse further up the chain to find the GroupHead...

At the moment I just have:

for m in matObj where isGroupMember m AND (NOT isOpenGroupMember m) do
(
if isGroupHead m.parent != false then setGroupOpen m.parent true
else setGroupOpen m.parent.parent true
)
Which obviously only solves the problem in my specific instance - where the grouphead is only one .parent away...

I really appreciate your help on this. I'm going to try to find a way to solve it myself but any suggestions you have would be fantastic.

AJ
09-24-2007, 11:57 AM
I think I've cracked it.

I defined the following function:

fn GroupOpen OpenMe =
(
if isGroupHead OpenMe.parent != false then setGroupOpen OpenMe.parent true else GroupOpen OpenMe.parent
)

And then used it like this:

mat = meditmaterials[medit.GetActiveMtlSlot()]
matObj = for o in objects where (superclassof o == GeometryClass OR superclassof o == Shape) AND o.material == mat collect o
for m in matObj where isGroupMember m AND (NOT isOpenGroupMember m) do GroupOpen m
select matObj
It works - seemingly... Again, I just don't know if it's the most efficient way to do so!

Gravey
09-24-2007, 12:32 PM
The way you have it seems to only work at one or 2 levels of the heirachy.for m in matObj where isGroupMember m AND (NOT isOpenGroupMember m) do
(
par = m.parent
while par != undefined do
(
if isGroupHead par then
(
setGroupOpen par true
par = undefined
)
else par = par.parent
)
) This should work through as many parents as it takes before it reaches the grouphead. Let me know if you want clarification on how it all works

AJ
09-24-2007, 01:18 PM
Nope that all makes perfect sense - thank you once more!

Although as far as I'm aware (and I'm not particularly aware!), both of our scripts are performing (practically) the same function...?

The way you have it seems to only work at one or 2 levels of the heirachy.
It does?
I thought the fact that if m.parent returns false in the GroupOpen function it calls on itself with an additional .parent would cycle through the whole heirachy until it got to the GroupHead?

Like I said, I'm a novice and your solution certainly works so I'm not going to question it - I just want to make sure I understand the difference in the two methods.

Gravey
09-24-2007, 02:45 PM
sorry i missread your code for your function. I thought it said '... else SetGroupOpen OpenMe.parent'
If your way works then great! I wasn't aware that you could call a function from inside itself!

CGTalk Moderation
09-24-2007, 02:45 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.