diff --git a/TODO.md b/TODO.md index fe53d45..5be78d4 100644 --- a/TODO.md +++ b/TODO.md @@ -226,6 +226,8 @@ Blender side: - [ ] materials_path custom property should be ignored both in the list of fixable component AND on export - [ ] if we want to add material_infos & others as normal components they should not be editable, so we need another attribute, and adapt the UI for that + - [x] injection of materials_infos should be done outside of export_materials as it should run even if materials do not need exporting + - [x] if material library is toggled, then changes to materials should not change the blueprints that are using them => not really: as the name & co might change - [ ] material assets seem to be added to list regardless of whether material exports are enabled or not - [x] review & upgrade overall logic of material libraries, their names & output path diff --git a/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py b/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py index 53e3920..fb044ec 100644 --- a/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py +++ b/tools/blenvy/add_ons/auto_export/blueprints/export_blueprints.py @@ -2,6 +2,7 @@ import os import bpy from blenvy.assets.assets_scan import get_blueprint_asset_tree from blenvy.assets.generate_asset_file import write_ron_assets_file +from ....materials.materials_helpers import add_material_info_to_objects, get_blueprint_materials 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 @@ -26,7 +27,11 @@ def export_blueprints(blueprints, settings, blueprints_data): if export_materials_library: gltf_export_settings['export_materials'] = 'PLACEHOLDER' + # inject blueprint asset data upsert_blueprint_assets(blueprint, blueprints_data=blueprints_data, settings=settings) + # upsert material infos if needed + (_, materials_per_object) = get_blueprint_materials(blueprint) + add_material_info_to_objects(materials_per_object, settings) # do the actual export generate_temporary_scene_and_export( 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 2f9c98e..05e6bea 100644 --- a/tools/blenvy/add_ons/auto_export/common/auto_export.py +++ b/tools/blenvy/add_ons/auto_export/common/auto_export.py @@ -26,7 +26,7 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material, #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_blueprints_enabled = getattr(settings.auto_export, "export_blueprints") export_materials_library = getattr(settings.auto_export, "export_materials_library") # standard gltf export settings are stored differently @@ -62,7 +62,7 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material, light['BlenderLightShadows'] = f"(enabled: {enabled}, buffer_bias: {light.shadow_buffer_bias})" # export - if do_export_blueprints: + if export_blueprints_enabled: print("EXPORTING") # get blueprints/collections infos (blueprints_to_export) = get_blueprints_to_export(changes_per_scene, changes_per_collection, changed_export_parameters, blueprints_data, settings) @@ -100,22 +100,21 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material, old_current_scene = bpy.context.scene # backup current selections old_selections = bpy.context.selected_objects - + # deal with materials - if export_materials_library and len(materials_to_export) > 0: + if export_materials_library and (not change_detection or changed_export_parameters or len(materials_to_export) > 0) : print("export MATERIALS") export_materials(materials_to_export, settings, blueprints_data) # export any level/world scenes - if len(level_scenes_to_export) > 0: + if not change_detection or changed_export_parameters or len(level_scenes_to_export) > 0: print("export LEVELS") for scene_name in level_scenes_to_export: print(" exporting scene:", scene_name) export_level_scene(bpy.data.scenes[scene_name], settings, blueprints_data) # now deal with blueprints/collections - do_export_blueprints = not change_detection or changed_export_parameters or len(blueprints_to_export) > 0 - if do_export_blueprints: + if not change_detection or changed_export_parameters or len(blueprints_to_export) > 0: print("export BLUEPRINTS") export_blueprints(blueprints_to_export, settings, blueprints_data) diff --git a/tools/blenvy/add_ons/auto_export/materials/export_materials.py b/tools/blenvy/add_ons/auto_export/materials/export_materials.py index 61d45df..184a452 100644 --- a/tools/blenvy/add_ons/auto_export/materials/export_materials.py +++ b/tools/blenvy/add_ons/auto_export/materials/export_materials.py @@ -74,34 +74,30 @@ def clear_materials_scene(temp_scene): # exports the materials used inside the current project: # the name of the output path is /_materials_library.gltf/glb def export_materials(materials_to_export, settings, blueprints_data): - if len(materials_to_export) > 0: - gltf_export_settings = generate_gltf_export_settings(settings) - materials_path_full = getattr(settings,"materials_path_full") + gltf_export_settings = generate_gltf_export_settings(settings) + materials_path_full = getattr(settings,"materials_path_full") - (used_material_names, materials_per_object) = get_all_materials(blueprints_data.blueprint_names, settings.library_scenes) - add_material_info_to_objects(materials_per_object, settings) + gltf_export_settings = { **gltf_export_settings, + 'use_active_scene': True, + 'use_active_collection':True, + 'use_active_collection_with_nested':True, + 'use_visible': False, + 'use_renderable': False, + 'export_apply':True + } - gltf_export_settings = { **gltf_export_settings, - 'use_active_scene': True, - 'use_active_collection':True, - 'use_active_collection_with_nested':True, - 'use_visible': False, - 'use_renderable': False, - 'export_apply':True - } + for material in materials_to_export: + print("exporting material", material.name) + gltf_output_path = os.path.join(materials_path_full, material.name) - for material in materials_to_export: - print("exporting material", material.name) - gltf_output_path = os.path.join(materials_path_full, material.name) - - generate_temporary_scene_and_export( - settings=settings, - gltf_export_settings=gltf_export_settings, - temp_scene_name="__materials_scene", - gltf_output_path=gltf_output_path, - tempScene_filler= lambda temp_collection: generate_material_scene_content(temp_collection, material.name), - tempScene_cleaner= lambda temp_scene, params: clear_materials_scene(temp_scene=temp_scene) - ) + generate_temporary_scene_and_export( + settings=settings, + gltf_export_settings=gltf_export_settings, + temp_scene_name="__materials_scene", + gltf_output_path=gltf_output_path, + tempScene_filler= lambda temp_collection: generate_material_scene_content(temp_collection, material.name), + tempScene_cleaner= lambda temp_scene, params: clear_materials_scene(temp_scene=temp_scene) + ) def cleanup_materials(collections, library_scenes): diff --git a/tools/blenvy/materials/materials_helpers.py b/tools/blenvy/materials/materials_helpers.py index df618dd..90a3b4c 100644 --- a/tools/blenvy/materials/materials_helpers.py +++ b/tools/blenvy/materials/materials_helpers.py @@ -17,19 +17,50 @@ def check_if_material_on_disk(scene_name, folder_path, extension): found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path) return found + # get materials per object, and injects the materialInfo component def get_materials(object, materials_per_object): material_slots = object.material_slots used_materials_names = [] + + if not hasattr(object, "data"): + return used_materials_names + if not hasattr(object.data,"materials"): + return used_materials_names + if len(object.data.materials) == 0: + return used_materials_names + + # since we are scanning polygons to get the actually used materials, we do not get them in the correct order + materials_per_object_unordered = [] + + """materials_count = len(material_slots) + print("materials_count", materials_count) + material_indices = np.empty(materials_count, dtype=np.int64) + object.data.polygons.foreach_get("material_index", material_indices) + #for material_index in object.data.polygons.foreach_get("material_index", storage): + print("polygon material_indices", material_indices)""" + # TODO: perhaps optimise it using foreach_get + for polygon in object.data.polygons: + slot = material_slots[polygon.material_index] + material = slot.material + if not material.name in used_materials_names: + used_materials_names.append(material.name) + materials_per_object_unordered.append((material, polygon.material_index)) + + if len(used_materials_names) == len(material_slots): # we found all materials, bail out + break + + # now re-order the materials as per the object's material slots + sorted_materials = sorted(materials_per_object_unordered, key=lambda tup: tup[1]) + + # and add them + if not object in materials_per_object: + materials_per_object[object] = [] + materials_per_object[object] = [material[0] for material in sorted_materials]#.append(material) + + """for m in material_slots: + material = m.material""" - for m in material_slots: - material = m.material - # print(" slot", m, "material", material) - used_materials_names.append(material.name) - # TODO:, also respect slots & export multiple materials if applicable ! - if not object in materials_per_object: - materials_per_object[object] = [] - materials_per_object[object].append(material) return used_materials_names