Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 2 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,18 @@ You can transfer:
* Displacement map

## Clean Installation of GoB
1. Remove your old GoB addon from your Blender Addons Folder
2. Copy the extracted GoB addon into your Blender Addon Folder
1. Remove your old GoB addon from your Blender Addons Folder if you have one sitting there.
2. Install the zip via Preferences -> Add-ons -> Install from Disk (arrow top right corner).
3. Start Blender and enable the GoB addon in the Preferences > Addons menu and safe your preferences
4. Select a object you want to send to Zbrush and press the Export Button in the Header.
This will configure Zbrush to know that it is communicating with Blender, Run Zbrush and load in your Object.
5. Restart Zbrush and that is it.

## Update GoB
1. Remove your old GoB addon from your Blender Addons Folder
2. Copy the extracted GoB addon into your Blender Addon Folder


### Configure Blender
**_Note**: If you have a previous version, remove it via the Addon panel (unroll the GoB entry and remove it) before continuing._

**_Note**: Github breaks (changes) name of zip file and the first (root) folder inside zip, when you download addon. Both zip file and first folder inside should be named: 'GoB'
The addon final location sould look like this:
* C:\Users\XXXXX\AppData\Roaming\Blender Foundation\Blender\2.80\scripts\addons\**GoB**

1. In Blender, open the addon panel, then click the _'Install From Files...'_ button at the bottom. Select the `GoB.zip` file, this will install the addon inside the correct folder.
3. Check the **GoB** box and save the User preferences to launch it at startup. Then click on the Import icon on the header (on top of Blender) to activate autoloading.


## Usage
The addon adds two icons Import/Export to the top info panel:
* By clicking on the Export icon, you export the selected mesh objects into ZBrush.
* By clicking on the Import icon, you enable autoloading mode. Latest objects are imported from GoZ.


