mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-12-22 23:54:10 +00:00
feat(Blenvy): more work done on materials handling overhaul (wip)
* split out materials scan from injection of materialInfo into objects * added material Asset injection into list of assets at scene level * related tweaks & cleanups * continued overhaul on the bevy side
This commit is contained in:
parent
1fdb45bab6
commit
ed0c85b66e
@ -17,14 +17,14 @@ use bevy::{
|
||||
render::mesh::Mesh,
|
||||
};
|
||||
|
||||
use crate::{AssetLoadTracker, AssetsToLoad, BluePrintsConfig};
|
||||
use crate::{AssetLoadTracker, AssetsToLoad, BluePrintsConfig, BlueprintInstanceReady};
|
||||
|
||||
#[derive(Component, Reflect, Default, Debug)]
|
||||
#[reflect(Component)]
|
||||
/// struct containing the name & source of the material to apply
|
||||
/// struct containing the name & path of the material to apply
|
||||
pub struct MaterialInfo {
|
||||
pub name: String,
|
||||
pub source: String,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
/// flag component
|
||||
@ -37,21 +37,21 @@ pub(crate) struct BlueprintMaterialAssetsNotLoaded;
|
||||
/// system that injects / replaces materials from material library
|
||||
pub(crate) fn materials_inject(
|
||||
blueprints_config: ResMut<BluePrintsConfig>,
|
||||
material_infos: Query<(Entity, &MaterialInfo), Added<MaterialInfo>>,
|
||||
|
||||
ready_blueprints: Query<(Entity, &Children), (With<BlueprintInstanceReady>)>,
|
||||
material_infos: Query<(Entity, &MaterialInfo, &Parent), Added<MaterialInfo>>,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for (entity, material_info) in material_infos.iter() {
|
||||
let model_file_name = format!(
|
||||
"{}_materials_library.{}",
|
||||
&material_info.source, &blueprints_config.format
|
||||
);
|
||||
let materials_path = Path::new(&blueprints_config.material_library_folder)
|
||||
.join(Path::new(model_file_name.as_str()));
|
||||
let material_name = &material_info.name;
|
||||
let material_full_path = materials_path.to_str().unwrap().to_string() + "#" + material_name; // TODO: yikes, cleanup
|
||||
|
||||
if blueprints_config
|
||||
/*for(entity, children) in ready_blueprints.iter() {
|
||||
println!("Blueprint ready !");
|
||||
} */
|
||||
for (entity, material_info, parent) in material_infos.iter() {
|
||||
println!("Entity with material info {:?} {:?}", entity, material_info);
|
||||
let parent_blueprint = ready_blueprints.get(parent.get());
|
||||
println!("Parent blueprint {:?}", parent_blueprint)
|
||||
/*if blueprints_config
|
||||
.material_library_cache
|
||||
.contains_key(&material_full_path)
|
||||
{
|
||||
@ -68,7 +68,7 @@ pub(crate) fn materials_inject(
|
||||
let material_file_id = material_file_handle.id();
|
||||
|
||||
// FIXME: fix this stuff
|
||||
/*let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
|
||||
let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
|
||||
name: material_full_path,
|
||||
id: material_file_id,
|
||||
loaded: false,
|
||||
@ -83,17 +83,17 @@ pub(crate) fn materials_inject(
|
||||
..Default::default()
|
||||
})
|
||||
.insert(BlueprintMaterialAssetsNotLoaded);
|
||||
*/
|
||||
}
|
||||
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
// TODO, merge with check_for_loaded, make generic ?
|
||||
// FIXME: fix this:
|
||||
/*
|
||||
|
||||
pub(crate) fn check_for_material_loaded(
|
||||
mut blueprint_assets_to_load: Query<
|
||||
(Entity, &mut AssetsToLoad<Gltf>),
|
||||
(Entity, &mut AssetsToLoad),
|
||||
With<BlueprintMaterialAssetsNotLoaded>,
|
||||
>,
|
||||
asset_server: Res<AssetServer>,
|
||||
@ -125,7 +125,7 @@ pub(crate) fn check_for_material_loaded(
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/// system that injects / replaces materials from material library
|
||||
pub(crate) fn materials_inject2(
|
||||
mut blueprints_config: ResMut<BluePrintsConfig>,
|
||||
@ -152,7 +152,7 @@ pub(crate) fn materials_inject2(
|
||||
for (material_info, children) in material_infos.iter() {
|
||||
let model_file_name = format!(
|
||||
"{}_materials_library.{}",
|
||||
&material_info.source, &blueprints_config.format
|
||||
&material_info.path, &blueprints_config.format
|
||||
);
|
||||
let materials_path = Path::new(&blueprints_config.material_library_folder)
|
||||
.join(Path::new(model_file_name.as_str()));
|
||||
|
@ -27,6 +27,13 @@ pub struct SpawnHere;
|
||||
/// flag component for dynamically spawned scenes
|
||||
pub struct Spawned;
|
||||
|
||||
|
||||
#[derive(Component)]
|
||||
/// flag component added when a Blueprint instance ist Ready : ie :
|
||||
/// - its assets have loaded
|
||||
/// - it has finished spawning
|
||||
pub struct BlueprintInstanceReady;
|
||||
|
||||
#[derive(Component, Reflect, Default, Debug)]
|
||||
#[reflect(Component)]
|
||||
/// flag component marking any spwaned child of blueprints ..unless the original entity was marked with the `NoInBlueprint` marker component
|
||||
@ -298,6 +305,7 @@ pub(crate) fn spawn_from_blueprints2(
|
||||
..Default::default()
|
||||
},
|
||||
Spawned,
|
||||
BlueprintInstanceReady, // FIXME: not sure if this is should be added here or in the post process
|
||||
OriginalChildren(original_children),
|
||||
BlueprintAnimations {
|
||||
// these are animations specific to the inside of the blueprint
|
||||
|
@ -113,10 +113,14 @@ General issues:
|
||||
- [ ] add option to 'split out' meshes from blueprints ?
|
||||
- [ ] 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] remove 'export_marked_assets' it should be a default setting
|
||||
- [x] disable/ hide asset editing ui for external assets
|
||||
- [ ] inject_export_path_into_internal_blueprints should be called on every asset/blueprint scan !! Not just on export
|
||||
- [x] fix level asets UI
|
||||
- [ ] persist exported materials path in blueprints so that it can be read from library file users
|
||||
- [ ] just like "export_path" write it into each blueprint's collection
|
||||
- [ ] scan for used materials per blueprint !
|
||||
- [ ] for scenes, scan for used materials of all non instance objects (TODO: what about overrides ?)
|
||||
|
||||
- [x] remove BlueprintsList & replace is with assets list
|
||||
|
||||
|
@ -4,7 +4,7 @@ from pathlib import Path
|
||||
|
||||
from blenvy.core.helpers_collections import (traverse_tree)
|
||||
from blenvy.core.object_makers import make_cube
|
||||
from blenvy.materials.materials_helpers import get_all_materials
|
||||
from blenvy.materials.materials_helpers import add_material_info_to_objects, get_all_materials
|
||||
from .generate_temporary_scene_and_export import generate_temporary_scene_and_export
|
||||
from .export_gltf import (generate_gltf_export_settings)
|
||||
|
||||
@ -69,8 +69,8 @@ def export_materials(collections, library_scenes, settings):
|
||||
gltf_export_settings = generate_gltf_export_settings(settings)
|
||||
materials_path_full = getattr(settings,"materials_path_full")
|
||||
|
||||
used_material_names = get_all_materials(collections, library_scenes)
|
||||
current_project_name = Path(bpy.context.blend_data.filepath).stem
|
||||
(used_material_names, materials_per_object) = get_all_materials(collections, library_scenes)
|
||||
add_material_info_to_objects(materials_per_object, settings)
|
||||
|
||||
gltf_export_settings = { **gltf_export_settings,
|
||||
'use_active_scene': True,
|
||||
@ -80,8 +80,9 @@ def export_materials(collections, library_scenes, settings):
|
||||
'use_renderable': False,
|
||||
'export_apply':True
|
||||
}
|
||||
|
||||
gltf_output_path = os.path.join(materials_path_full, current_project_name + "_materials_library")
|
||||
|
||||
current_project_name = Path(bpy.context.blend_data.filepath).stem
|
||||
gltf_output_path = os.path.join(materials_path_full, current_project_name + "_materials")
|
||||
|
||||
print(" exporting Materials to", gltf_output_path, ".gltf/glb")
|
||||
|
||||
|
@ -21,7 +21,6 @@ parameter_names_whitelist_auto_export = [
|
||||
'export_separate_dynamic_and_static_objects',
|
||||
'export_materials_library',
|
||||
'collection_instances_combine_mode',
|
||||
'export_marked_assets'
|
||||
]
|
||||
|
||||
def get_setting_changes():
|
||||
|
@ -1,6 +1,9 @@
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import bpy
|
||||
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
|
||||
@ -49,9 +52,9 @@ def export_main_scene(scene, settings, blueprints_data):
|
||||
auto_assets = []
|
||||
|
||||
all_assets = []
|
||||
export_gltf_extension = getattr(settings.auto_export, "export_gltf_extension", ".glb")
|
||||
|
||||
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}")
|
||||
@ -69,8 +72,15 @@ def export_main_scene(scene, settings, blueprints_data):
|
||||
"""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)
|
||||
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}")
|
||||
material_assets = [{"name": materials_library_name, "path": materials_exported_path}] # we also add the material library as an asset
|
||||
|
||||
|
||||
scene["local_assets"] = assets_to_fake_ron([{"name": asset.name, "path": asset.path} for asset in scene.user_assets] + auto_assets + material_assets)
|
||||
scene["AllAssets"] = assets_to_fake_ron(all_assets + [{"name": asset.name, "path": asset.path} for asset in scene.user_assets] + auto_assets + material_assets)
|
||||
|
||||
|
||||
if export_separate_dynamic_and_static_objects:
|
||||
|
@ -101,13 +101,6 @@ class AutoExportSettings(PropertyGroup):
|
||||
update=save_settings
|
||||
) # type: ignore
|
||||
|
||||
export_marked_assets: BoolProperty(
|
||||
name='Auto export marked assets',
|
||||
description='Collections that have been marked as assets will be systematically exported, even if not in use in another scene',
|
||||
default=True,
|
||||
update=save_settings
|
||||
) # type: ignore
|
||||
|
||||
dry_run: EnumProperty(
|
||||
name="dry run",
|
||||
description="debug/ develop helper to enable everything but the actual exporting of files",
|
||||
|
@ -51,7 +51,6 @@ def draw_settings_ui(layout, auto_export_settings):
|
||||
|
||||
# collections/blueprints
|
||||
section.prop(auto_export_settings, "collection_instances_combine_mode")
|
||||
section.prop(auto_export_settings, "export_marked_assets")
|
||||
section.separator()
|
||||
|
||||
section.prop(auto_export_settings, "export_separate_dynamic_and_static_objects")
|
||||
|
@ -8,8 +8,6 @@ from .blueprint import Blueprint
|
||||
# - with the "auto_export" flag
|
||||
# https://blender.stackexchange.com/questions/167878/how-to-get-all-collections-of-the-current-scene
|
||||
def blueprints_scan(main_scenes, library_scenes, settings):
|
||||
export_marked_assets = getattr(settings.auto_export, "export_marked_assets")
|
||||
|
||||
blueprints = {}
|
||||
blueprints_from_objects = {}
|
||||
blueprint_name_from_instances = {}
|
||||
@ -84,12 +82,12 @@ def blueprints_scan(main_scenes, library_scenes, settings):
|
||||
|
||||
if (
|
||||
'AutoExport' in collection and collection['AutoExport'] == True # get marked collections
|
||||
or export_marked_assets and collection.asset_data is not None # or if you have marked collections as assets you can auto export them too
|
||||
or collection.asset_data is not None # or if you have marked collections as assets you can auto export them too
|
||||
or collection.name in list(internal_collection_instances.keys()) # or if the collection has an instance in one of the main scenes
|
||||
):
|
||||
blueprint = Blueprint(collection.name)
|
||||
blueprint.local = True
|
||||
blueprint.marked = 'AutoExport' in collection and collection['AutoExport'] == True or export_marked_assets and collection.asset_data is not None
|
||||
blueprint.marked = 'AutoExport' in collection and collection['AutoExport'] == True or collection.asset_data is not None
|
||||
blueprint.objects = [object.name for object in collection.all_objects if not object.instance_type == 'COLLECTION'] # inneficient, double loop
|
||||
blueprint.nested_blueprints = [object.instance_collection.name for object in collection.all_objects if object.instance_type == 'COLLECTION'] # FIXME: not precise enough, aka "what is a blueprint"
|
||||
blueprint.collection = collection
|
||||
|
@ -4,32 +4,43 @@ from pathlib import Path
|
||||
from ..core.helpers_collections import (traverse_tree)
|
||||
|
||||
# get materials per object, and injects the materialInfo component
|
||||
def get_materials(object):
|
||||
def get_materials(object, materials_per_object):
|
||||
material_slots = object.material_slots
|
||||
used_materials_names = []
|
||||
#materials_per_object = {}
|
||||
current_project_name = Path(bpy.context.blend_data.filepath).stem
|
||||
|
||||
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 !
|
||||
# TODO: do NOT modify objects like this !! do it in a different function
|
||||
object['MaterialInfo'] = '(name: "'+material.name+'", source: "'+current_project_name + '")'
|
||||
|
||||
materials_per_object[object] = material
|
||||
return used_materials_names
|
||||
|
||||
|
||||
def get_all_materials(collection_names, library_scenes):
|
||||
used_material_names = []
|
||||
materials_per_object = {}
|
||||
|
||||
for scene in library_scenes:
|
||||
root_collection = scene.collection
|
||||
for cur_collection in traverse_tree(root_collection):
|
||||
if cur_collection.name in collection_names:
|
||||
for object in cur_collection.all_objects:
|
||||
used_material_names = used_material_names + get_materials(object)
|
||||
used_material_names = used_material_names + get_materials(object, materials_per_object)
|
||||
|
||||
# we only want unique names
|
||||
used_material_names = list(set(used_material_names))
|
||||
return used_material_names
|
||||
return (used_material_names, materials_per_object)
|
||||
|
||||
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")
|
||||
|
||||
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 object in materials_per_object.keys():
|
||||
material = materials_per_object[object]
|
||||
# TODO: switch to using actual components ?
|
||||
materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}")
|
||||
object['MaterialInfo'] = f'(name: "{material.name}", path: "{materials_exported_path}")'
|
@ -105,7 +105,7 @@ def test_export_complex(setup_data):
|
||||
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 = False # TODO: switch back
|
||||
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
|
||||
|
@ -53,7 +53,7 @@ def test_export_external_blueprints(setup_data):
|
||||
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 = False # TODO switch back
|
||||
blenvy.auto_export.export_materials_library = True
|
||||
|
||||
print("SCENES", bpy.data.scenes)
|
||||
for scene in bpy.data.scenes:
|
||||
|
@ -223,7 +223,6 @@ def test_export_do_not_export_marked_assets(setup_data):
|
||||
export_output_folder="./models",
|
||||
export_scene_settings=True,
|
||||
export_blueprints=True,
|
||||
export_marked_assets = False
|
||||
)
|
||||
assert os.path.exists(os.path.join(setup_data["levels_path"], "World.glb")) == True
|
||||
assert os.path.exists(os.path.join(setup_data["blueprints_path"], "Blueprint1.glb")) == True
|
||||
|
Loading…
Reference in New Issue
Block a user