Skip to content

Commit

Permalink
feat(gltf_auto_export): removed blueprints specific created_nested/cl…
Browse files Browse the repository at this point in the history
…ear_blueprint_hollow_scene !

 * unified with main variants of those functions
 * made adapted changes where relevant
  • Loading branch information
kaosat-dev committed Feb 4, 2024
1 parent bb4cc73 commit 129508f
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 168 deletions.
160 changes: 4 additions & 156 deletions tools/gltf_auto_export/auto_export/export_blueprints.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import os
import bpy


from .object_makers import make_empty
from .export_gltf import (export_gltf, generate_gltf_export_preferences)
from ..helpers_collections import find_layer_collection_recursive, recurLayerCollection
from ..helpers_scenes import clear_hollow_scene, generate_hollow_scene

# 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):
Expand Down Expand Up @@ -35,11 +37,11 @@ def export_collections(collections, folder_path, library_scene, addon_prefs, glt
#print("generate hollow scene for nested blueprints", library_collections)
backup = bpy.context.window.scene
collection = bpy.data.collections[collection_name]
(hollow_scene, temporary_collections, root_objects, special_properties) = generate_blueprint_hollow_scene(collection, library_collections, addon_prefs)
(hollow_scene, temporary_collections, root_objects, special_properties) = generate_hollow_scene(collection, library_collections, addon_prefs, name="__temp_scene_"+collection.name)

export_gltf(gltf_output_path, export_settings)

clear_blueprint_hollow_scene(hollow_scene, collection, temporary_collections, root_objects, special_properties)
clear_hollow_scene(hollow_scene, collection, temporary_collections, root_objects, special_properties)
bpy.context.window.scene = backup
else:
#print("standard export")
Expand All @@ -64,160 +66,6 @@ def export_blueprints_from_collections(collections, library_scene, folder_path,
# TODO : rethrow
raise error


def generate_blueprint_hollow_scene(blueprint_collection, library_collections, addon_prefs):
collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode")

temp_scene = bpy.data.scenes.new(name="temp_scene_"+blueprint_collection.name)
temp_scene_root_collection = temp_scene.collection

# we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene
bpy.context.window.scene = temp_scene
found = find_layer_collection_recursive(temp_scene_root_collection, bpy.context.view_layer.layer_collection)
if found:
# once it's found, set the active layer collection to the one we found
bpy.context.view_layer.active_layer_collection = found

original_names = []
temporary_collections = []
root_objects = []
special_properties= { # to be able to reset any special property afterwards
"combine": [],
}

# TODO also add the handling for "template" flags, so that instead of creating empties we link the data from the sub collection INTO the parent collection
# copies the contents of a collection into another one while replacing blueprint instances with empties
# if we have combine_mode set to "Inject", we take all the custom attributed of the nested (1 level only ! unless we use 'deepMerge') custom attributes and copy them to this level
def copy_hollowed_collection_into(source_collection, destination_collection, parent_empty=None):
for object in source_collection.objects:
combine_mode = object['_combine'] if '_combine' in object else collection_instances_combine_mode

if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in library_collections)) ):

# get the name of the collection this is an instance of
collection_name = object.instance_collection.name
"""
blueprint_template = object['Template'] if 'Template' in object else False
if blueprint_template and parent_empty is None: # ONLY WORKS AT ROOT LEVEL
print("BLUEPRINT TEMPLATE", blueprint_template, destination_collection, parent_empty)
for object in source_collection.objects:
if object.type == 'EMPTY' and object.name.endswith("components"):
original_collection = bpy.data.collections[collection_name]
components_holder = object
print("WE CAN INJECT into", object, "data from", original_collection)
# now we look for components inside the collection
components = {}
for object in original_collection.objects:
if object.type == 'EMPTY' and object.name.endswith("components"):
for component_name in object.keys():
if component_name not in '_RNA_UI':
print( component_name , "-" , object[component_name] )
components[component_name] = object[component_name]
# copy template components into target object
for key in components:
print("copying ", key,"to", components_holder)
if not key in components_holder:
components_holder[key] = components[key]
"""

original_name = object.name
original_names.append(original_name)

object.name = original_name + "____bak"
empty_obj = make_empty(original_name, object.location, object.rotation_euler, object.scale, destination_collection)
"""we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object"""
empty_obj['BlueprintName'] = '"'+collection_name+'"'
empty_obj['SpawnHere'] = ''


for k, v in object.items():
if k != 'template' or k != '_combine': # do not copy these properties
empty_obj[k] = v

if parent_empty is not None:
empty_obj.parent = parent_empty
else:
# we backup special properties that we do not want to export, and remove them
if '_combine' in object:
special_properties["combine"].append((object, object['_combine']))
del object['_combine']