# Acknowledgements
This script was originally written by user "Stunton" and posted [here on ZBrushCentral](http://www.zbrushcentral.com/showthread.php?127419-GoB-an-unofficial-GoZ-for-Blender).

Expand Down
54 changes: 29 additions & 25 deletions gob_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,32 +531,33 @@ def exportGoZ(self, scn, obj, path_export):

def execute(self, context):

if utils.prefs().custom_pixologoc_path:
paths.PATH_GOZ = utils.prefs().pixologoc_path
paths.set_goz_root(
utils.prefs().pixologoc_path if utils.prefs().custom_pixologoc_path else None
)

PATH_PROJECT = utils.prefs().project_path

#setup GoZ configuration
#if not os.path.isfile(f"{paths.PATH_GOZ}/GoZApps/Blender/GoZ_Info.txt"):
source_GoZ_Info_dir = os.path.join(paths.PATH_GOB, "Blender")
target_GoZ_Info_dir = os.path.join(paths.PATH_GOZ, "GoZApps", "Blender")
source_GoZ_Info = os.path.join(source_GoZ_Info_dir, "GoZ_Info.txt")
target_GoZ_Info = os.path.join(target_GoZ_Info_dir, "GoZ_Info.txt")
try: #install in GoZApps if missing
source_GoZ_Info = os.path.join(paths.PATH_GOB, "Blender")
target_GoZ_Info = os.path.join(paths.PATH_GOZ, "GoZApps", "Blender")
print(source_GoZ_Info, target_GoZ_Info)
shutil.copytree(source_GoZ_Info, target_GoZ_Info, symlinks=True)
except FileExistsError: #if blender folder is found update the info file
source_GoZ_Info = os.path.join(paths.PATH_GOB, "Blender", "GoZ_Info.txt")
target_GoZ_Info = os.path.join(paths.PATH_GOZ, "GoZApps", "Blender", "GoZ_Info.txt")
shutil.copy2(source_GoZ_Info, target_GoZ_Info)
print(source_GoZ_Info_dir, target_GoZ_Info_dir)
shutil.copytree(source_GoZ_Info_dir, target_GoZ_Info_dir, symlinks=True)
except FileExistsError:
pass
except Exception as e:
print(e)

#write blender path to GoZ configuration
#if not os.path.isfile(f"{paths.PATH_GOZ}/GoZApps/Blender/GoZ_Config.txt"):
try:
shutil.copy2(source_GoZ_Info, target_GoZ_Info)
with open(os.path.join(paths.PATH_GOZ, "GoZApps", "Blender", "GoZ_Config.txt"), 'wt') as GoB_Config:
blender_path = os.path.join(paths.PATH_BLENDER).replace('\\', '/')
GoB_Config.write(f'PATH = "{blender_path}"')
#specify GoZ application
with open(os.path.join(paths.PATH_GOZ, "GoZBrush", "GoZ_Application.txt"), 'wt') as GoZ_Application:
GoZ_Application.write("Blender")

GoZ_Application.write("Blender")
except Exception as e:
print(e)

Expand Down Expand Up @@ -701,18 +702,21 @@ def execute(self, context):
print(e)

# only run if PATH_OBJLIST file file is not empty, else zbrush errors
if not paths.is_file_empty(paths.PATH_OBJLIST):
path_exists = paths.find_zbrush(self, context, paths.isMacOS)
if utils.prefs().export_run_zbrush:
if not paths.is_file_empty(paths.PATH_OBJLIST) and utils.prefs().export_run_zbrush:
goz_launcher = paths.get_gozbrush_launcher()
if goz_launcher:
print("GoB GoZ launcher:", goz_launcher)
Popen([goz_launcher])
else:
path_exists = paths.find_zbrush(self, context, paths.isMacOS)
if not path_exists:
bpy.ops.gob.search_zbrush('INVOKE_DEFAULT')
else:
if paths.isMacOS:
print("OSX Popen: ", utils.prefs().zbrush_exec)
Popen(['open', '-a', utils.prefs().zbrush_exec, paths.PATH_SCRIPT])
else: #windows
print("Windows Popen: ", utils.prefs().zbrush_exec)
Popen([utils.prefs().zbrush_exec, paths.PATH_SCRIPT], shell=True)
elif paths.isMacOS:
print("OSX Popen: ", utils.prefs().zbrush_exec)
Popen(['open', '-a', utils.prefs().zbrush_exec, paths.PATH_SCRIPT])
else: #windows
print("Windows Popen: ", utils.prefs().zbrush_exec)
Popen([utils.prefs().zbrush_exec, paths.PATH_SCRIPT])

# restore object context
if context.object and currentContext:
Expand Down
16 changes: 12 additions & 4 deletions gob_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,13 +595,14 @@ def GoZit(self, pathFile):

def execute(self, context):

if utils.prefs().custom_pixologoc_path:
paths.PATH_GOZ = utils.prefs().pixologoc_path
paths.set_goz_root(
utils.prefs().pixologoc_path if utils.prefs().custom_pixologoc_path else None
)

global gob_import_cache
goz_obj_paths = []
try:
with open(os.path.join(paths.PATH_GOZ, "GoZBrush", "GoZ_ObjectList.txt"), 'rt') as goz_objs_list:
with open(paths.PATH_OBJLIST, 'rt') as goz_objs_list:
goz_obj_paths.extend(f'{line.strip()}.GoZ' for line in goz_objs_list)
except PermissionError:
if utils.prefs().debug_output:
Expand Down Expand Up @@ -653,6 +654,10 @@ def execute(self, context):


def invoke(self, context, event):
paths.set_goz_root(
utils.prefs().pixologoc_path if utils.prefs().custom_pixologoc_path else None
)

if utils.prefs().debug_output:
print("ACTION: ", self.action)

Expand Down Expand Up @@ -693,9 +698,12 @@ def invoke(self, context, event):
def run_import_periodically():
# print("Runing timers update check")
global cached_last_edition_time, run_background_update
paths.set_goz_root(
utils.prefs().pixologoc_path if utils.prefs().custom_pixologoc_path else None
)

try:
file_edition_time = os.path.getmtime(os.path.join(paths.PATH_GOZ, "GoZBrush", "GoZ_ObjectList.txt"))
file_edition_time = os.path.getmtime(paths.PATH_OBJLIST)
#print("file_edition_time: ", file_edition_time, end='\n\n')
except Exception as e:
print(e)
Expand Down
83 changes: 79 additions & 4 deletions paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,88 @@
from . import ui, utils, gob_import


def goz_root_candidates():
system = platform.system()
if system == 'Windows':
public_root = os.environ.get('PUBLIC', os.path.join("C:\\", "Users", "Public"))
return [
os.path.join(public_root, "Documents", "Maxon"),
os.path.join(public_root, "Documents", "Pixologic"),
os.path.join(public_root, "Maxon"),
os.path.join(public_root, "Pixologic"),
]
if system == 'Darwin':
return [
os.path.join(os.sep, "Users", "Shared", "Maxon"),
os.path.join(os.sep, "Users", "Shared", "Pixologic"),
]
return []


def is_goz_root(path):
if not path:
return False
return any(
os.path.isdir(os.path.join(path, folder))
for folder in ("GoZApps", "GoZBrush", "GoZProjects")
)


def resolve_goz_root(path_override=None):
if path_override:
return os.path.normpath(path_override)

for candidate in goz_root_candidates():
if is_goz_root(candidate):
return os.path.normpath(candidate)

candidates = goz_root_candidates()
return os.path.normpath(candidates[0]) if candidates else False


def set_goz_root(path_override=None):
global PATH_GOZ, PATH_OBJLIST, PATH_CONFIG, PATH_VARS

PATH_GOZ = resolve_goz_root(path_override)
if PATH_GOZ:
PATH_OBJLIST = os.path.join(PATH_GOZ, "GoZBrush", "GoZ_ObjectList.txt")
PATH_CONFIG = os.path.join(PATH_GOZ, "GoZBrush", "GoZ_Config.txt")
PATH_VARS = os.path.join(PATH_GOZ, "GoZProjects", "Default", "GoB_variables.zvr")
else:
PATH_OBJLIST = False
PATH_CONFIG = False
PATH_VARS = False

return PATH_GOZ


def get_gozbrush_launcher():
if not PATH_GOZ:
return None

if platform.system() == 'Windows':
candidates = [os.path.join(PATH_GOZ, "GoZBrush", "GoZBrushFromApp.exe")]
elif platform.system() == 'Darwin':
candidates = [
os.path.join(PATH_GOZ, "GoZBrush", "GoZBrushFromApp.app", "Contents", "MacOS", "GoZBrushFromApp"),
os.path.join(PATH_GOZ, "GoZBrush", "GoZBrushFromApp"),
]
else:
candidates = []

for candidate in candidates:
if os.path.isfile(candidate):
return candidate
return None


def gob_init_os_paths():
isMacOS = False
useZSH = False
if platform.system() == 'Windows':
print("GoB Found System: ", platform.system())
isMacOS = False
PATH_GOZ = os.path.join(os.environ['PUBLIC'] , "Pixologic")
PATH_GOZ = resolve_goz_root()

elif platform.system() == 'Darwin': #osx
print("GoB Found System: ", platform.system())
Expand All @@ -45,7 +120,7 @@ def gob_init_os_paths():

isMacOS = True
#print(os.path.isfile("/Users/Shared/Pixologic/GoZBrush/GoZBrushFromApp.app/Contents/MacOS/GoZBrushFromApp"))
PATH_GOZ = os.path.join("Users", "Shared", "Pixologic")
PATH_GOZ = resolve_goz_root()
else:
print("GoB Unkonwn System: ", platform.system())
PATH_GOZ = False ## NOTE: GOZ seems to be missing, reinstall from zbrush
Expand Down Expand Up @@ -160,7 +235,7 @@ def execute(self, context):
Popen(['open', '-a', GOZ_INSTALLER])
else:
GOZ_INSTALLER = os.path.join(path, "Troubleshoot Help", "GoZ_for_ZBrush_Installer_WIN.exe")
Popen([GOZ_INSTALLER], shell=True)
Popen([GOZ_INSTALLER])
else:
bpy.ops.gob.search_zbrush('INVOKE_DEFAULT')
return {'FINISHED'}
return {'FINISHED'}
21 changes: 7 additions & 14 deletions preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class GoB_Preferences(AddonPreferences):
#GLOBAL
zbrush_exec: StringProperty(
name="ZBrush Path",
description="Select Zbrush executable (C:\Program Files\Pixologic\ZBrush\ZBrush.exe). "
description="Select ZBrush executable (for example C:\\Program Files\\Maxon ZBrush 2025\\ZBrush.exe). "
"\nIf not specified the system default for Zscript (.zsc) files will be used",
subtype='FILE_PATH',
default="") # Default: ""
Expand All @@ -58,23 +58,16 @@ class GoB_Preferences(AddonPreferences):
default=False) # Default: False

