feat(Blenvy:Blender): numerous minor tweaks & fixes (mostly materials related)

* now correctly handling multi material meshes that have more materials in their slots as there are actual
materials applied
 * per-blueprint materials are now correctly inserted/updated even when there are no material changes (ie cases where
the ordering of slots etc is changed on a mesh)
 * conditions for trigerring exports of levels & materials are more coherent and exports are now trigerred on export setting
changes (as they should have been !)
 * minor cleanups
This commit is contained in:
kaosat.dev 2024-07-27 21:59:57 +02:00
parent ab7a0cab65
commit 94fe3f6d3c
5 changed files with 73 additions and 40 deletions

View File

@ -226,6 +226,8 @@ Blender side:
- [ ] materials_path custom property should be ignored both in the list of fixable component AND on export - [ ] 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 - [ ] 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 - [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 - [ ] 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 - [x] review & upgrade overall logic of material libraries, their names & output path

View File

@ -2,6 +2,7 @@ import os
import bpy import bpy
from blenvy.assets.assets_scan import get_blueprint_asset_tree from blenvy.assets.assets_scan import get_blueprint_asset_tree
from blenvy.assets.generate_asset_file import write_ron_assets_file 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 ..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.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 from ..common.export_gltf import generate_gltf_export_settings
@ -26,7 +27,11 @@ def export_blueprints(blueprints, settings, blueprints_data):
if export_materials_library: if export_materials_library:
gltf_export_settings['export_materials'] = 'PLACEHOLDER' gltf_export_settings['export_materials'] = 'PLACEHOLDER'
# inject blueprint asset data
upsert_blueprint_assets(blueprint, blueprints_data=blueprints_data, settings=settings) 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 # do the actual export
generate_temporary_scene_and_export( generate_temporary_scene_and_export(

View File

@ -26,7 +26,7 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
#should we use change detection or not #should we use change detection or not
change_detection = getattr(settings.auto_export, "change_detection") change_detection = getattr(settings.auto_export, "change_detection")
export_scene_settings = getattr(settings.auto_export, "export_scene_settings") 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") export_materials_library = getattr(settings.auto_export, "export_materials_library")
# standard gltf export settings are stored differently # 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})" light['BlenderLightShadows'] = f"(enabled: {enabled}, buffer_bias: {light.shadow_buffer_bias})"
# export # export
if do_export_blueprints: if export_blueprints_enabled:
print("EXPORTING") print("EXPORTING")
# get blueprints/collections infos # get blueprints/collections infos
(blueprints_to_export) = get_blueprints_to_export(changes_per_scene, changes_per_collection, changed_export_parameters, blueprints_data, settings) (blueprints_to_export) = get_blueprints_to_export(changes_per_scene, changes_per_collection, changed_export_parameters, blueprints_data, settings)
@ -102,20 +102,19 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
old_selections = bpy.context.selected_objects old_selections = bpy.context.selected_objects
# deal with materials # 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") print("export MATERIALS")
export_materials(materials_to_export, settings, blueprints_data) export_materials(materials_to_export, settings, blueprints_data)
# export any level/world scenes # 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") print("export LEVELS")
for scene_name in level_scenes_to_export: for scene_name in level_scenes_to_export:
print(" exporting scene:", scene_name) print(" exporting scene:", scene_name)
export_level_scene(bpy.data.scenes[scene_name], settings, blueprints_data) export_level_scene(bpy.data.scenes[scene_name], settings, blueprints_data)
# now deal with blueprints/collections # now deal with blueprints/collections
do_export_blueprints = not change_detection or changed_export_parameters or len(blueprints_to_export) > 0 if not change_detection or changed_export_parameters or len(blueprints_to_export) > 0:
if do_export_blueprints:
print("export BLUEPRINTS") print("export BLUEPRINTS")
export_blueprints(blueprints_to_export, settings, blueprints_data) export_blueprints(blueprints_to_export, settings, blueprints_data)

View File

@ -74,13 +74,9 @@ def clear_materials_scene(temp_scene):
# exports the materials used inside the current project: # exports the materials used inside the current project:
# the name of the output path is <materials_folder>/<name_of_your_blend_file>_materials_library.gltf/glb # the name of the output path is <materials_folder>/<name_of_your_blend_file>_materials_library.gltf/glb
def export_materials(materials_to_export, settings, blueprints_data): def export_materials(materials_to_export, settings, blueprints_data):
if len(materials_to_export) > 0:
gltf_export_settings = generate_gltf_export_settings(settings) gltf_export_settings = generate_gltf_export_settings(settings)
materials_path_full = getattr(settings,"materials_path_full") 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, gltf_export_settings = { **gltf_export_settings,
'use_active_scene': True, 'use_active_scene': True,
'use_active_collection':True, 'use_active_collection':True,

View File

@ -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) found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path)
return found return found
# get materials per object, and injects the materialInfo component # get materials per object, and injects the materialInfo component
def get_materials(object, materials_per_object): def get_materials(object, materials_per_object):
material_slots = object.material_slots material_slots = object.material_slots
used_materials_names = [] used_materials_names = []
for m in material_slots: if not hasattr(object, "data"):
material = m.material return used_materials_names
# print(" slot", m, "material", material) 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) used_materials_names.append(material.name)
# TODO:, also respect slots & export multiple materials if applicable ! 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: if not object in materials_per_object:
materials_per_object[object] = [] materials_per_object[object] = []
materials_per_object[object].append(material) materials_per_object[object] = [material[0] for material in sorted_materials]#.append(material)
"""for m in material_slots:
material = m.material"""
return used_materials_names return used_materials_names