if parent_empty is not None:
object.parent = parent_empty
destination_collection.objects.link(object)
else:
root_objects.append(object)
destination_collection.objects.link(object)

# for every sub-collection of the source, copy its content into a new sub-collection of the destination
for collection in source_collection.children:
original_name = collection.name
collection.name = original_name + "____bak"
collection_placeholder = make_empty(original_name, [0,0,0], [0,0,0], [1,1,1], destination_collection)

if parent_empty is not None:
collection_placeholder.parent = parent_empty

copy_hollowed_collection_into(collection, destination_collection, collection_placeholder)

"""
copy_collection = bpy.data.collections.new(collection.name + "____collection_export")
# save the newly created collection for later reuse
temporary_collections.append(copy_collection)
# copy & link objects
copy_hollowed_collection_into(collection, copy_collection)
destination_collection.children.link(copy_collection)"""

copy_hollowed_collection_into(blueprint_collection, temp_scene_root_collection)

return (temp_scene, temporary_collections, root_objects, special_properties)


# clear & remove "hollow scene"
def clear_blueprint_hollow_scene(temp_scene, original_collection, temporary_collections, root_objects, special_properties):

def restore_original_names(collection):
if collection.name.endswith("____bak"):
collection.name = collection.name.replace("____bak", "")
for object in collection.objects:
if object.instance_type == 'COLLECTION':
if object.name.endswith("____bak"):
object.name = object.name.replace("____bak", "")
for child_collection in collection.children:
restore_original_names(child_collection)

restore_original_names(original_collection)

# remove empties (only needed when we go via ops ????)
temp_root_collection = temp_scene.collection
temp_scene_objects = [o for o in temp_root_collection.objects]
for object in temp_scene_objects:
if object.type == 'EMPTY':
if hasattr(object, "SpawnHere"):
bpy.data.objects.remove(object, do_unlink=True)
else:
bpy.context.scene.collection.objects.unlink(object)
if object in root_objects:
pass
else:
bpy.data.objects.remove(object, do_unlink=True)
else:
bpy.context.scene.collection.objects.unlink(object)

# put back special properties
for (object, value) in special_properties["combine"]:
object['_combine'] = value

# remove temporary collections
for collection in temporary_collections:
bpy.data.collections.remove(collection)

bpy.data.scenes.remove(temp_scene)


# TODO : add a flag to also search of deeply nested components
def get_nested_components(object):
if object.instance_type == 'COLLECTION':
Expand Down
8 changes: 4 additions & 4 deletions tools/gltf_auto_export/auto_export/export_main_scenes.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
bpy.context.window.scene = hollow_scene
print(" exporting gltf to", gltf_output_path, ".gltf/glb")
export_gltf(gltf_output_path, export_settings)
clear_hollow_scene(hollow_scene, scene, temporary_collections, root_objects, special_properties)
clear_hollow_scene(hollow_scene, scene.collection, temporary_collections, root_objects, special_properties)


# now export static objects
Expand All @@ -46,13 +46,13 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
bpy.context.window.scene = hollow_scene
print(" exporting gltf to", gltf_output_path, ".gltf/glb")
export_gltf(gltf_output_path, export_settings)
clear_hollow_scene(hollow_scene, scene, temporary_collections, root_objects, special_properties)
clear_hollow_scene(hollow_scene, scene.collection, temporary_collections, root_objects, special_properties)

else:
#print("NO SPLIT")

# todo: add exception handling
(hollow_scene, temporary_collections, root_objects, special_properties) = generate_hollow_scene(scene, library_collections, addon_prefs)
(hollow_scene, temporary_collections, root_objects, special_properties) = generate_hollow_scene(scene.collection, library_collections, addon_prefs, name="__temp_scene")
# set active scene to be the given scene
bpy.context.window.scene = hollow_scene
print("context scene", bpy.context.scene, "window scene", bpy.context.window.scene, bpy.context.scene == bpy.context.window.scene)
Expand All @@ -63,7 +63,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
print(" exporting gltf to", gltf_output_path, ".gltf/glb")
export_gltf(gltf_output_path, export_settings)

clear_hollow_scene(hollow_scene, scene, temporary_collections, root_objects, special_properties)
clear_hollow_scene(hollow_scene, scene.collection, temporary_collections, root_objects, special_properties)
else:
print(" exporting gltf to", gltf_output_path, ".gltf/glb")
export_gltf(gltf_output_path, export_settings)
Expand Down
74 changes: 66 additions & 8 deletions tools/gltf_auto_export/helpers_scenes.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import bpy
from .helpers_collections import (find_layer_collection_recursive)
from .helpers_collections import (find_layer_collection_recursive, set_active_collection)
from .auto_export.object_makers import (make_empty)

