From 478be88a55ef2185a9aa87c76302dd9b1033fc8e Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Sun, 7 Jul 2024 22:06:16 +0200 Subject: [PATCH] feat(Blenvy:Blender): * fixed issue with parenting due to Blender's very weird matrix_parent_inverse ... solves all issues with children of empties blueprint instances within blueprint instances etc having the wrong transforms in some cases * fixed bad gltf format propagation: semi ok solution, but a cleaner one would be better * added additional custom properties to the blacklist , level/blueprint exports are now using the one in the constants instead of a local copy * minor tweaks & cleanups --- tools/blenvy/TODO.md | 3 ++- .../add_ons/auto_export/common/auto_export.py | 16 +++++++--------- .../auto_export/common/duplicate_object.py | 4 ++++ .../add_ons/auto_export/common/export_gltf.py | 5 ++++- .../generate_temporary_scene_and_export.py | 5 ++--- tools/blenvy/add_ons/auto_export/constants.py | 11 +++++++++-- .../auto_export/levels/export_main_scenes.py | 9 +++++++-- tools/blenvy/assets/assets_scan.py | 6 +++--- tools/blenvy/blueprints/blueprint_helpers.py | 17 +++++++++++++++-- tools/blenvy/materials/materials_helpers.py | 2 +- tools/blenvy/tests/test_bevy_integration.py | 10 +++++++--- .../tests/test_bevy_integration_simple.py | 1 + 12 files changed, 62 insertions(+), 27 deletions(-) diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index 03e83c6..ff6a483 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -199,7 +199,8 @@ Blender side: - [ ] disabled components - [ ] blueprint instances as children of blueprint instances - [ ] blueprint instances as children of empties -- [x] update testing files +- [x] update testing blend files +- [ ] disable 'export_hierarchy_full_collections' for all cases: not reliable and redudant - [ ] add option to 'split out' meshes from blueprints ? diff --git a/tools/blenvy/add_ons/auto_export/common/auto_export.py b/tools/blenvy/add_ons/auto_export/common/auto_export.py index cf64c73..ab38da9 100644 --- a/tools/blenvy/add_ons/auto_export/common/auto_export.py +++ b/tools/blenvy/add_ons/auto_export/common/auto_export.py @@ -21,16 +21,11 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): # have the export parameters (not auto export, just gltf export) have changed: if yes (for example switch from glb to gltf, compression or not, animations or not etc), we need to re-export everything print ("changed_export_parameters", changed_export_parameters) try: - # path to the current blend file - file_path = bpy.data.filepath - # Get the folder - blend_file_path = os.path.dirname(file_path) - #should we use change detection or not change_detection = getattr(settings.auto_export, "change_detection") - export_scene_settings = getattr(settings.auto_export,"export_scene_settings") - do_export_blueprints = getattr(settings.auto_export,"export_blueprints") - export_materials_library = getattr(settings.auto_export,"export_materials_library") + export_scene_settings = getattr(settings.auto_export, "export_scene_settings") + do_export_blueprints = getattr(settings.auto_export, "export_blueprints") + export_materials_library = getattr(settings.auto_export, "export_materials_library") # standard gltf export settings are stored differently standard_gltf_exporter_settings = get_standard_exporter_settings() @@ -47,7 +42,10 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): # we inject the blueprints export path blueprints_path = getattr(settings,"blueprints_path") - inject_export_path_into_internal_blueprints(internal_blueprints=blueprints_data.internal_blueprints, blueprints_path=blueprints_path, gltf_extension=gltf_extension) + # inject the "export_path" and "material_path" properties into the internal blueprints + inject_export_path_into_internal_blueprints(internal_blueprints=blueprints_data.internal_blueprints, blueprints_path=blueprints_path, gltf_extension=gltf_extension, settings=settings) + + for blueprint in blueprints_data.blueprints: bpy.context.window_manager.blueprints_registry.add_blueprint(blueprint) #bpy.context.window_manager.blueprints_registry.refresh_blueprints() diff --git a/tools/blenvy/add_ons/auto_export/common/duplicate_object.py b/tools/blenvy/add_ons/auto_export/common/duplicate_object.py index 22af988..a3a6ddb 100644 --- a/tools/blenvy/add_ons/auto_export/common/duplicate_object.py +++ b/tools/blenvy/add_ons/auto_export/common/duplicate_object.py @@ -119,6 +119,10 @@ def duplicate_object(object, parent, combine_mode, destination_collection, bluep # do this both for empty replacements & normal copies if parent is not None: copy.parent = parent + # without this, the copy"s offset from parent (if any ) will not be set correctly ! + # see here for example https://blender.stackexchange.com/questions/3763/parenting-messes-up-transforms-where-is-the-offset-stored + copy.matrix_parent_inverse = object.matrix_parent_inverse + remove_unwanted_custom_properties(copy) copy_animation_data(object, copy) diff --git a/tools/blenvy/add_ons/auto_export/common/export_gltf.py b/tools/blenvy/add_ons/auto_export/common/export_gltf.py index 24ae8e6..fc72ce0 100644 --- a/tools/blenvy/add_ons/auto_export/common/export_gltf.py +++ b/tools/blenvy/add_ons/auto_export/common/export_gltf.py @@ -24,6 +24,7 @@ def generate_gltf_export_settings(settings): export_cameras=True, export_extras=True, # For custom exported properties. export_lights=True, + export_hierarchy_full_collections=False #export_texcoords=True, #export_normals=True, @@ -54,6 +55,7 @@ def generate_gltf_export_settings(settings): standard_gltf_exporter_settings = get_standard_exporter_settings() + # these essential params should NEVER be overwritten , no matter the settings of the standard exporter constant_keys = [ 'use_selection', 'use_visible', @@ -63,9 +65,10 @@ def generate_gltf_export_settings(settings): 'export_cameras', 'export_extras', # For custom exported properties. 'export_lights', + 'export_hierarchy_full_collections' ] - # a certain number of essential params should NEVER be overwritten , no matter the settings of the standard exporter + # for key in standard_gltf_exporter_settings.keys(): if str(key) not in constant_keys: gltf_export_settings[key] = standard_gltf_exporter_settings.get(key) diff --git a/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py b/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py index 05bbe75..191f2bb 100644 --- a/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py +++ b/tools/blenvy/add_ons/auto_export/common/generate_temporary_scene_and_export.py @@ -5,7 +5,7 @@ from blenvy.core.object_makers import (make_empty) from .duplicate_object import duplicate_object from .export_gltf import export_gltf from blenvy.core.scene_helpers import add_scene_property - +from ..constants import custom_properties_to_filter_out """ generates a temporary scene, fills it with data, cleans up after itself * named using temp_scene_name @@ -19,7 +19,7 @@ def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_out temp_scene = bpy.data.scenes.new(name=temp_scene_name) temp_root_collection = temp_scene.collection - properties_black_list = ['glTF2ExportSettings', 'assets', 'user_assets', 'components_meta', 'Components_meta', 'Generated_assets', 'generated_assets'] + properties_black_list = custom_properties_to_filter_out if additional_data is not None: # FIXME not a fan of having this here for entry in dict(additional_data): # we copy everything over except those on the black list @@ -75,7 +75,6 @@ def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_out # 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, filter=None, blueprints_data=None, settings={}): collection_instances_combine_mode = getattr(settings.auto_export, "collection_instances_combine_mode") - for object in source_collection.objects: if object.name.endswith("____bak"): # some objects could already have been handled, ignore them continue diff --git a/tools/blenvy/add_ons/auto_export/constants.py b/tools/blenvy/add_ons/auto_export/constants.py index 68664d4..8b13750 100644 --- a/tools/blenvy/add_ons/auto_export/constants.py +++ b/tools/blenvy/add_ons/auto_export/constants.py @@ -1,4 +1,11 @@ TEMPSCENE_PREFIX = "__temp_scene" -#hard coded custom properties to ignore -custom_properties_to_filter_out = ['_combine', 'template', 'components_meta'] +#hard coded custom properties to ignore on export +custom_properties_to_filter_out = [ + 'glTF2ExportSettings', + 'assets', 'user_assets', 'Generated_assets', 'generated_assets', + 'components_meta', 'Components_meta', + '_combine', 'template', + 'Blenvy_scene_type', 'blenvy_scene_type' + ] +#['_combine', 'template', 'components_meta', 'Components_meta', 'Blenvy_scene_type'] diff --git a/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py b/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py index 747835f..6ac87ad 100644 --- a/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py +++ b/tools/blenvy/add_ons/auto_export/levels/export_main_scenes.py @@ -55,7 +55,7 @@ def export_main_scene(scene, settings, blueprints_data): auto_assets = [] all_assets = [] - export_gltf_extension = getattr(settings.auto_export, "export_gltf_extension", ".glb") + export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb") blueprints_path = getattr(settings, "blueprints_path") for blueprint in blueprints_in_scene: @@ -64,6 +64,11 @@ def export_main_scene(scene, settings, blueprints_data): else: # get the injected path of the external blueprints blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None + # add their material path + materials_exported_path = blueprint.collection['materials_path'] if 'materials_path' in blueprint.collection else None + auto_assets.append({"name": blueprint.name+"_material", "path": materials_exported_path})#, "generated": True, "internal":blueprint.local, "parent": None}) + + if blueprint_exported_path is not None: # and not does_asset_exist(assets_list, blueprint_exported_path): auto_assets.append({"name": blueprint.name, "path": blueprint_exported_path})#, "generated": True, "internal":blueprint.local, "parent": None}) @@ -80,7 +85,7 @@ def export_main_scene(scene, settings, blueprints_data): materials_library_name = f"{current_project_name}_materials" materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}") material_assets = [{"name": materials_library_name, "path": materials_exported_path}] # we also add the material library as an asset - + print("material_assets", material_assets, "extension", export_gltf_extension) scene["BlueprintAssets"] = assets_to_fake_ron(all_assets + [{"name": asset.name, "path": asset.path} for asset in scene.user_assets] + auto_assets + material_assets) #scene["BlueprintAssets"] = assets_to_fake_ron([{'name':'foo', 'path':'bar'}]) diff --git a/tools/blenvy/assets/assets_scan.py b/tools/blenvy/assets/assets_scan.py index a628a05..c8baae0 100644 --- a/tools/blenvy/assets/assets_scan.py +++ b/tools/blenvy/assets/assets_scan.py @@ -62,7 +62,7 @@ def get_userTextures(): def get_blueprint_assets_tree(blueprint, blueprints_data, parent, settings): blueprints_path = getattr(settings, "blueprints_path") - export_gltf_extension = getattr(settings.auto_export, "export_gltf_extension", ".glb") + export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb") assets_list = [] @@ -91,7 +91,7 @@ def get_blueprint_assets_tree(blueprint, blueprints_data, parent, settings): def get_main_scene_assets_tree(main_scene, blueprints_data, settings): blueprints_path = getattr(settings, "blueprints_path") - export_gltf_extension = getattr(settings.auto_export, "export_gltf_extension", ".glb") + export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb") blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(main_scene.name, None) assets_list = get_user_assets_as_list(main_scene) @@ -123,7 +123,7 @@ def get_main_scene_assets_tree(main_scene, blueprints_data, settings): def get_blueprint_asset_tree(blueprint, blueprints_data, settings): blueprints_path = getattr(settings, "blueprints_path") - export_gltf_extension = getattr(settings.auto_export, "export_gltf_extension", ".glb") + export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb") assets_list = get_user_assets_as_list(blueprint.collection) diff --git a/tools/blenvy/blueprints/blueprint_helpers.py b/tools/blenvy/blueprints/blueprint_helpers.py index 633eeca..5c5834b 100644 --- a/tools/blenvy/blueprints/blueprint_helpers.py +++ b/tools/blenvy/blueprints/blueprint_helpers.py @@ -2,6 +2,8 @@ import os import json import bpy +from pathlib import Path + from ..core.scene_helpers import add_scene_property def find_blueprints_not_on_disk(blueprints, folder_path, extension): @@ -19,12 +21,23 @@ def check_if_blueprint_on_disk(scene_name, folder_path, extension): found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path) return found -def inject_export_path_into_internal_blueprints(internal_blueprints, blueprints_path, gltf_extension): +def inject_export_path_into_internal_blueprints(internal_blueprints, blueprints_path, gltf_extension, settings): + export_materials_library = getattr(settings.auto_export, "export_materials_library") + # FIXME: duplicate of materials stuff + export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb") + materials_path = getattr(settings, "materials_path") + current_project_name = Path(bpy.context.blend_data.filepath).stem + materials_library_name = f"{current_project_name}_materials" + materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}") + for blueprint in internal_blueprints: blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{gltf_extension}") # print("injecting blueprint path", blueprint_exported_path, "for", blueprint.name) - + print("blueprint_exported_path", blueprint_exported_path) blueprint.collection["export_path"] = blueprint_exported_path + if export_materials_library: + blueprint.collection["materials_path"] = materials_exported_path + def inject_blueprints_list_into_main_scene(scene, blueprints_data, settings): project_root_path = getattr(settings, "project_root_path") diff --git a/tools/blenvy/materials/materials_helpers.py b/tools/blenvy/materials/materials_helpers.py index 262056b..4c2c2ab 100644 --- a/tools/blenvy/materials/materials_helpers.py +++ b/tools/blenvy/materials/materials_helpers.py @@ -34,7 +34,7 @@ def get_all_materials(collection_names, library_scenes): def add_material_info_to_objects(materials_per_object, settings): materials_path = getattr(settings, "materials_path") - export_gltf_extension = getattr(settings.auto_export, "export_gltf_extension", ".glb") + export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb") current_project_name = Path(bpy.context.blend_data.filepath).stem materials_library_name = f"{current_project_name}_materials" diff --git a/tools/blenvy/tests/test_bevy_integration.py b/tools/blenvy/tests/test_bevy_integration.py index 8d582ec..a234a11 100644 --- a/tools/blenvy/tests/test_bevy_integration.py +++ b/tools/blenvy/tests/test_bevy_integration.py @@ -122,9 +122,13 @@ def test_export_complex(setup_data): user_asset.path = "audio/fake.mp3" # we have to cheat, since we cannot rely on the data injected when saving the library file (since we are not saving it as part of the tests) - #bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb" - #bpy.data.collections["External_blueprint2"]["export_path"] = "blueprints/External_blueprint2.glb" - #bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb" + bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb" + bpy.data.collections["External_blueprint2"]["export_path"] = "blueprints/External_blueprint2.glb" + bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb" + + bpy.data.collections["External_blueprint"]["materials_path"] = "materials/testing_library_materials.glb" + bpy.data.collections["External_blueprint2"]["materials_path"] = "materials/testing_library_materials.glb" + bpy.data.collections["External_blueprint3"]["materials_path"] = "materials/testing_library_materials.glb" # do the actual exporting prepare_and_export() diff --git a/tools/blenvy/tests/test_bevy_integration_simple.py b/tools/blenvy/tests/test_bevy_integration_simple.py index 595a681..2b0ca14 100644 --- a/tools/blenvy/tests/test_bevy_integration_simple.py +++ b/tools/blenvy/tests/test_bevy_integration_simple.py @@ -80,6 +80,7 @@ def test_export_complex(setup_data): export_props = { } gltf_settings = { + "export_format":"GLTF_SEPARATE", "export_animations": True, "export_optimize_animation_size": False, "export_apply":True