custom_pixologoc_path: BoolProperty(
name="Custom Pixologic Public Path",
description="This will allow you to set a custom Public Pixologic Path, this is where ZBrush stores GoZ configurations",
name="Custom GoZ Public Path",
description="Set a custom public GoZ path when ZBrush stores GoZ data outside the detected Maxon or Pixologic folder",
default=False) # Default: False

if platform.system() == 'Windows':
PATH_GOZ = os.path.join(os.environ['PUBLIC'] , "Pixologic")
elif platform.system() == 'Darwin': #osx
PATH_GOZ = os.path.join("Users", "Shared", "Pixologic")
else:
PATH_GOZ = False

pixologoc_path: StringProperty(
name="Pixologic Public Path",
description="Set public pixologic path, this needs to be a valid folder which zbrush accesses."
"By default this folder is on the windows system drive under C:\\Users\\Public\\Pixologic",
name="GoZ Public Path",
description="Set the public GoZ folder used by ZBrush."
"\nExamples: C:\\Users\\Public\\Documents\\Maxon or C:\\Users\\Public\\Documents\\Pixologic",
subtype='DIR_PATH',
default=PATH_GOZ) # Default: PATH_GOZ
default=paths.PATH_GOZ or "") # Default: PATH_GOZ

project_path: StringProperty(
name="Project Path",
Expand Down