Compare commits
4 Commits
aba2a4f5e5
...
dca49bd696
Author | SHA1 | Date |
---|---|---|
Mark Moissette | dca49bd696 | |
Jan Hohenheim | b92081d06e | |
kaosat.dev | 5621b66cb3 | |
kaosat.dev | 4586273e37 |
2
TODO.md
2
TODO.md
|
@ -222,7 +222,9 @@ Blender side:
|
||||||
- [ ] materials fixes & upgrades
|
- [ ] materials fixes & upgrades
|
||||||
- [x] materials do not get exported again if the files are missing, until you change a material
|
- [x] materials do not get exported again if the files are missing, until you change a material
|
||||||
- [x] materials do not get exported when a material is added ?
|
- [x] materials do not get exported when a material is added ?
|
||||||
|
- [ ] if material library is toggled, then changes to materials should not change the blueprints that are using them ?
|
||||||
- [ ] 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
|
||||||
|
- [ ] review & upgrade overall logic of material libraries, their names & output path
|
||||||
- [ ] persist exported materials path in blueprints so that it can be read from library file users
|
- [ ] 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
|
- [ ] just like "export_path" write it into each blueprint's collection
|
||||||
- [ ] scan for used materials per blueprint !
|
- [ ] scan for used materials per blueprint !
|
||||||
|
|
|
@ -49,16 +49,14 @@ impl Default for BluePrintBundle {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
/// Plugin for gltf blueprints
|
/// Plugin for gltf blueprints
|
||||||
pub struct BlueprintsPlugin {
|
pub struct BlueprintsPlugin {}
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for BlueprintsPlugin {
|
impl Default for BlueprintsPlugin {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { }
|
Self {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn hot_reload(watching_for_changes: Res<WatchingForChanges>) -> bool {
|
fn hot_reload(watching_for_changes: Res<WatchingForChanges>) -> bool {
|
||||||
// println!("hot reload ? {}", watching_for_changes.0);
|
// println!("hot reload ? {}", watching_for_changes.0);
|
||||||
watching_for_changes.0
|
watching_for_changes.0
|
||||||
|
@ -110,6 +108,8 @@ impl Plugin for BlueprintsPlugin {
|
||||||
.register_type::<Vec<String>>()
|
.register_type::<Vec<String>>()
|
||||||
.register_type::<BlueprintAssets>()
|
.register_type::<BlueprintAssets>()
|
||||||
.register_type::<HashMap<String, Vec<String>>>()
|
.register_type::<HashMap<String, Vec<String>>>()
|
||||||
|
.init_asset::<RawGltfAsset>()
|
||||||
|
.init_asset_loader::<RawGltfAssetLoader>()
|
||||||
.configure_sets(
|
.configure_sets(
|
||||||
Update,
|
Update,
|
||||||
(GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn)
|
(GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn)
|
||||||
|
@ -119,6 +119,7 @@ impl Plugin for BlueprintsPlugin {
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
|
load_raw_gltf,
|
||||||
blueprints_prepare_spawn,
|
blueprints_prepare_spawn,
|
||||||
blueprints_check_assets_loading,
|
blueprints_check_assets_loading,
|
||||||
blueprints_assets_loaded,
|
blueprints_assets_loaded,
|
||||||
|
@ -132,16 +133,14 @@ impl Plugin for BlueprintsPlugin {
|
||||||
.chain()
|
.chain()
|
||||||
.in_set(GltfBlueprintsSet::Spawn),
|
.in_set(GltfBlueprintsSet::Spawn),
|
||||||
)
|
)
|
||||||
|
|
||||||
// animation
|
// animation
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
trigger_blueprint_animation_markers_events,
|
trigger_blueprint_animation_markers_events,
|
||||||
trigger_instance_animation_markers_events
|
trigger_instance_animation_markers_events,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
// hot reload
|
// hot reload
|
||||||
.add_systems(Update, react_to_asset_changes.run_if(hot_reload));
|
.add_systems(Update, react_to_asset_changes.run_if(hot_reload));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use bevy::{gltf::Gltf, prelude::*, scene::SceneInstance, utils::hashbrown::HashMap};
|
use bevy::{
|
||||||
|
asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext},
|
||||||
|
gltf::Gltf,
|
||||||
|
prelude::*,
|
||||||
|
scene::SceneInstance,
|
||||||
|
utils::hashbrown::HashMap,
|
||||||
|
};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -115,17 +121,59 @@ Overview of the Blueprint Spawning process
|
||||||
=> distinguish between blueprint instances inside blueprint instances vs blueprint instances inside blueprints ??
|
=> distinguish between blueprint instances inside blueprint instances vs blueprint instances inside blueprints ??
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub(crate) fn blueprints_prepare_spawn(
|
#[derive(Asset, TypePath, Debug)]
|
||||||
|
pub struct RawGltfAsset(pub RawGltf);
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(super) struct RawGltfAssetLoader;
|
||||||
|
|
||||||
|
impl AssetLoader for RawGltfAssetLoader {
|
||||||
|
type Asset = RawGltfAsset;
|
||||||
|
type Settings = ();
|
||||||
|
type Error = gltf::Error;
|
||||||
|
|
||||||
|
async fn load<'a>(
|
||||||
|
&'a self,
|
||||||
|
reader: &'a mut Reader<'_>,
|
||||||
|
_settings: &'a (),
|
||||||
|
_load_context: &'a mut LoadContext<'_>,
|
||||||
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
reader.read_to_end(&mut bytes).await?;
|
||||||
|
let gltf = RawGltf::from_slice_without_validation(&bytes)?;
|
||||||
|
Ok(RawGltfAsset(gltf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Component, Deref, DerefMut)]
|
||||||
|
#[component(storage = "SparseSet")]
|
||||||
|
pub(super) struct AssociatedRawGltfHandle(Handle<RawGltfAsset>);
|
||||||
|
|
||||||
|
pub(super) fn load_raw_gltf(
|
||||||
blueprint_instances_to_spawn: Query<(Entity, &BlueprintInfo), Added<SpawnBlueprint>>,
|
blueprint_instances_to_spawn: Query<(Entity, &BlueprintInfo), Added<SpawnBlueprint>>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for (entity, blueprint_info) in blueprint_instances_to_spawn.iter() {
|
||||||
|
let gltf_handle: Handle<RawGltfAsset> = asset_server.load(&blueprint_info.path);
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(AssociatedRawGltfHandle(gltf_handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn blueprints_prepare_spawn(
|
||||||
|
blueprint_instances_to_spawn: Query<(Entity, &BlueprintInfo, &AssociatedRawGltfHandle)>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
// for hot reload
|
// for hot reload
|
||||||
watching_for_changes: Res<WatchingForChanges>,
|
watching_for_changes: Res<WatchingForChanges>,
|
||||||
mut assets_to_blueprint_instances: ResMut<AssetToBlueprintInstancesMapper>,
|
mut assets_to_blueprint_instances: ResMut<AssetToBlueprintInstancesMapper>,
|
||||||
|
raw_gltf_assets: Res<Assets<RawGltfAsset>>,
|
||||||
// for debug
|
// for debug
|
||||||
// all_names: Query<&Name>
|
// all_names: Query<&Name>
|
||||||
) {
|
) {
|
||||||
for (entity, blueprint_info) in blueprint_instances_to_spawn.iter() {
|
for (entity, blueprint_info, raw_gltf_handle) in blueprint_instances_to_spawn.iter() {
|
||||||
info!(
|
info!(
|
||||||
"BLUEPRINT: to spawn detected: {:?} path:{:?}",
|
"BLUEPRINT: to spawn detected: {:?} path:{:?}",
|
||||||
blueprint_info.name, blueprint_info.path
|
blueprint_info.name, blueprint_info.path
|
||||||
|
@ -149,7 +197,9 @@ pub(crate) fn blueprints_prepare_spawn(
|
||||||
|
|
||||||
// and we also add all its assets
|
// and we also add all its assets
|
||||||
/* prefetch attempt */
|
/* prefetch attempt */
|
||||||
let gltf = RawGltf::open(format!("assets/{}", blueprint_info.path)).unwrap();
|
let Some(RawGltfAsset(gltf)) = raw_gltf_assets.get(&raw_gltf_handle.0) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
for scene in gltf.scenes() {
|
for scene in gltf.scenes() {
|
||||||
if let Some(scene_extras) = scene.extras().clone() {
|
if let Some(scene_extras) = scene.extras().clone() {
|
||||||
let lookup: HashMap<String, Value> =
|
let lookup: HashMap<String, Value> =
|
||||||
|
@ -254,7 +304,10 @@ pub(crate) fn blueprints_prepare_spawn(
|
||||||
.entity(entity)
|
.entity(entity)
|
||||||
.insert(bevy::prelude::Name::from(blueprint_info.name.clone()));
|
.insert(bevy::prelude::Name::from(blueprint_info.name.clone()));
|
||||||
// add the blueprint spawning marker
|
// add the blueprint spawning marker
|
||||||
commands.entity(entity).insert(BlueprintSpawning);
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BlueprintSpawning)
|
||||||
|
.remove::<AssociatedRawGltfHandle>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13340,11 +13340,11 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
"blenvy::blueprints::animation::SceneAnimations": {
|
"blenvy::blueprints::animation::InstanceAnimations": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"isComponent": true,
|
"isComponent": true,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
"long_name": "blenvy::blueprints::animation::SceneAnimations",
|
"long_name": "blenvy::blueprints::animation::InstanceAnimations",
|
||||||
"properties": {
|
"properties": {
|
||||||
"graph": {
|
"graph": {
|
||||||
"type": {
|
"type": {
|
||||||
|
@ -13367,7 +13367,7 @@
|
||||||
"named_indices",
|
"named_indices",
|
||||||
"graph"
|
"graph"
|
||||||
],
|
],
|
||||||
"short_name": "SceneAnimations",
|
"short_name": "InstanceAnimations",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,11 +12,9 @@ def get_materials_to_export(changes_per_material, changed_export_parameters, blu
|
||||||
|
|
||||||
all_materials = bpy.data.materials
|
all_materials = bpy.data.materials
|
||||||
local_materials = [material for material in all_materials if material.library is None]
|
local_materials = [material for material in all_materials if material.library is None]
|
||||||
#and (changed_export_parameters or len(changes_per_material.keys()) > 0 )
|
|
||||||
|
|
||||||
materials_to_export = []
|
materials_to_export = []
|
||||||
if change_detection and not changed_export_parameters:
|
if change_detection and not changed_export_parameters:
|
||||||
changed_materials = []
|
changed_materials = [bpy.data.materials[material_name] for material_name in list(changes_per_material.keys())]
|
||||||
|
|
||||||
# first check if all materials have already been exported before (if this is the first time the exporter is run
|
# first check if all materials have already been exported before (if this is the first time the exporter is run
|
||||||
# in your current Blender session for example)
|
# in your current Blender session for example)
|
||||||
|
@ -27,5 +25,4 @@ def get_materials_to_export(changes_per_material, changed_export_parameters, blu
|
||||||
materials_always_export = []
|
materials_always_export = []
|
||||||
materials_to_export = list(set(changed_materials + materials_not_on_disk + materials_always_export))
|
materials_to_export = list(set(changed_materials + materials_not_on_disk + materials_always_export))
|
||||||
|
|
||||||
|
|
||||||
return materials_to_export
|
return materials_to_export
|
||||||
|
|
|
@ -4,14 +4,24 @@ import bpy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from ..core.helpers_collections import (traverse_tree)
|
from ..core.helpers_collections import (traverse_tree)
|
||||||
|
|
||||||
def find_materials_not_on_disk(materials, folder_path, extension):
|
def find_materials_not_on_disk(materials, materials_path_full, extension):
|
||||||
not_found_materials = []
|
not_found_materials = []
|
||||||
|
|
||||||
|
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_full, f"{materials_library_name}{extension}")
|
||||||
|
|
||||||
|
found = os.path.exists(materials_exported_path) and os.path.isfile(materials_exported_path)
|
||||||
for material in materials:
|
for material in materials:
|
||||||
gltf_output_path = os.path.join(folder_path, material.name + extension)
|
if not found:
|
||||||
|
not_found_materials.append(material)
|
||||||
|
|
||||||
|
"""for material in materials:
|
||||||
|
gltf_output_path = os.path.join(materials_path_full, material.name + extension)
|
||||||
# print("gltf_output_path", gltf_output_path)
|
# print("gltf_output_path", gltf_output_path)
|
||||||
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)
|
||||||
if not found:
|
if not found:
|
||||||
not_found_materials.append(material)
|
not_found_materials.append(material)"""
|
||||||
return not_found_materials
|
return not_found_materials
|
||||||
|
|
||||||
def check_if_material_on_disk(scene_name, folder_path, extension):
|
def check_if_material_on_disk(scene_name, folder_path, extension):
|
||||||
|
|
Loading…
Reference in New Issue