Tutorial — ZBrush Python Export Presets
Augmented Traveler local tutorial. Back to ZBrush — Tutorials · Maya equivalent: Tutorial — Maya Python Batch Export and Naming Checks
Optional. ZBrush 2026 added Python scripting. This tutorial uses it for one job that people get wrong by hand: exporting every visible subtool at subdivision level 1 as OBJ, with the studio's names, for the round trip (Tutorial — ZBrush No-Topology-Change Round Trip).
Draft. Built from Maxon's official SDK example. Test every call against the SDK documentation for your ZBrush version. The DevOps engineer owns the script in source control.
1. Running Python in ZBrush
- In the app: open ZScript → Python Scripting → Load and choose the
.pyfile; it runs straight away. Reload runs the last script again. - Command line (batch):
ZBrush -script <script.py> <args…>. - Record a macro: New Macro / End Macro. This is a quick way to find the interface path of a button, which you then use with
zbc.press("Palette:Button").
2. The script
Save it as Pipeline/ZBrush/scripts/at_export_level1.py.
"""Augmented Traveler: export visible SubTools at SDiv 1 as OBJ for the round trip.
Based on Maxon's mod_subtool_export example (ZBrush Python SDK 2026).
Usage in ZBrush: ZScript > Python Scripting > Load (edits EXPORT_DIR first),
or: ZBrush -script at_export_level1.py <export_dir>
"""
import os
import sys
import datetime
import zbrush.commands as zbc
EXPORT_DIR = sys.argv[1] if len(sys.argv) > 1 else r"D:/AT/Export/ZBrush"
PREFIX = "AT_"
def export_level1(export_dir=EXPORT_DIR):
os.makedirs(export_dir, exist_ok=True)
stamp = datetime.date.today().strftime("%Y%m%d")
count = zbc.get_subtool_count()
written = []
for i in range(count):
zbc.select_subtool(i)
if not (zbc.get_subtool_status() & 0x01): # skip hidden SubTools
continue
name = zbc.get_active_tool_path().rsplit("/")[-1]
if not name.startswith(PREFIX):
print(f"SKIPPED (name must start with {PREFIX}): {name}")
continue
# Go to subdivision level 1. Verify this interface path in your version
# (record a macro of setting SDiv to 1 if it differs).
zbc.set("Tool:Geometry:SDiv", 1)
out = os.path.join(export_dir, f"{name}_L1_{stamp}.obj").replace(os.sep, "/")
zbc.set_next_filename(out)
zbc.press("Tool:Export")
written.append(out)
print("Exported", out)
print(f"{len(written)} file(s) written. Check vertex counts in Maya before Transfer Vertices.")
return written
export_level1()
3. Rules
- The script only exports. It never runs DynaMesh, ZRemesher, Decimation or any other operation that changes topology.
- It exports at level 1 only. Higher levels stay in the
.ZPRfile for detail baking (Tutorial — Baking Detail Maps for MetaHuman). - Always run the Maya-side vertex-order test after exporting. The script can't check vertex order.
4. Check before using it in production
Sources
- Maxon, ZBrush Python SDK (2026.1): https://developers.maxon.net/docs/zbrush/py/
- Maxon, SDK example mod_subtool_export: https://developers.maxon.net/docs/zbrush/py/2026_1_0/examples/modeling_ex_mod_subtool_export.html
- Maxon, SDK Quickstart (Python Scripting palette): https://developers.maxon.net/docs/zbrush/py/2026_1_0/manuals/quickstart.html
- Maxon, ZBrush Python API examples on GitHub: https://github.com/Maxon-Computer/ZBrush-Python-API-Examples
- Maxon, ZScript Python Scripting (ZBrush help): https://help.maxon.net/zbr/en-us/Content/html/reference-guide/zscript/zscript-python.html
- Full list: Sources — 2026-09-19