Subtools and Macros

I get the below error when I try and create a macro that imports two OBJs and puts one as a subtool… it never ends up putting the object in the subtool…

Any ideas?



Hmm… ok…

I just tested Macros with Subtools using objects that are preloaded in ZBrush… and it worked.

So it seems like it’s something to do with objects that i’ve imported that is not allowing me to append a subtool.

is there some limitation in filenames? paths? that I could be ignorant of.

thank you

Macros can be tricky like that but the solution depends on what you are trying to do. For example, do you want your macro to give you the option of choosing the OBJs? Posting the whole macro will help as it will need editing.

Thanks for the response. Yeah, basically I want to import two objects and make one the subtool of the other.

It would be nice to then subdivide and create a morph target and layer but that is secondary.

What I want hope to be able to do is run a python script on the macro that will change the imported OBJs for subsequent projects…

When I’m around a computer I will upload a version of the script and see if anyone can make sense of it.

If the subtool was part of the project file, it would seem possible. Were you trying to bring it in from elsewhere such as a folder?

Ahh is there an issue with creating a subtool in macros. I’m trying to import 2 obj files…

I thinks it seems like it’s something to do with objects that i’ve imported that is not allowing me to append a subtool .

Here’s a macro that will do what you want, or you can adapt it to you needs. Copy the file to your ZBrush 4R4\ZStartup\Macros\Misc folder and press Macro>Reload All Macros or restart ZBrush. There will then be an AppendOBJ button in the Macro>Misc folder.

The macro works by reading a text file. I’ve set this to ZBrush 4R4\ZScripts\AppendList.txt but you can change this to anything/anywhere you want by editing the fileListPath at the start of the macro. (Note though, it’s probably not a good idea to store the file in the Macros folder or subfolders as ZBrush will try to load it as a macro.)

The AppendList.txt file has the file names and full paths for the OBJs you want to use. The list is simply the file paths, on separate lines, e.g. :


The macro will load the first file and then append the remaining ones, so long as the files actually exist. It will append any number up to 100 OBJs, though again you can change this if you wish by editing the maxAppend number at the start of the macro.

I’ve commented the macro so that anyone who’s interested can see what the code is doing.

Download macro here:


Marcus that works great! Thanks a ton! I’ve been trying to find a way to do this for years…!

What did you have to do in order to make it work? Or are there just a few things that don’t work with macros?

If I wanted to add a couple other functions such as set a morph target, create a couple layers and subdivide… could I just add that or would there be more i’d need to know for that as well?

Thanks a million regardless!

It’s the selecting from the pop up which is tricky. For some reason it requires a full path which is not provided when the macro is just recorded. The [IGetTitle] code corrects that.

In general macros work very well but sometimes a little editing can make them much more useful. ZScript is not too difficult once you get started.

I’ve added some new code at the end of the macro. It just runs through all the new subtools and calls a ‘DoStuff’ routine. You’ll see this routine at the top of the macro. I’ve put in what I think you’re after but you can edit it how you want.

Revised macro:

Marcus, you understand me! :slight_smile:

EXACTLY what I needed it to do. I’m gonna keep developing this now! Thanks so much for your tips.

I’d love to learn to do this stuff. Do you know of any tutorials? Building interfaces would be awesome…

I’m glad you found it useful. :slight_smile:

If you are interested in learning more about ZScript then the online docs has more information:

And you can always ask questions in this forum.

thanks… going through the document now. It’s to bad we can’t use the rename function in zscript… I saw that you answered someones question about that elsewhere on this forum…

If I wanted to import and apply a texture and displacement map would I also need the IGetTitle code to do that?

Also, storing a morph target doesn’t seem to want to work…

OK, I fixed the storing morph target… I just adjusted where it was placed in the script and voila…! Had to put it further down the stack.

I’d love to hide the 2nd and 3rd subtool on import and load textures and displacements still tho :smiley:

To hide all but the first subtool you’d have to adjust the Loop code to this:

  [Loop,[SubToolGetCount],//loop through all subtools
      [SubToolSelect,[Val,n]]//select each subtool
        [VarSet,subToolPath,[IGetTitle,Tool:Item Info]]//get subtool name
        [VarSet,subToolPath,[StrExtract,subToolPath,0,[StrLength,subToolPath]-2]]//trim off period
        [IClick,[StrMerge,"Tool:Sub Tool:",subToolPath]]//turn it off

Loading textures and displacements is a bit more tricky in that you’ll need to get the filenames, unless you can name them the same as your OBJs apart from a suffix and extension which you can add in code. You would use [FileNameExtract] to get the OBJ path and name without extension, then use [StrMerge] to create the new file name.

Then you’d use code something like this at the appropriate point in the DoStuff routine:

[IPress,Texture:Import]//import texture
[ISet,Texture:Item Info,[IGetMax,Texture:Item Info]]//select the last imported texture
[VarSet,txtrName,[IGetTitle,Texture:Item Info]]//get the title
[VarSet,txtrName,[StrExtract,txtrName,0,[StrLength,txtrName]-2]]//trim off period
[ISet,Texture:Item Info,0]//turn off texture
//assign texture to subtool:
[IPress,Tool:Texture Map:TextureMap]	

Marcus maybe you will be know.

My problem is linked up, so-so, with this above. I want to get visiblity status of subtool. And I want to set it invisible.

I tried like this:

17 is for visible. 1 is for invisible.

But how i can get this information ? I tried [IModGet] but this don’t work.


You can do it like this. Note that [IModSet] is not always reliable; it is best to test the Mod and then simply click on the subtool to make it visible/invisible.

This example runs through all the subtools and turns them off if necessary. (Note there is no error checking to see if a polymesh is selected, if there is more than one subtool, etc.) :

[IButton,TurnOffAllSubTools,"Loop through all subtools and turn them off",
  //this avoids an error if the top subtool is selected & hidden
  [If,[SubToolGetActiveIndex]==0,//if the top subtool is selected
     [SubToolSelect,1]//select the second subtool
  //loop through all subtools
    [SubToolSelect,[Val,n]]//select the subtool by number
    [VarSet,subToolPath,[IGetTitle,Tool:Item Info]]//get subtool name
    [VarSet,subToolPath,[StrExtract,subToolPath,0,[StrLength,subToolPath]-2]]//trim off period
    [VarSet,subToolPath,[StrMerge,"Tool:Sub Tool:",subToolPath]]//set the path
    [If,([IModGet,#subToolPath]>=17),//check the mod
      [IClick,#subToolPath]//click to turn it off
,n]//end loop

Thx Marcus. I solved the problem.

If you don’t mind Dragotron , I put one more question in your Thread.
I don’t want make a rubbish on the forum.

Marcus maybe you have idea how to check if subtool is zsphere ?

I have idea that I can check this by name, but what will happend when user will change name :/. This complicate all . There is some flag or marker that we can recognize zsphere from others sub tools like, for example, PolyMesh ?

You can test for the different ZTools like this:

[If,[IExists,Tool:SubTool:Append],//we have a 3D tool    
      [If,[IExists,Tool:AdaptiveSkin:Make Adaptive Skin],
        [Note,"This is a ZSphere"]
      ,//else there's no Adaptive Skin option
        [Note,"This is a Polymesh"]  
    ,//else there's no Geometry SDiv slider     
      [Note,"This is a Parametric primitive"]  
    ,//else there's no SubTool Append button
    [Note,"This is a 2.5D tool"]