From ba25c3cb20eb834ef7907b953d7ec35c79c4eb99 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Sat, 8 Jun 2024 11:52:13 +0200 Subject: [PATCH] feat(Blenvy): experimenting with injection of assets data into exported scenes/gltf files * added extraction of local/all (wip) assets into auto export * added injection of LocalAssets & AllAssets (unsure) * related tweaks & experiments * also cleaned up asset ui for external assets * started updating the bevy integration tests --- tools/blenvy/TODO.md | 7 ++- .../add_ons/auto_export/common/auto_export.py | 4 +- .../generate_temporary_scene_and_export.py | 20 ++++++- .../auto_export/common/prepare_and_export.py | 2 +- .../auto_export/levels/export_main_scenes.py | 54 +++++++++++++++++-- tools/blenvy/assets/ui.py | 40 +------------- tools/blenvy/blueprints/ui.py | 2 +- tools/blenvy/tests/test_bevy_integration.py | 38 ++++++------- .../tests/test_bevy_integration_prepare.py | 30 +++++------ 9 files changed, 114 insertions(+), 83 deletions(-) diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index 33ee8e2..405bf07 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -111,4 +111,9 @@ General issues: - [x] fix asset file selection - [x] change "assets" tab to "levels"/worlds tab & modify UI accordingly - [ ] add option to 'split out' meshes from blueprints ? - - [ ] ie considering meshletts etc , it would make sense to keep blueprints seperate from purely mesh gltfs \ No newline at end of file + - [ ] ie considering meshletts etc , it would make sense to keep blueprints seperate from purely mesh gltfs + +- [ ] remove 'export_marked_assets' it should be a default setting +- [x] disable/ hide asset editing ui for external assets + +clear && pytest -svv --blender-template ../../testing/bevy_example/art/testing_library.blend --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration_prepare.py && pytest -svv --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration.py \ No newline at end of file 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 e3bc8f0..9509fac 100644 --- a/tools/blenvy/add_ons/auto_export/common/auto_export.py +++ b/tools/blenvy/add_ons/auto_export/common/auto_export.py @@ -105,7 +105,7 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): print("export MAIN scenes") for scene_name in main_scenes_to_export: print(" exporting scene:", scene_name) - export_main_scene(bpy.data.scenes[scene_name], blend_file_path, settings, blueprints_data) + export_main_scene(bpy.data.scenes[scene_name], settings, blueprints_data) # now deal with blueprints/collections do_export_library_scene = not change_detection or changed_export_parameters or len(blueprints_to_export) > 0 @@ -124,7 +124,7 @@ def auto_export(changes_per_scene, changed_export_parameters, settings): else: for scene in settings.main_scenes: - export_main_scene(scene, blend_file_path, settings, []) + export_main_scene(scene, settings, []) 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 7bd0abd..2f5e6ee 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 @@ -1,8 +1,10 @@ +import json import bpy from blenvy.core.helpers_collections import (set_active_collection) 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 """ generates a temporary scene, fills it with data, cleans up after itself @@ -12,11 +14,26 @@ generates a temporary scene, fills it with data, cleans up after itself * cleaned up using tempScene_cleaner """ -def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_output_path, temp_scene_name="__temp_scene", tempScene_filler=None, tempScene_cleaner=None): +def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_output_path, temp_scene_name="__temp_scene", tempScene_filler=None, tempScene_cleaner=None, additional_data=None): temp_scene = bpy.data.scenes.new(name=temp_scene_name) temp_root_collection = temp_scene.collection + print("additional_dataAAAAAAAAAAAAAAAH", additional_data) + if additional_data is not None: # FIXME not a fan of having this here + for entry in dict(additional_data): + print("entry in additional data", entry) + if entry == "local_assets": + temp_scene["local_assets"] = additional_data[entry] # this is for bevy 0.14 + temp_root_collection["local_assets"] = additional_data[entry] # for previous bevy versions, remove when migration done + bla = "[(name: \"test_asset\", path: \"audio/fake.mp3\")]" + add_scene_property(temp_scene, 'assets_components', {"LocalAssets": f"LocalAssets({additional_data[entry]})".replace("'", '')}) + + if entry == entry == "AllAssets": + temp_scene["AllAssets"] = additional_data[entry] + temp_root_collection["AllAssets"] = additional_data[entry] # for previous bevy versions, remove when migration done + add_scene_property(temp_scene, 'assets_components', {"AllAssets": f"AllAssets({additional_data[entry]})".replace("'", '')}) + # save active scene original_scene = bpy.context.window.scene # and selected collection @@ -43,6 +60,7 @@ def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_out scene_filler_data = tempScene_filler(temp_root_collection) # export the temporary scene try: + print("dry_run MODE", settings.auto_export.dry_run) if settings.auto_export.dry_run == "DISABLED": export_gltf(gltf_output_path, gltf_export_settings) except Exception as error: diff --git a/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py b/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py index ebfa07e..20dc0ae 100644 --- a/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py +++ b/tools/blenvy/add_ons/auto_export/common/prepare_and_export.py @@ -18,7 +18,7 @@ def prepare_and_export(): setting_changes = get_setting_changes() print("setting_changes", setting_changes) # do the actual export - blenvy.auto_export.dry_run = 'NO_EXPORT'#'DISABLED'# + # blenvy.auto_export.dry_run = 'NO_EXPORT'#'DISABLED'# auto_export(per_scene_changes, setting_changes, blenvy) # cleanup 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 69f0b8d..0c634ae 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 @@ -1,11 +1,20 @@ +import json import os +from types import SimpleNamespace from blenvy.blueprints.blueprint_helpers import inject_blueprints_list_into_main_scene, remove_blueprints_list_from_main_scene from ..constants import TEMPSCENE_PREFIX from ..common.generate_temporary_scene_and_export import generate_temporary_scene_and_export, copy_hollowed_collection_into, clear_hollow_scene from ..common.export_gltf import (generate_gltf_export_settings, export_gltf) from .is_object_dynamic import is_object_dynamic, is_object_static -def export_main_scene(scene, blend_file_path, settings, blueprints_data): +def assets_to_fake_ron(list_like): + result = [] + for item in list_like: + result.append(f"(name: \"{item['name']}\", path: \"{item['path']}\")") + return result#.join(", ") + + +def export_main_scene(scene, settings, blueprints_data): gltf_export_settings = generate_gltf_export_settings(settings) assets_path_full = getattr(settings,"assets_path_full") levels_path_full = getattr(settings,"levels_path_full") @@ -25,7 +34,44 @@ def export_main_scene(scene, blend_file_path, settings, blueprints_data): if export_blueprints : gltf_output_path = os.path.join(levels_path_full, scene.name) - #inject_blueprints_list_into_main_scene(scene, blueprints_data, settings) + inject_blueprints_list_into_main_scene(scene, blueprints_data, settings) + print("main scene", scene) + for asset in scene.user_assets: + print(" user asset", asset.name, asset.path) + for asset in scene.generated_assets: + print(" generated asset", asset) + """for blueprint in blueprints_data.blueprints_per_scenes[scene.name]: + print("BLUEPRINT", blueprint)""" + blueprint_instances_in_scene = blueprints_data.blueprint_instances_per_main_scene.get(scene.name, {}).keys() + blueprints_in_scene = [blueprints_data.blueprints_per_name[blueprint_name] for blueprint_name in blueprint_instances_in_scene] + #yala = [blueprint.collection.user_assets for blueprint in blueprints_in_scene] + #print("dsfsdf", yala) + auto_assets = [] + + all_assets = [] + + blueprints_path = getattr(settings, "blueprints_path") + export_gltf_extension = getattr(settings.auto_export, "export_gltf_extension", ".glb") + for blueprint in blueprints_in_scene: + if blueprint.local: + blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}") + else: + # get the injected path of the external blueprints + blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else 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}) + + # now also add the assets of the blueprints # TODO: wait no , these should not be a part of the (scene) local assets + for asset in blueprint.collection.user_assets: + print("adding assets of blueprint", asset.name) + all_assets.append({"name": asset.name, "path": asset.path}) + + """for asset in auto_assets: + print(" generated asset", asset.name, asset.path)""" + + scene["local_assets"] = assets_to_fake_ron([{"name": asset.name, "path": asset.path} for asset in scene.user_assets] + auto_assets) + scene["AllAssets"] = assets_to_fake_ron(all_assets + [{"name": asset.name, "path": asset.path} for asset in scene.user_assets] + auto_assets) + if export_separate_dynamic_and_static_objects: #print("SPLIT STATIC AND DYNAMIC") # first export static objects @@ -54,19 +100,21 @@ def export_main_scene(scene, blend_file_path, settings, blueprints_data): generate_temporary_scene_and_export( settings, temp_scene_name=TEMPSCENE_PREFIX, + additional_data = scene, gltf_export_settings=gltf_export_settings, gltf_output_path=gltf_output_path, tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, blueprints_data=blueprints_data, settings=settings), tempScene_cleaner= lambda temp_scene, params: clear_hollow_scene(original_root_collection=scene.collection, temp_scene=temp_scene, **params) ) + remove_blueprints_list_from_main_scene(scene) + else: gltf_output_path = os.path.join(assets_path_full, scene.name) print(" exporting gltf to", gltf_output_path, ".gltf/glb") if settings.auto_export.dry_run == "DISABLED": export_gltf(gltf_output_path, gltf_export_settings) - remove_blueprints_list_from_main_scene(scene) diff --git a/tools/blenvy/assets/ui.py b/tools/blenvy/assets/ui.py index f89ce22..d1c3754 100644 --- a/tools/blenvy/assets/ui.py +++ b/tools/blenvy/assets/ui.py @@ -20,7 +20,7 @@ def draw_assets(layout, name, title, asset_registry, target_type, target_name, e add_possible = does_asset_exist(target, {"path": asset_registry.asset_path_selector}) #"name": asset_registry.asset_name_selector, - if header: + if header and editable: row = header.row() row.alert = add_possible @@ -41,23 +41,6 @@ def draw_assets(layout, name, title, asset_registry, target_type, target_name, e if panel: if editable: row = panel.row() - - - """row.alert = add_possible - row.prop(asset_registry, "asset_name_selector", text="") - row.label(text=asset_registry.asset_path_selector) - asset_selector = row.operator(operator="asset.open_filebrowser", text="", icon="FILE_FOLDER") - - add_asset_layout = row.column() - add_asset_layout.enabled = not add_possible - - add_asset = add_asset_layout.operator(operator="bevyassets.add", text="", icon="ADD") - add_asset.target_type = target_type - add_asset.target_name = target_name - add_asset.asset_name = asset_registry.asset_name_selector - add_asset.asset_type = asset_registry.asset_type_selector - add_asset.asset_path = asset_registry.asset_path_selector""" - #panel.separator() for asset in user_assets: @@ -77,27 +60,6 @@ def draw_assets(layout, name, title, asset_registry, target_type, target_name, e remove_asset.target_type = target_type remove_asset.target_name = target_name remove_asset.asset_path = asset.path - - '''for asset in generated_assets: - row = panel.row() - #row.label(text=asset.name) - #row.label(text=asset.path) - split = row.split(factor=nesting_indent) - col = split.column() - col.label(text=" ") - col = split.column() - - - sub_header, sub_panel = col.panel(f"assets_sub{asset.name}", default_closed=False) - sub_header.label(text=f"{asset.name} ({asset.path})", icon="XRAY") - if sub_panel: - sub_panel.label(text=" some stuff") - """remove_asset = row.operator(operator="bevyassets.remove", text="", icon="TRASH") - remove_asset.target_type = target_type - remove_asset.target_name = target_name - remove_asset.asset_path = asset.path"""''' - - return panel class Blenvy_assets(bpy.types.Panel): diff --git a/tools/blenvy/blueprints/ui.py b/tools/blenvy/blueprints/ui.py index 5664c79..5464b9d 100644 --- a/tools/blenvy/blueprints/ui.py +++ b/tools/blenvy/blueprints/ui.py @@ -77,4 +77,4 @@ class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel): generated_assets = get_generated_assets(blueprint.collection) draw_assets(layout=col, name=blueprint.name, title="Assets", asset_registry=asset_registry, user_assets=user_assets, generated_assets=generated_assets, target_type="BLUEPRINT", target_name=blueprint.name, editable=False) - panel.label(text="External") + panel.label(text="External blueprint, assets are not editable") diff --git a/tools/blenvy/tests/test_bevy_integration.py b/tools/blenvy/tests/test_bevy_integration.py index b1709f1..3a11543 100644 --- a/tools/blenvy/tests/test_bevy_integration.py +++ b/tools/blenvy/tests/test_bevy_integration.py @@ -9,7 +9,7 @@ import filecmp from PIL import Image from pixelmatch.contrib.PIL import pixelmatch -from blenvy.auto_export.export.prepare_and_export import prepare_and_export +from blenvy.add_ons.auto_export.common.prepare_and_export import prepare_and_export @pytest.fixture def setup_data(request): @@ -73,14 +73,11 @@ def setup_data(request): """ def test_export_complex(setup_data): root_path = setup_data["root_path"] - auto_export_operator = bpy.ops.export_scenes.auto_gltf # with change detection # first, configure things # we use the global settings for that export_props = { - "main_scene_names" : ['World'], - "library_scene_names": ['Library'], } gltf_settings = { "export_animations": True, @@ -102,26 +99,29 @@ def test_export_complex(setup_data): # move the cube in the library # TODO: add back bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1] - registry = bpy.context.window_manager.components_registry blenvy = bpy.context.window_manager.blenvy - main_scene = blenvy.main_scenes.add() - main_scene.name = "World" + #blenvy.project_root_path = + #blenvy.blueprints_path blenvy.auto_export.auto_export = True + blenvy.auto_export.export_scene_settings = True + blenvy.auto_export.export_blueprints = True + blenvy.auto_export.export_materials_library = True + + bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene + bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene + + # scene asset + user_asset = bpy.data.scenes['World'].user_assets.add() + user_asset.name = "test_asset" + user_asset.path = "audio/fake.mp3" + + # blueprint asset + user_asset = bpy.data.collections['Blueprint4_nested'].user_assets.add() + user_asset.name = "yoho_audio" + user_asset.path = "audio/fake.mp3" prepare_and_export() - """auto_export_operator( - auto_export=True, - direct_mode=True, - project_root_path = os.path.abspath(root_path), - #blueprints_path = os.path.join("assets", "models", "library"), - export_output_folder = os.path.join("assets", "models"), #"./models", - #levels_path = os.path.join("assets", "models"), - - export_scene_settings=True, - export_blueprints=True, - export_materials_library=True - )""" # blueprint1 => has an instance, got changed, should export # blueprint2 => has NO instance, but marked as asset, should export # blueprint3 => has NO instance, not marked as asset, used inside blueprint 4: should export diff --git a/tools/blenvy/tests/test_bevy_integration_prepare.py b/tools/blenvy/tests/test_bevy_integration_prepare.py index 812e4c7..fc59799 100644 --- a/tools/blenvy/tests/test_bevy_integration_prepare.py +++ b/tools/blenvy/tests/test_bevy_integration_prepare.py @@ -2,6 +2,7 @@ import os import json import pytest import bpy +from blenvy.add_ons.auto_export.common.prepare_and_export import prepare_and_export @pytest.fixture def setup_data(request): @@ -25,14 +26,11 @@ def setup_data(request): # this runs the external blueprints file def test_export_external_blueprints(setup_data): root_path = setup_data["root_path"] - auto_export_operator = bpy.ops.export_scenes.auto_gltf # with change detection # first, configure things # we use the global settings for that export_props = { - "main_scene_names" : [], - "library_scene_names": ['Library'], } gltf_settings = { "export_animations": True, @@ -49,20 +47,20 @@ def test_export_external_blueprints(setup_data): stored_gltf_settings.clear() stored_gltf_settings.write(json.dumps(gltf_settings)) + blenvy = bpy.context.window_manager.blenvy + #blenvy.project_root_path = + #blenvy.blueprints_path + blenvy.auto_export.auto_export = True + blenvy.auto_export.export_scene_settings = True + blenvy.auto_export.export_blueprints = True + blenvy.auto_export.export_materials_library = True - auto_export_operator( - auto_export=True, - direct_mode=True, - project_root_path = os.path.abspath(root_path), - #blueprints_path = os.path.join("assets", "models", "library"), - #export_output_folder = os.path.join("assets", "models"), #"./models", - #levels_path = os.path.join("assets", "models"), - - export_scene_settings=False, - export_blueprints=True, - export_materials_library=True, - export_marked_assets= True - ) + print("SCENES", bpy.data.scenes) + for scene in bpy.data.scenes: + print("SCNE", scene) + bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene + # do the actual export + prepare_and_export() assert os.path.exists(os.path.join(setup_data["blueprints_path"], "External_blueprint.glb")) == True assert os.path.exists(os.path.join(setup_data["blueprints_path"], "External_blueprint2.glb")) == True