# generate a copy of a scene that replaces collection instances with empties
# copy original names before creating a new scene, & reset them
def generate_hollow_scene(scene, library_collections, addon_prefs, filter=None):

def export_bla(scene, library_collections, addon_prefs, filter=None):
collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode")

root_collection = scene.collection
Expand All @@ -14,6 +13,62 @@ def generate_hollow_scene(scene, library_collections, addon_prefs, filter=None):
# we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene
bpy.context.window.scene = temp_scene

with bpy.context.temp_override(scene=temp_scene):
print("context inside", bpy.context.scene)
set_active_collection(bpy.context.scene, copy_root_collection.name)


# restore everything
clear_hollow_scene(hollow_scene, scene, temporary_collections, root_objects, special_properties)
bpy.context.window.scene = scene


"""
backup = bpy.context.window.scene
collection = bpy.data.collections[collection_name]
(hollow_scene, temporary_collections, root_objects, special_properties) = generate_blueprint_hollow_scene(collection, library_collections, addon_prefs)
export_gltf(gltf_output_path, export_settings)
clear_blueprint_hollow_scene(hollow_scene, collection, temporary_collections, root_objects, special_properties)
bpy.context.window.scene = backup
"""
"""
blueprint_template = object['Template'] if 'Template' in object else False
if blueprint_template and parent_empty is None: # ONLY WORKS AT ROOT LEVEL
print("BLUEPRINT TEMPLATE", blueprint_template, destination_collection, parent_empty)
for object in source_collection.objects:
if object.type == 'EMPTY' and object.name.endswith("components"):
original_collection = bpy.data.collections[collection_name]
components_holder = object
print("WE CAN INJECT into", object, "data from", original_collection)
# now we look for components inside the collection
components = {}
for object in original_collection.objects:
if object.type == 'EMPTY' and object.name.endswith("components"):
for component_name in object.keys():
if component_name not in '_RNA_UI':
print( component_name , "-" , object[component_name] )
components[component_name] = object[component_name]
# copy template components into target object
for key in components:
print("copying ", key,"to", components_holder)
if not key in components_holder:
components_holder[key] = components[key]
"""
# generate a copy of a scene that replaces collection instances with empties
# copy original names before creating a new scene, & reset them
def generate_hollow_scene(original_root_collection, library_collections, addon_prefs, name="__temp_scene", filter=None):
collection_instances_combine_mode = getattr(addon_prefs, "collection_instances_combine_mode")

temp_scene = bpy.data.scenes.new(name=name)
copy_root_collection = temp_scene.collection

# we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene
bpy.context.window.scene = temp_scene

found = find_layer_collection_recursive(copy_root_collection, bpy.context.view_layer.layer_collection)
if found:
# once it's found, set the active layer collection to the one we found
Expand All @@ -26,6 +81,10 @@ def generate_hollow_scene(scene, library_collections, addon_prefs, filter=None):
"combine": [],
}

# TODO also add the handling for "template" flags, so that instead of creating empties we link the data from the sub collection INTO the parent collection
# copies the contents of a collection into another one while replacing blueprint instances with empties
# if we have combine_mode set to "Inject", we take all the custom attributed of the nested (1 level only ! unless we use 'deepMerge') custom attributes and copy them to this level

# copies the contents of a collection into another one while replacing library instances with empties
def copy_hollowed_collection_into(source_collection, destination_collection, parent_empty=None):
for object in source_collection.objects:
Expand Down Expand Up @@ -77,12 +136,12 @@ def copy_hollowed_collection_into(source_collection, destination_collection, par

copy_hollowed_collection_into(collection, destination_collection, collection_placeholder)

copy_hollowed_collection_into(root_collection, copy_root_collection)
copy_hollowed_collection_into(original_root_collection, copy_root_collection)

return (temp_scene, temporary_collections, root_objects, special_properties)

# clear & remove "hollow scene"
def clear_hollow_scene(temp_scene, original_scene, temporary_collections, root_objects, special_properties):
def clear_hollow_scene(temp_scene, original_root_collection, temporary_collections, root_objects, special_properties):

def restore_original_names(collection):
if collection.name.endswith("____bak"):
Expand All @@ -95,8 +154,7 @@ def restore_original_names(collection):
restore_original_names(child_collection)

# reset original names
root_collection = original_scene.collection
restore_original_names(root_collection)
restore_original_names(original_root_collection)

# remove empties (only needed when we go via ops ????)
temp_root_collection = temp_scene.collection
Expand Down

0 comments on commit 129508f

Please sign in to comment.