Skip to content

Instantly share code, notes, and snippets.

@Tiim
Last active August 16, 2021 14:44
Show Gist options
  • Save Tiim/ef4925c64cb177a61fdf8176cab7a2db to your computer and use it in GitHub Desktop.
Save Tiim/ef4925c64cb177a61fdf8176cab7a2db to your computer and use it in GitHub Desktop.
import bpy
import os
import re
from bpy_extras import io_utils
from zipfile import ZipFile
EXPORT_SINGLE = False # Only export the selected Collection and not seperate files
ENABLE_ZIP = True
dir = os.path.dirname(bpy.data.filepath)
texture_dir = None
if os.path.basename(dir) == 'project':
print("Photogrammetry file structure detected!")
dir = os.path.join(dir, '..', 'models', '4-other-formats')
texture_dir = os.path.join(os.path.dirname(bpy.data.filepath), '..', 'textures_pkg')
else:
print("No special folder structure detected!")
dir = os.path.join(dir, 'export')
texture_dir = os.path.join(os.path.dirname(bpy.data.filepath), 'textures_pkg')
def simple_slug(str):
return re.sub('\W', '_', str.lower())
def copy_imgs(images, folder):
copy_set = set()
for t in images:
io_utils.path_reference(t.filepath, os.path.dirname(bpy.data.filepath), folder,
"COPY", "", copy_set, t.library)
io_utils.path_reference_copy(copy_set)
def select(obj_or_col, select):
if type(obj_or_col) == bpy.types.Collection:
for obj in obj_or_col.all_objects:
obj.select_set(select)
else:
obj = obj_or_col
obj.select_set(select)
def zip_folder(name, path, folder):
if not ENABLE_ZIP:
return
print("Zipping folder", folder)
with ZipFile(os.path.join(path, name + '.zip'), 'w') as zipObj:
for folder, subfolders, filenames in os.walk(folder):
for file in filenames:
file_path = os.path.join(folder, file)
zipObj.write(file_path, os.path.basename(file_path))
def export_obj(object, dir, tex, name_ext=''):
odir = os.path.join(dir, object.name, 'obj')
os.makedirs(odir, exist_ok=True)
file = os.path.join(odir,object.name+name_ext+'.obj')
select(object, True)
bpy.ops.export_scene.obj(filepath=file, check_existing=False, use_selection=True, path_mode='COPY');
select(object, False)
zip_folder(object.name + name_ext + '-obj', dir, odir)
def export_fbx(object, dir, tex, name_ext=''):
file = os.path.join(dir,object.name+name_ext+'.fbx')
select(object, True)
bpy.ops.export_scene.fbx(filepath=file, check_existing=False, use_selection=True, path_mode='COPY', embed_textures=True);
select(object, False)
def export_dae(object, dir, tex, name_ext=''):
odir = os.path.join(dir, object.name, 'dae')
os.makedirs(odir, exist_ok=True)
file = os.path.join(odir,object.name+name_ext+'.dae')
select(object, True)
bpy.ops.wm.collada_export(filepath=file, check_existing=False, selected=True, use_texture_copies=True);
select(object, False)
copy_imgs(tex, odir)
zip_folder(object.name + name_ext + '-dae', dir, odir)
def export_abc(object, dir, tex, name_ext=''):
odir = os.path.join(dir, object.name, 'abc')
os.makedirs(odir, exist_ok=True)
file = os.path.join(odir,object.name+name_ext+'.abc')
select(object, True)
bpy.ops.wm.alembic_export(filepath=file, check_existing=False, selected=True);
select(object, False)
copy_imgs(tex, odir)
zip_folder(object.name + name_ext + '-abc', dir, odir)
def set_subsurf(obj_or_col, set = True ):
if type(obj_or_col) == bpy.types.Collection:
old = []
for i, object in enumerate(obj_or_col.all_objects):
if type(set) == bool:
old.append(set_subsurf(object, set))
else:
old.append(set_subsurf(object, set[i]))
return old
object = obj_or_col
if len(object.modifiers) != 1 or object.modifiers[0].type != 'SUBSURF':
return
subsurf = object.modifiers[0]
old_show_viewport = subsurf.show_viewport
old_show_render = subsurf.show_render
if type(set) == tuple:
subsurf.show_viewport = set[0]
subsurf.show_render = set[1]
else:
subsurf.show_viewport = set
subsurf.show_render = set
return (old_show_viewport, old_show_render)
def has_subsurf(obj_or_col):
if type(obj_or_col) == bpy.types.Collection:
for object in obj_or_col.all_objects:
if len(object.modifiers) == 1 and object.modifiers[0].type == 'SUBSURF' and (object.modifiers[0].show_render or object.modifiers[0].show_viewport):
return True
else:
object = obj_or_col
if len(object.modifiers) == 1 and object.modifiers[0].type == 'SUBSURF' and (object.modifiers[0].show_render or object.modifiers[0].show_viewport):
return True
return False
def process_textures(obj_or_col):
principled = None
if type(obj_or_col) == bpy.types.Collection:
tex = []
for obj in obj_or_col.all_objects:
tex.extend(process_textures(obj))
return tex
object = obj_or_col
for node in object.active_material.node_tree.nodes.values():
#print(node.bl_idname)
if node.bl_idname == 'ShaderNodeBsdfPrincipled':
principled = node
if principled is None:
return
tex_dir = os.path.join(texture_dir, object.name)
textures = []
for inp in principled.inputs:
if len(inp.links) != 1:
continue
node = inp.links[0].from_node
if node.bl_idname == 'ShaderNodeNormalMap':
node = node.inputs.values()[1].links[0].from_node
if node.bl_idname != 'ShaderNodeTexImage':
continue
image = node.image
image.pack()
new_name = object.name +'_'+ simple_slug(inp.name)
image_path = os.path.join(tex_dir, new_name + os.path.splitext(image.filepath_raw)[1] )
os.makedirs(os.path.dirname(image_path), exist_ok = True)
print("Save img:", image.name, image_path)
image.save_render(image_path)
image.filepath_raw = image_path
image.name = new_name
textures.append(image)
zip_folder(object.name + '-textures', texture_dir, tex_dir)
return textures
exporters = [export_obj, export_fbx, export_dae, export_abc]
def main():
objects = []
if EXPORT_SINGLE:
objects = [bpy.context.collection]
else:
objects = bpy.context.selected_objects
bpy.ops.object.select_all(action='DESELECT')
if len(objects) < 1 or objects[0] is None:
print("ERR: No objects or collections selected")
return
for object in objects:
tex = process_textures(object)
if has_subsurf(object):
old = set_subsurf(object, set=False)
for export in exporters: export(object, dir, tex)
set_subsurf(object, set=True)
for export in exporters: export(object, dir, tex, name_ext='_subsurf')
set_subsurf(object, set=old)
else:
for export in exporters: export(object, dir, tex)
print("Done")
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment