mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-22 11:50:53 +00:00
feat(auto_export): continued refactoring & internal improvements
* continued restructure of auto_export internals * split out get_levels_to_export * simplified, cleaned up & made get_collections_to_export more efficient (skipping useless computations based on settings) * moved more settings to addon_prefs, created boilerplate to create copies & inject additional params * modified tracker's use of the above, so that the actual list of future exports is displayed * a lot of other tweaks & cleanups
This commit is contained in:
parent
c2dc0324c3
commit
6a1594188e
@ -1,9 +1,15 @@
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
from types import SimpleNamespace
|
||||
import bpy
|
||||
import traceback
|
||||
|
||||
from .preferences import AutoExportGltfAddonPreferences
|
||||
|
||||
from .get_collections_to_export import get_collections_to_export
|
||||
from .get_levels_to_export import get_levels_to_export
|
||||
from .get_standard_exporter_settings import get_standard_exporter_settings
|
||||
|
||||
from .export_main_scenes import export_main_scene
|
||||
from .export_blueprints import check_if_blueprint_on_disk, check_if_blueprints_exist, export_blueprints_from_collections
|
||||
@ -29,10 +35,37 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
|
||||
|
||||
export_blueprints = getattr(addon_prefs,"export_blueprints")
|
||||
export_output_folder = getattr(addon_prefs,"export_output_folder")
|
||||
export_models_path = os.path.join(folder_path, export_output_folder)
|
||||
|
||||
export_materials_library = getattr(addon_prefs,"export_materials_library")
|
||||
export_scene_settings = getattr(addon_prefs,"export_scene_settings")
|
||||
|
||||
# standard gltf export settings are stored differently
|
||||
standard_gltf_exporter_settings = get_standard_exporter_settings()
|
||||
gltf_extension = standard_gltf_exporter_settings.get("export_format", 'GLB')
|
||||
gltf_extension = '.glb' if gltf_extension == 'GLB' else '.gltf'
|
||||
|
||||
# here we do a bit of workaround by creating an override # TODO: do this at the "UI" level
|
||||
export_blueprints_path = os.path.join(folder_path, export_output_folder, getattr(addon_prefs,"export_blueprints_path")) if getattr(addon_prefs,"export_blueprints_path") != '' else folder_path
|
||||
#print('addon_prefs', AutoExportGltfAddonPreferences.__annotations__)#)addon_prefs.__annotations__)
|
||||
|
||||
if hasattr(addon_prefs, "__annotations__") :
|
||||
tmp = {}
|
||||
for k in AutoExportGltfAddonPreferences.__annotations__:
|
||||
item = AutoExportGltfAddonPreferences.__annotations__[k]
|
||||
print("tutu",k, item.keywords.get('default', None) )
|
||||
default = item.keywords.get('default', None)
|
||||
tmp[k] = default
|
||||
|
||||
for (k, v) in addon_prefs.properties.items():
|
||||
tmp[k] = v
|
||||
|
||||
addon_prefs = SimpleNamespace(**tmp) #copy.deepcopy(addon_prefs)
|
||||
addon_prefs.__annotations__ = tmp
|
||||
addon_prefs.export_blueprints_path = export_blueprints_path
|
||||
addon_prefs.export_gltf_extension = gltf_extension
|
||||
addon_prefs.export_models_path = export_models_path
|
||||
|
||||
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
|
||||
|
||||
print("main scenes", main_scene_names, "library_scenes", library_scene_names)
|
||||
@ -49,14 +82,34 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
|
||||
# export
|
||||
if export_blueprints:
|
||||
print("EXPORTING")
|
||||
# create parent relations for all collections
|
||||
(collections, collections_to_export, main_scenes_to_export, library_collections, collections_per_scene, blueprint_hierarchy, export_levels_path, gltf_extension) = get_collections_to_export(folder_path, export_output_folder, changes_per_scene, changed_export_parameters, addon_prefs)
|
||||
# get blueprints/collections infos
|
||||
(collections, collections_to_export, library_collections, collections_per_scene) = get_collections_to_export(changes_per_scene, changed_export_parameters, addon_prefs)
|
||||
|
||||
# get level/main scenes infos
|
||||
(main_scenes_to_export) = get_levels_to_export(changes_per_scene, changed_export_parameters, addon_prefs)
|
||||
|
||||
# since materials export adds components we need to call this before blueprints are exported
|
||||
# export materials & inject materials components into relevant objects
|
||||
if export_materials_library:
|
||||
export_materials(collections, library_scenes, folder_path, addon_prefs)
|
||||
|
||||
# update the list of tracked exports
|
||||
exports_total = len(collections_to_export) + len(main_scenes_to_export) + (1 if export_materials_library else 0)
|
||||
bpy.context.window_manager.auto_export_tracker.exports_total = exports_total
|
||||
bpy.context.window_manager.auto_export_tracker.exports_count = exports_total
|
||||
|
||||
print("-------------------------------")
|
||||
#print("collections: all:", collections)
|
||||
#print("collections: changed:", changed_collections)
|
||||
#print("collections: not found on disk:", collections_not_on_disk)
|
||||
print("collections: in library:", library_collections)
|
||||
print("collections: to export:", collections_to_export)
|
||||
print("collections: per_scene:", collections_per_scene)
|
||||
print("-------------------------------")
|
||||
print("BLUEPRINTS: to export:", collections_to_export)
|
||||
print("-------------------------------")
|
||||
print("MAIN SCENES: to export:", main_scenes_to_export)
|
||||
print("-------------------------------")
|
||||
# backup current active scene
|
||||
old_current_scene = bpy.context.scene
|
||||
# backup current selections
|
||||
@ -65,24 +118,19 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
|
||||
# first export any main/level/world scenes
|
||||
if len(main_scenes_to_export) > 0:
|
||||
print("export MAIN scenes")
|
||||
for scene_name in main_scene_names:
|
||||
# we have more relaxed rules to determine if the main scenes have changed : any change is ok, (allows easier handling of changes, render settings etc)
|
||||
do_export_main_scene = not export_change_detection or changed_export_parameters or scene_name in changes_per_scene.keys() or not check_if_blueprint_on_disk(scene_name, export_levels_path, gltf_extension)
|
||||
if do_export_main_scene:
|
||||
print(" exporting scene:", scene_name)
|
||||
export_main_scene(bpy.data.scenes[scene_name], folder_path, addon_prefs, library_collections)
|
||||
|
||||
for scene_name in main_scenes_to_export:
|
||||
print(" exporting scene:", scene_name)
|
||||
export_main_scene(bpy.data.scenes[scene_name], folder_path, addon_prefs, library_collections)
|
||||
|
||||
# now deal with blueprints/collections
|
||||
do_export_library_scene = not export_change_detection or changed_export_parameters or len(collections_to_export) > 0 # export_library_scene_name in changes_per_scene.keys()
|
||||
do_export_library_scene = not export_change_detection or changed_export_parameters or len(collections_to_export) > 0
|
||||
if do_export_library_scene:
|
||||
print("export LIBRARY")
|
||||
# we only want to go through the library scenes where our collections to export are present
|
||||
for (scene_name, collections_to_export) in collections_per_scene.items():
|
||||
print(" exporting collections from scene:", scene_name)
|
||||
print(" collections to export", collections_to_export)
|
||||
library_scene = bpy.data.scenes[scene_name]
|
||||
export_blueprints_from_collections(collections_to_export, library_scene, folder_path, addon_prefs, blueprint_hierarchy, collections)
|
||||
export_blueprints_from_collections(collections_to_export, folder_path, addon_prefs, collections)
|
||||
|
||||
# reset current scene from backup
|
||||
bpy.context.window.scene = old_current_scene
|
||||
|
@ -7,7 +7,7 @@ from .export_gltf import (generate_gltf_export_preferences)
|
||||
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
|
||||
|
||||
# export collections: all the collections that have an instance in the main scene AND any marked collections, even if they do not have instances
|
||||
def export_collections(collections, folder_path, library_scene, addon_prefs, gltf_export_preferences, blueprint_hierarchy, library_collections):
|
||||
def export_collections(collections, folder_path, addon_prefs, gltf_export_preferences, library_collections):
|
||||
|
||||
# save current active collection
|
||||
active_collection = bpy.context.view_layer.active_layer_collection
|
||||
@ -35,13 +35,13 @@ def export_collections(collections, folder_path, library_scene, addon_prefs, glt
|
||||
bpy.context.view_layer.active_layer_collection = active_collection
|
||||
|
||||
|
||||
def export_blueprints_from_collections(collections, library_scene, folder_path, addon_prefs, blueprint_hierarchy, library_collections):
|
||||
def export_blueprints_from_collections(collections, folder_path, addon_prefs, library_collections):
|
||||
export_output_folder = getattr(addon_prefs,"export_output_folder")
|
||||
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs)
|
||||
export_blueprints_path = os.path.join(folder_path, export_output_folder, getattr(addon_prefs,"export_blueprints_path")) if getattr(addon_prefs,"export_blueprints_path") != '' else folder_path
|
||||
|
||||
try:
|
||||
export_collections(collections, export_blueprints_path, library_scene, addon_prefs, gltf_export_preferences, blueprint_hierarchy, library_collections)
|
||||
export_collections(collections, export_blueprints_path, addon_prefs, gltf_export_preferences, library_collections)
|
||||
except Exception as error:
|
||||
print("failed to export collections to gltf: ", error)
|
||||
raise error
|
||||
|
@ -1,59 +1,59 @@
|
||||
import os
|
||||
import bpy
|
||||
|
||||
from .get_standard_exporter_settings import get_standard_exporter_settings
|
||||
from .export_blueprints import check_if_blueprint_on_disk, check_if_blueprints_exist, export_blueprints_from_collections
|
||||
from ..helpers.helpers_collections import get_exportable_collections
|
||||
from ..helpers.helpers_collections import (get_collections_in_library, get_exportable_collections, get_collections_per_scene, find_collection_ascendant_target_collection)
|
||||
from ..helpers.helpers_scenes import (get_scenes, )
|
||||
|
||||
def get_collections_to_export(folder_path, export_output_folder, changes_per_scene, changed_export_parameters, addon_prefs):
|
||||
def get_collections_to_export(changes_per_scene, changed_export_parameters, addon_prefs):
|
||||
export_change_detection = getattr(addon_prefs, "export_change_detection")
|
||||
export_materials_library = getattr(addon_prefs,"export_materials_library")
|
||||
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension", ".glb")
|
||||
export_blueprints_path = getattr(addon_prefs,"export_blueprints_path", "")
|
||||
|
||||
# standard gltf export settings are stored differently
|
||||
standard_gltf_exporter_settings = get_standard_exporter_settings()
|
||||
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
|
||||
|
||||
collection_parents = dict()
|
||||
for collection in bpy.data.collections:
|
||||
collection_parents[collection.name] = None
|
||||
for collection in bpy.data.collections:
|
||||
for ch in collection.children:
|
||||
collection_parents[ch.name] = collection.name
|
||||
|
||||
# get a list of all collections actually in use
|
||||
(collections, blueprint_hierarchy) = get_exportable_collections(level_scenes, library_scenes, addon_prefs)
|
||||
collections_to_export = collections # just for clarity
|
||||
|
||||
# first check if all collections have already been exported before (if this is the first time the exporter is run
|
||||
# in your current Blender session for example)
|
||||
export_blueprints_path = os.path.join(folder_path, export_output_folder, getattr(addon_prefs,"export_blueprints_path")) if getattr(addon_prefs,"export_blueprints_path") != '' else folder_path
|
||||
export_levels_path = os.path.join(folder_path, export_output_folder)
|
||||
print("export_change_detection", export_change_detection, export_gltf_extension, export_blueprints_path)
|
||||
|
||||
# if the export parameters have changed, bail out early
|
||||
# we need to re_export everything if the export parameters have been changed
|
||||
if export_change_detection and not changed_export_parameters:
|
||||
changed_collections = []
|
||||
|
||||
gltf_extension = standard_gltf_exporter_settings.get("export_format", 'GLB')
|
||||
gltf_extension = '.glb' if gltf_extension == 'GLB' else '.gltf'
|
||||
collections_not_on_disk = check_if_blueprints_exist(collections, export_blueprints_path, gltf_extension)
|
||||
changed_collections = []
|
||||
# first check if all collections have already been exported before (if this is the first time the exporter is run
|
||||
# in your current Blender session for example)
|
||||
collections_not_on_disk = check_if_blueprints_exist(collections, export_blueprints_path, export_gltf_extension)
|
||||
|
||||
for scene, objects in changes_per_scene.items():
|
||||
print(" changed scene", scene)
|
||||
for obj_name, obj in objects.items():
|
||||
object_collections = list(obj.users_collection) if hasattr(obj, 'users_collection') else []
|
||||
object_collection_names = list(map(lambda collection: collection.name, object_collections))
|
||||
# create parent relations for all collections # TODO: optimise this
|
||||
collection_parents = dict()
|
||||
for collection in bpy.data.collections:
|
||||
collection_parents[collection.name] = None
|
||||
for collection in bpy.data.collections:
|
||||
for ch in collection.children:
|
||||
collection_parents[ch.name] = collection.name
|
||||
|
||||
if len(object_collection_names) > 1:
|
||||
print("ERRROR for",obj_name,"objects in multiple collections not supported")
|
||||
else:
|
||||
object_collection_name = object_collection_names[0] if len(object_collection_names) > 0 else None
|
||||
#recurse updwards until we find one of our collections (or not)
|
||||
matching_collection = find_collection_ascendant_target_collection(collection_parents, collections, object_collection_name)
|
||||
if matching_collection is not None:
|
||||
changed_collections.append(matching_collection)
|
||||
# determine which collections have changed
|
||||
for scene, objects in changes_per_scene.items():
|
||||
print(" changed scene", scene)
|
||||
for obj_name, obj in objects.items():
|
||||
object_collections = list(obj.users_collection) if hasattr(obj, 'users_collection') else []
|
||||
object_collection_names = list(map(lambda collection: collection.name, object_collections))
|
||||
|
||||
collections_to_export = list(set(changed_collections + collections_not_on_disk)) if export_change_detection else collections
|
||||
if len(object_collection_names) > 1:
|
||||
print("ERRROR for",obj_name,"objects in multiple collections not supported")
|
||||
else:
|
||||
object_collection_name = object_collection_names[0] if len(object_collection_names) > 0 else None
|
||||
#recurse updwards until we find one of our collections (or not)
|
||||
matching_collection = find_collection_ascendant_target_collection(collection_parents, collections, object_collection_name)
|
||||
if matching_collection is not None:
|
||||
changed_collections.append(matching_collection)
|
||||
|
||||
# we need to re_export everything if the export parameters have been changed # TODO: perhaps do this BEFORE the rest above for better perfs
|
||||
collections_to_export = collections if changed_export_parameters else collections_to_export
|
||||
collections_to_export = list(set(changed_collections + collections_not_on_disk))
|
||||
|
||||
# this needs to be done based on all previously collected collections, not the ones that we filter out based on their presence in the library scenes
|
||||
collections_per_scene = get_collections_per_scene(collections_to_export, library_scenes)
|
||||
|
||||
# collections that do not come from a library should not be exported as seperate blueprints
|
||||
@ -61,27 +61,5 @@ def get_collections_to_export(folder_path, export_output_folder, changes_per_sce
|
||||
library_collections = get_collections_in_library(library_scenes)
|
||||
collections_to_export = list(set(collections_to_export).intersection(set(library_collections)))
|
||||
|
||||
|
||||
main_scenes_to_export = [scene_name for scene_name in main_scene_names if not export_change_detection or changed_export_parameters or scene_name in changes_per_scene.keys() or not check_if_blueprint_on_disk(scene_name, export_levels_path, gltf_extension)]
|
||||
|
||||
# update the list of tracked exports
|
||||
exports_total = len(collections_to_export) + len(main_scenes_to_export) + (1 if export_materials_library else 0)
|
||||
bpy.context.window_manager.auto_export_tracker.exports_total = exports_total
|
||||
bpy.context.window_manager.auto_export_tracker.exports_count = exports_total
|
||||
|
||||
|
||||
|
||||
print("-------------------------------")
|
||||
print("collections: all:", collections)
|
||||
print("collections: changed:", changed_collections)
|
||||
print("collections: not found on disk:", collections_not_on_disk)
|
||||
print("collections: in library:", library_collections)
|
||||
print("collections: to export:", collections_to_export)
|
||||
print("collections: per_scene:", collections_per_scene)
|
||||
print("-------------------------------")
|
||||
print("BLUEPRINTS: to export:", collections_to_export)
|
||||
print("-------------------------------")
|
||||
print("MAIN SCENES: to export:", main_scenes_to_export)
|
||||
print("-------------------------------")
|
||||
|
||||
return (collections, collections_to_export, main_scenes_to_export, library_collections, collections_per_scene, blueprint_hierarchy, export_levels_path, gltf_extension)
|
||||
# all collections, collections to export
|
||||
return (collections, collections_to_export, library_collections, collections_per_scene)
|
15
tools/gltf_auto_export/auto_export/get_levels_to_export.py
Normal file
15
tools/gltf_auto_export/auto_export/get_levels_to_export.py
Normal file
@ -0,0 +1,15 @@
|
||||
import bpy
|
||||
from .export_blueprints import check_if_blueprint_on_disk
|
||||
from ..helpers.helpers_scenes import (get_scenes, )
|
||||
|
||||
def get_levels_to_export(changes_per_scene, changed_export_parameters, addon_prefs):
|
||||
export_change_detection = getattr(addon_prefs, "export_change_detection")
|
||||
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
|
||||
export_models_path = getattr(addon_prefs, "export_models_path")
|
||||
|
||||
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
|
||||
|
||||
# determine list of main scenes to export
|
||||
# we have more relaxed rules to determine if the main scenes have changed : any change is ok, (allows easier handling of changes, render settings etc)
|
||||
main_scenes_to_export = [scene_name for scene_name in main_scene_names if not export_change_detection or changed_export_parameters or scene_name in changes_per_scene.keys() or not check_if_blueprint_on_disk(scene_name, export_models_path, export_gltf_extension)]
|
||||
return (main_scenes_to_export)
|
@ -1,13 +1,18 @@
|
||||
import json
|
||||
import os
|
||||
from types import SimpleNamespace
|
||||
import bpy
|
||||
|
||||
from bpy.types import (PropertyGroup)
|
||||
from bpy.props import (PointerProperty, IntProperty, StringProperty)
|
||||
|
||||
from .get_collections_to_export import get_collections_to_export
|
||||
|
||||
from ..constants import TEMPSCENE_PREFIX
|
||||
from .internals import CollectionsToExport
|
||||
from ..helpers.helpers_scenes import (get_scenes)
|
||||
from ..helpers.helpers_collections import (get_exportable_collections)
|
||||
from .preferences import AutoExportGltfAddonPreferences
|
||||
|
||||
class AutoExportTracker(PropertyGroup):
|
||||
|
||||
@ -135,16 +140,44 @@ class AutoExportTracker(PropertyGroup):
|
||||
|
||||
# get a list of exportable collections for display
|
||||
# keep it simple, just use Simplenamespace for compatibility with the rest of our code
|
||||
addon_prefs = SimpleNamespace(**get_auto_exporter_settings())
|
||||
print("addon prefs", addon_prefs)
|
||||
addon_prefs.export_marked_assets = True
|
||||
[_, level_scenes, _, library_scenes] = get_scenes(addon_prefs)
|
||||
(collections, _) = get_exportable_collections(level_scenes, library_scenes, addon_prefs)
|
||||
|
||||
tmp = {}
|
||||
for k in AutoExportGltfAddonPreferences.__annotations__:
|
||||
item = AutoExportGltfAddonPreferences.__annotations__[k]
|
||||
print("tutu",k, item.keywords.get('default', None) )
|
||||
default = item.keywords.get('default', None)
|
||||
tmp[k] = default
|
||||
auto_settings = get_auto_exporter_settings()
|
||||
for k in auto_settings:
|
||||
print("k", k, auto_settings[k])
|
||||
tmp[k] = auto_settings[k]
|
||||
tmp['__annotations__'] = tmp
|
||||
|
||||
# path to the current blend file
|
||||
file_path = bpy.data.filepath
|
||||
# Get the folder
|
||||
folder_path = os.path.dirname(file_path)
|
||||
export_output_folder =tmp["export_output_folder"]
|
||||
export_models_path = os.path.join(folder_path, export_output_folder)
|
||||
export_blueprints_path = os.path.join(folder_path, export_output_folder, tmp["export_blueprints_path"]) if tmp["export_blueprints_path"] != '' else folder_path
|
||||
tmp["export_blueprints_path"] = export_blueprints_path
|
||||
tmp["export_models_path"] = export_models_path
|
||||
addon_prefs = SimpleNamespace(**tmp)
|
||||
|
||||
#
|
||||
|
||||
#addon_prefs.export_blueprints_path = export_blueprints_path
|
||||
#addon_prefs.export_gltf_extension = gltf_extension
|
||||
#addon_prefs.export_models_path = export_models_path
|
||||
|
||||
|
||||
(collections, collections_to_export, library_collections, collections_per_scene) = get_collections_to_export(cls.changed_objects_per_scene, False, addon_prefs)
|
||||
print("collections to export", collections_to_export)
|
||||
try:
|
||||
# we save this list of collections in the context
|
||||
bpy.context.window_manager.exportedCollections.clear()
|
||||
#TODO: add error handling for this
|
||||
for collection_name in collections:
|
||||
for collection_name in collections_to_export:
|
||||
ui_info = bpy.context.window_manager.exportedCollections.add()
|
||||
ui_info.name = collection_name
|
||||
except Exception as error:
|
||||
|
@ -138,25 +138,16 @@ def get_collections_per_scene(collection_names, library_scenes):
|
||||
return collections_per_scene
|
||||
|
||||
def get_collections_in_library(library_scenes):
|
||||
"""all_collections = []
|
||||
all_collection_names = []
|
||||
for main_scene in main_scenes:
|
||||
(collection_names, collections) = get_used_collections(main_scene)
|
||||
all_collection_names = all_collection_names + list(collection_names)
|
||||
all_collections = all_collections + collections"""
|
||||
|
||||
# now that we have the collections that are in use by collection instances, check if those collections are actully present in the library scenes
|
||||
collections = []
|
||||
collection_names = []
|
||||
for library_scene in library_scenes:
|
||||
root_collection = library_scene.collection
|
||||
|
||||
for collection in traverse_tree(root_collection):
|
||||
collections.append(collection)
|
||||
collection_names.append(collection.name)
|
||||
return collection_names
|
||||
|
||||
|
||||
def get_collection_hierarchy(root_col, levels=1):
|
||||
"""Read hierarchy of the collections in the scene"""
|
||||
level_lookup = {}
|
||||
|
Loading…
Reference in New Issue
Block a user