ZBrushCentral

how to determine if a subtool is made up of multiple parts or polygroups?

Hi! I’d like to make a script that automatically splits any masked or hidden geo. I already know how to do that part. However, if there is nothing masked, I’d like it to split to either parts or polygroups. But to do that, I’d like to be able to know if parts or groups exist so that I know which command to make the script run. Any ideas?

thanks!

Hi Ryan,
I think if Group Split is enable in subtools: split, then you have multiple groups on the current subtools.

Unfortunately, both that button and Split to Parts are always active regardless of the status of the subtool.

yeah sorry Ryan i speak too fast, i tried to found out any workaround but in vein.
to provide you a solution, the only solution i found just write now
is that if you can read obj file and count how many lines start with “g groupxxxxx” you will know the number of group on the subtool.
that’s a big game even more when the file is huge and you must to write a library in C to make it very fast.
or with the goz sdk, i guess you get access to the format and you can read throught it the same way.

Tragically, both that catch and Split to Parts are constantly dynamic paying little heed to the status of the subtool.

Hi Ryan!
I Hope this helps.
// THIS IS FOR THE POLYGROUPS
[VarSet, hasMultiplePolyGroups, 0]
[IFreeze,
[VarSet, curUndo, [IGet, Edit:Tool:UndoCounter]] // Saves the current undo so you can go back

[VarSet, totalPolycountBefore,0] [Mesh3DGet,0,,,totalPolycountBefore] [IKeyPress, '1', // This IKEYPRESS 1 will automatically clicks the Message PopUp when it reaches the max undo set in the Preferences [IPress, "Tool:Polypaint:Polypaint From Polygroups"] [IPress, "Tool:Masking:Mask By Hue"] [IPress, "Tool:Visibility:HidePt"] [VarSet, totalPolycountAfter,0] [Mesh3DGet,0,,,totalPolycountAfter] [If, #totalPolycountAfter == #totalPolycountBefore, ,// If the polycount before and after is not the same then it means it has polygroups [VarSet, hasMultiplePolyGroups, 1] ] ] [ISet, Edit:Tool:UndoCounter, #curUndo] [IPress, "Tool:Masking:Clear"]// This deletes the undo steps after the curUndo [ISet, Edit:Tool:UndoCounter, #curUndo]

]

[If, #hasMultiplePolyGroups ,
// PUT THE CODES HERE IF IT HAS MULTIPLE POLYGROUPS
,]

// THIS IS FOR THE PARTS
[VarSet, hasMultipleParts, 0]
[IFreeze,
[VarSet, curUndo, [IGet, Edit:Tool:UndoCounter]] // Saves the current undo so you can go back

[VarSet, totalPolycountBefore,0] [Mesh3DGet,0,,,totalPolycountBefore] [IKeyPress, '1', // This IKEYPRESS 1 will automatically clicks the Message PopUp when it reaches the max undo set in the Preferences [IPress, "Tool:Polygroups:Auto Groups"] [IPress, "Tool:Polypaint:Polypaint From Polygroups"] [IPress, "Tool:Masking:Mask By Hue"] [IPress, "Tool:Visibility:HidePt"] [VarSet, totalPolycountAfter,0] [Mesh3DGet,0,,,totalPolycountAfter] [If, #totalPolycountAfter == #totalPolycountBefore, ,// If the polycount before and after is not the same then it means it has parts [VarSet, hasMultipleParts, 1] ] ] [ISet, Edit:Tool:UndoCounter, #curUndo] [IPress, "Tool:Masking:Clear"]// This deletes the undo steps after the curUndo [ISet, Edit:Tool:UndoCounter, #curUndo]

]

[If, #hasMultipleParts ,
// PUT THE CODES HERE IF IT HAS MULTIPLE PARTS
,]

As you’ve found, there’s no easy way to do this. The suggestion posted by JRoC is probably as good a way as any.

However, in case it’s of interest, here’s a way to check for groups in an OBJ file, using just zscript. (A dll would be quicker!) I found there are issues reading strings when the file size gets large (over about a million polys), which is why I split it into chunks. (I’ve not managed to find out what restriction causes ZBrush to stop reading the string.) Also I use a rough-and-ready method to start reading in the middle of the file as ZBrush always writes the faces after the vertices.

This is a bare bones solution which doesn’t do any error checking. It would be probably sensible to export the lowest res, if there is one.

It doesn’t check for parts. That would involve using Auto Groups in a similar way to JRoC’s solution. It’s perhaps also worth pointing out that you can have groups and parts together!

[IButton,CheckGroups,“Check a mesh for PolyGroups”,
//set export options (should be reset after)
[IPress,Tool:Export:Qud]//export quads
[IUnPress,Tool:Polypaint:Colorize]//don’t want polypaint exported
[IUnPress,Tool:Export:Txr]//don’t want texture coords exported
[IUnPress,Tool:Export:Flp]
[IPress,Tool:Export:Mrg]
[IPress,Tool:Export:Grp]
//export the OBJ
[FileNameSetNext,“output.obj”]
[IPress,Tool:Export]
//load into memory
[VarSet,fSize,[FileGetInfo,“output.obj”,1]]
[VarMul,fSize,1024]
[VarMul,fSize,1024]//file size in bytes
[VarSet,fSize,INT(fSize)]
[VarSet,bytesToMem,1024]
[VarSet,pnts,0]
[Mesh3DGet,0,pnts]//number of points
[If,fSize > 65536,
[VarSet,fOffset,INT(pnts*25)]//approx total bytes for vertex lines
[VarSet,lpNo,INT((fSize - fOffset)/bytesToMem)]
,
[VarSet,fOffset,0]
[VarSet,lpNo,INT(fSize/bytesToMem)]
]
[VarInc,lpNo]
[VarSet,objLine,""]
[VarSet,found,0]
[VarSet,grps,0]
[VarSet,grp1OK,1]
[Loop,lpNo,
[MemDelete,ZZ_OBJMem]//make sure this isn’t around
//load chunk of file into memory
[MemCreateFromFile,ZZ_OBJMem,“output.obj”,fOffset,bytesToMem]
[VarSet,offset,0]
[VarSet,bytes,0]
//read all the strings in the chunk
[Loop,100,
[VarSet,bytes,[MemReadString,ZZ_OBJMem,objLine,offset,1]]
[VarSet,offset,offset+bytes]
[If,offset >= [MemGetSize,ZZ_OBJMem],[LoopExit]]
[If,([StrFind,"g ",objLine] == 0),
[If,grp1OK,//if it’s the first group we’ve found
[VarSet,group1,objLine]//record it
[VarSet,grp1OK,0]//make sure we only record the first time
, //else check for different group
[If,([StrLength,group1]==[StrLength,objLine])&&([StrFind,group1,objLine] == 0),
//same group - do nothing
,//else we have a new group
[VarSet,grps,1]
[LoopExit]//we don’t need to check any more
]
]
]
]//end loop
[VarAdd,fOffset,bytesToMem]//offset for next chunk
[If,fOffset >= fSize,[LoopExit]]//exit if end of file
[If,grps,[LoopExit]]//exit if groups found
]//end loop
//display result
[If,grps,
[Note,“There are groups”]
,
[Note,“There are NO groups”]
]
//clean up
[MemDelete,ZZ_OBJMem]
]//end button

GG marcus,
i was too lazy to test out to read directly a obj file using zbrush, but yes as long as the obj file is a small file it can works that way ;D

hah reading that now, and really it could have been simpler.
JRod and marcus method do not return the number of polygroup, so here is my own solution to that question.

[RoutineDef, get_polygroup_count_size,
	// backup the current tool id
	[VarSet, current_tool, [StrMerge,"Tool:",[IGetTitle, Tool:Current Tool]]]

	[IPress, "tool:subtool:copy"]
	[IPress, "tool:Polymesh3d"]
	[IPress, "tool:subtool:paste"]
	[IPress, "tool:subtool:select up"]
	//delete the polymesh3d
	[IKeyPress, '2', [IPress, "tool:subtool:delete"]]
	[IKeyPress, '2', [IPress, "tool:subtool:groups split"]]
	[VarSet, count, [SubToolGetCount]]
	
	//clean up
	[IKeyPress, '2', [IPress, "Tool:Subtool:Del All"]]
	//restore
	[If, [IExists, current_tool],
		[IPress, current_tool]
		,
		[Note, "The Ztools can't to be found",,1]
	]

,count]
[IButton, "Zplugin:Polygroup Count", "return the number of polygroup for the active subtool.",
	[VarSet,count, 1]
	[RoutineCall, get_polygroup_count_size, count]
	[Note, [StrMerge, "number of polygroup : ", count]]
,,1]

Use the Three back tick to concatenate your zscript code, like below :

```
// your code here
```