mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-26 21:37:01 +00:00
Compare commits
2 Commits
64fd308fd3
...
8683a6482f
Author | SHA1 | Date | |
---|---|---|---|
|
8683a6482f | ||
|
cf4673c1e3 |
@ -17,8 +17,8 @@ pub struct BlueprintAnimationPlayerLink(pub Entity);
|
|||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
|
/// storage for scene level animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
|
||||||
pub struct InstanceAnimations {
|
pub struct SceneAnimations {
|
||||||
pub named_animations: HashMap<String, Handle<AnimationClip>>,
|
pub named_animations: HashMap<String, Handle<AnimationClip>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ pub struct InstanceAnimations {
|
|||||||
/// so that the root entity knows which of its children contains an actualy `AnimationPlayer` component
|
/// so that the root entity knows which of its children contains an actualy `AnimationPlayer` component
|
||||||
/// this is for convenience, because currently , Bevy's gltf parsing inserts `AnimationPlayers` "one level down"
|
/// this is for convenience, because currently , Bevy's gltf parsing inserts `AnimationPlayers` "one level down"
|
||||||
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
|
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
|
||||||
pub struct InstanceAnimationPlayerLink(pub Entity);
|
pub struct SceneAnimationPlayerLink(pub Entity);
|
||||||
|
|
||||||
/// Stores Animation information: name, frame informations etc
|
/// Stores Animation information: name, frame informations etc
|
||||||
#[derive(Reflect, Default, Debug)]
|
#[derive(Reflect, Default, Debug)]
|
||||||
@ -78,8 +78,8 @@ pub fn trigger_instance_animation_markers_events(
|
|||||||
animation_infos: Query<(
|
animation_infos: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&AnimationMarkers,
|
&AnimationMarkers,
|
||||||
&InstanceAnimationPlayerLink,
|
&SceneAnimationPlayerLink,
|
||||||
&InstanceAnimations,
|
&SceneAnimations,
|
||||||
&AnimationInfos,
|
&AnimationInfos,
|
||||||
)>,
|
)>,
|
||||||
animation_players: Query<&AnimationPlayer>,
|
animation_players: Query<&AnimationPlayer>,
|
||||||
|
@ -120,7 +120,7 @@ impl Plugin for BlueprintsPlugin {
|
|||||||
.register_type::<MaterialInfo>()
|
.register_type::<MaterialInfo>()
|
||||||
.register_type::<SpawnHere>()
|
.register_type::<SpawnHere>()
|
||||||
.register_type::<BlueprintAnimations>()
|
.register_type::<BlueprintAnimations>()
|
||||||
.register_type::<InstanceAnimations>()
|
.register_type::<SceneAnimations>()
|
||||||
.register_type::<AnimationInfo>()
|
.register_type::<AnimationInfo>()
|
||||||
.register_type::<AnimationInfos>()
|
.register_type::<AnimationInfos>()
|
||||||
.register_type::<Vec<AnimationInfo>>()
|
.register_type::<Vec<AnimationInfo>>()
|
||||||
|
@ -3676,7 +3676,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
"bevy_gltf_blueprints::animation::InstanceAnimations": {
|
"bevy_gltf_blueprints::animation::SceneAnimations": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"isComponent": true,
|
"isComponent": true,
|
||||||
"isResource": false,
|
"isResource": false,
|
||||||
@ -3690,8 +3690,8 @@
|
|||||||
"required": [
|
"required": [
|
||||||
"named_animations"
|
"named_animations"
|
||||||
],
|
],
|
||||||
"short_name": "InstanceAnimations",
|
"short_name": "SceneAnimations",
|
||||||
"title": "bevy_gltf_blueprints::animation::InstanceAnimations",
|
"title": "bevy_gltf_blueprints::animation::SceneAnimations",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct"
|
"typeInfo": "Struct"
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use bevy_gltf_blueprints::{
|
use bevy_gltf_blueprints::{
|
||||||
AnimationInfos, AnimationMarkerReached, BlueprintAnimationPlayerLink, BlueprintAnimations,
|
AnimationInfos, AnimationMarkerReached, BlueprintAnimationPlayerLink, BlueprintAnimations,
|
||||||
InstanceAnimationPlayerLink, InstanceAnimations,
|
SceneAnimationPlayerLink, SceneAnimations,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy::{gltf::Gltf, prelude::*};
|
use bevy::{gltf::Gltf, prelude::*};
|
||||||
@ -58,7 +58,7 @@ pub fn animations(
|
|||||||
name, entity
|
name, entity
|
||||||
);
|
);
|
||||||
println!("Found match {:?}", gltf.named_animations);
|
println!("Found match {:?}", gltf.named_animations);
|
||||||
commands.entity(entity).insert(InstanceAnimations {
|
commands.entity(entity).insert(SceneAnimations {
|
||||||
named_animations: gltf.named_animations.clone(),
|
named_animations: gltf.named_animations.clone(),
|
||||||
});
|
});
|
||||||
for ancestor in parents.iter_ancestors(entity) {
|
for ancestor in parents.iter_ancestors(entity) {
|
||||||
@ -66,7 +66,7 @@ pub fn animations(
|
|||||||
// println!("found match with animationPlayer !! {:?}",names.get(ancestor));
|
// println!("found match with animationPlayer !! {:?}",names.get(ancestor));
|
||||||
commands
|
commands
|
||||||
.entity(entity)
|
.entity(entity)
|
||||||
.insert(InstanceAnimationPlayerLink(ancestor));
|
.insert(SceneAnimationPlayerLink(ancestor));
|
||||||
}
|
}
|
||||||
// info!("{:?} is an ancestor of {:?}", ancestor, player);
|
// info!("{:?} is an ancestor of {:?}", ancestor, player);
|
||||||
}
|
}
|
||||||
@ -77,17 +77,17 @@ pub fn animations(
|
|||||||
|
|
||||||
pub fn play_animations(
|
pub fn play_animations(
|
||||||
animated_marker1: Query<
|
animated_marker1: Query<
|
||||||
(&InstanceAnimationPlayerLink, &InstanceAnimations),
|
(&SceneAnimationPlayerLink, &SceneAnimations),
|
||||||
(With<AnimationInfos>, With<Marker1>),
|
(With<AnimationInfos>, With<Marker1>),
|
||||||
>,
|
>,
|
||||||
animated_marker2: Query<
|
animated_marker2: Query<
|
||||||
(&InstanceAnimationPlayerLink, &InstanceAnimations),
|
(&SceneAnimationPlayerLink, &SceneAnimations),
|
||||||
(With<AnimationInfos>, With<Marker2>),
|
(With<AnimationInfos>, With<Marker2>),
|
||||||
>,
|
>,
|
||||||
animated_marker3: Query<
|
animated_marker3: Query<
|
||||||
(
|
(
|
||||||
&InstanceAnimationPlayerLink,
|
&SceneAnimationPlayerLink,
|
||||||
&InstanceAnimations,
|
&SceneAnimations,
|
||||||
&BlueprintAnimationPlayerLink,
|
&BlueprintAnimationPlayerLink,
|
||||||
&BlueprintAnimations,
|
&BlueprintAnimations,
|
||||||
),
|
),
|
||||||
|
@ -5,6 +5,7 @@ import traceback
|
|||||||
|
|
||||||
from .export_main_scenes import export_main_scene
|
from .export_main_scenes import export_main_scene
|
||||||
from .export_blueprints import check_if_blueprint_on_disk, check_if_blueprints_exist, export_blueprints_from_collections
|
from .export_blueprints import check_if_blueprint_on_disk, check_if_blueprints_exist, export_blueprints_from_collections
|
||||||
|
from .get_standard_exporter_settings import get_standard_exporter_settings
|
||||||
|
|
||||||
from ..helpers.helpers_scenes import (get_scenes, )
|
from ..helpers.helpers_scenes import (get_scenes, )
|
||||||
from ..helpers.helpers_collections import (get_collections_in_library, get_exportable_collections, get_collections_per_scene, find_collection_ascendant_target_collection)
|
from ..helpers.helpers_collections import (get_collections_in_library, get_exportable_collections, get_collections_per_scene, find_collection_ascendant_target_collection)
|
||||||
@ -34,9 +35,8 @@ def auto_export(changes_per_scene, changed_export_parameters, addon_prefs):
|
|||||||
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
|
[main_scene_names, level_scenes, library_scene_names, library_scenes] = get_scenes(addon_prefs)
|
||||||
|
|
||||||
# standard gltf export settings are stored differently
|
# standard gltf export settings are stored differently
|
||||||
standard_gltf_exporter_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings")
|
|
||||||
print("standard_gltf_exporter_settings", standard_gltf_exporter_settings.as_string())
|
standard_gltf_exporter_settings = get_standard_exporter_settings()
|
||||||
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
|
|
||||||
|
|
||||||
print("main scenes", main_scene_names, "library_scenes", library_scene_names)
|
print("main scenes", main_scene_names, "library_scenes", library_scene_names)
|
||||||
print("export_output_folder", export_output_folder)
|
print("export_output_folder", export_output_folder)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
from ..constants import TEMPSCENE_PREFIX
|
||||||
from ..helpers.generate_and_export import generate_and_export
|
from ..helpers.generate_and_export import generate_and_export
|
||||||
from .export_gltf import (generate_gltf_export_preferences)
|
from .export_gltf import (generate_gltf_export_preferences)
|
||||||
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
|
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
|
||||||
@ -24,7 +25,7 @@ def export_collections(collections, folder_path, library_scene, addon_prefs, glt
|
|||||||
collection = bpy.data.collections[collection_name]
|
collection = bpy.data.collections[collection_name]
|
||||||
generate_and_export(
|
generate_and_export(
|
||||||
addon_prefs,
|
addon_prefs,
|
||||||
temp_scene_name="__temp_scene_"+collection.name,
|
temp_scene_name=TEMPSCENE_PREFIX+collection.name,
|
||||||
export_settings=export_settings,
|
export_settings=export_settings,
|
||||||
gltf_output_path=gltf_output_path,
|
gltf_output_path=gltf_output_path,
|
||||||
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),
|
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),
|
||||||
|
@ -2,6 +2,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
from .get_standard_exporter_settings import get_standard_exporter_settings
|
||||||
from .preferences import (AutoExportGltfPreferenceNames)
|
from .preferences import (AutoExportGltfPreferenceNames)
|
||||||
|
|
||||||
def generate_gltf_export_preferences(addon_prefs):
|
def generate_gltf_export_preferences(addon_prefs):
|
||||||
@ -48,9 +49,7 @@ def generate_gltf_export_preferences(addon_prefs):
|
|||||||
gltf_export_preferences[key] = getattr(addon_prefs, key)
|
gltf_export_preferences[key] = getattr(addon_prefs, key)
|
||||||
|
|
||||||
|
|
||||||
standard_gltf_exporter_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else bpy.data.texts.new(".gltf_auto_export_gltf_settings")
|
standard_gltf_exporter_settings = get_standard_exporter_settings()
|
||||||
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
|
|
||||||
"""standard_gltf_exporter_settings = get_standard_exporter_settings()"""
|
|
||||||
#print("standard settings", standard_gltf_exporter_settings)
|
#print("standard settings", standard_gltf_exporter_settings)
|
||||||
|
|
||||||
constant_keys = [
|
constant_keys = [
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
from ..constants import TEMPSCENE_PREFIX
|
||||||
from ..helpers.generate_and_export import generate_and_export
|
from ..helpers.generate_and_export import generate_and_export
|
||||||
from .export_gltf import (generate_gltf_export_preferences, export_gltf)
|
from .export_gltf import (generate_gltf_export_preferences, export_gltf)
|
||||||
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
|
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
|
||||||
@ -38,7 +39,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
|
|||||||
# first export static objects
|
# first export static objects
|
||||||
generate_and_export(
|
generate_and_export(
|
||||||
addon_prefs,
|
addon_prefs,
|
||||||
temp_scene_name="__temp_scene",
|
temp_scene_name=TEMPSCENE_PREFIX,
|
||||||
export_settings=export_settings,
|
export_settings=export_settings,
|
||||||
gltf_output_path=gltf_output_path,
|
gltf_output_path=gltf_output_path,
|
||||||
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_static, addon_prefs=addon_prefs),
|
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_static, addon_prefs=addon_prefs),
|
||||||
@ -49,7 +50,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
|
|||||||
gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name+ "_dynamic")
|
gltf_output_path = os.path.join(folder_path, export_output_folder, scene.name+ "_dynamic")
|
||||||
generate_and_export(
|
generate_and_export(
|
||||||
addon_prefs,
|
addon_prefs,
|
||||||
temp_scene_name="__temp_scene",
|
temp_scene_name=TEMPSCENE_PREFIX,
|
||||||
export_settings=export_settings,
|
export_settings=export_settings,
|
||||||
gltf_output_path=gltf_output_path,
|
gltf_output_path=gltf_output_path,
|
||||||
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_dynamic, addon_prefs=addon_prefs),
|
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, filter=is_object_dynamic, addon_prefs=addon_prefs),
|
||||||
@ -60,7 +61,7 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
|
|||||||
#print("NO SPLIT")
|
#print("NO SPLIT")
|
||||||
generate_and_export(
|
generate_and_export(
|
||||||
addon_prefs,
|
addon_prefs,
|
||||||
temp_scene_name="__temp_scene",
|
temp_scene_name=TEMPSCENE_PREFIX,
|
||||||
export_settings=export_settings,
|
export_settings=export_settings,
|
||||||
gltf_output_path=gltf_output_path,
|
gltf_output_path=gltf_output_path,
|
||||||
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),
|
tempScene_filler= lambda temp_collection: copy_hollowed_collection_into(scene.collection, temp_collection, library_collections=library_collections, addon_prefs=addon_prefs),
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import bpy
|
||||||
|
import json
|
||||||
|
|
||||||
|
def get_standard_exporter_settings():
|
||||||
|
standard_gltf_exporter_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"] if ".gltf_auto_export_gltf_settings" in bpy.data.texts else None
|
||||||
|
if standard_gltf_exporter_settings != None:
|
||||||
|
try:
|
||||||
|
standard_gltf_exporter_settings = json.loads(standard_gltf_exporter_settings.as_string())
|
||||||
|
except:
|
||||||
|
standard_gltf_exporter_settings = {}
|
||||||
|
else:
|
||||||
|
standard_gltf_exporter_settings = {}
|
||||||
|
|
||||||
|
return standard_gltf_exporter_settings
|
@ -46,7 +46,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
|
|||||||
|
|
||||||
bpy.types.WindowManager.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0)
|
bpy.types.WindowManager.main_scenes_list_index = IntProperty(name = "Index for main scenes list", default = 0)
|
||||||
bpy.types.WindowManager.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0)
|
bpy.types.WindowManager.library_scenes_list_index = IntProperty(name = "Index for library scenes list", default = 0)
|
||||||
bpy.types.WindowManager.previous_export_settings = StringProperty(default="")
|
|
||||||
|
|
||||||
cls.main_scenes_index = 0
|
cls.main_scenes_index = 0
|
||||||
cls.library_scenes_index = 0
|
cls.library_scenes_index = 0
|
||||||
@ -59,8 +58,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
|
|||||||
del bpy.types.WindowManager.main_scenes_list_index
|
del bpy.types.WindowManager.main_scenes_list_index
|
||||||
del bpy.types.WindowManager.library_scenes_list_index
|
del bpy.types.WindowManager.library_scenes_list_index
|
||||||
|
|
||||||
del bpy.types.WindowManager.previous_export_settings
|
|
||||||
|
|
||||||
def is_scene_ok(self, scene):
|
def is_scene_ok(self, scene):
|
||||||
try:
|
try:
|
||||||
operator = bpy.context.space_data.active_operator
|
operator = bpy.context.space_data.active_operator
|
||||||
@ -161,9 +158,20 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
|
|||||||
|
|
||||||
# if there were no setting before, it is new, we need export
|
# if there were no setting before, it is new, we need export
|
||||||
changed = False
|
changed = False
|
||||||
if previous_auto_settings == None or previous_gltf_settings == None:
|
print("previous_auto_settings", previous_auto_settings, "previous_gltf_settings", previous_gltf_settings)
|
||||||
|
if previous_auto_settings == None:
|
||||||
print("previous settings missing, exporting")
|
print("previous settings missing, exporting")
|
||||||
changed = True
|
changed = True
|
||||||
|
elif previous_gltf_settings == None:
|
||||||
|
print("previous gltf settings missing, exporting")
|
||||||
|
previous_gltf_settings = bpy.data.texts.new(".gltf_auto_export_gltf_settings_previous")
|
||||||
|
previous_gltf_settings.write(json.dumps({}))
|
||||||
|
if current_gltf_settings == None:
|
||||||
|
current_gltf_settings = bpy.data.texts[".gltf_auto_export_gltf_settings"]
|
||||||
|
current_gltf_settings.write(json.dumps({}))
|
||||||
|
|
||||||
|
changed = True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
auto_settings_changed = sorted(json.loads(previous_auto_settings.as_string()).items()) != sorted(json.loads(current_auto_settings.as_string()).items()) if current_auto_settings != None else False
|
auto_settings_changed = sorted(json.loads(previous_auto_settings.as_string()).items()) != sorted(json.loads(current_auto_settings.as_string()).items()) if current_auto_settings != None else False
|
||||||
gltf_settings_changed = sorted(json.loads(previous_gltf_settings.as_string()).items()) != sorted(json.loads(current_gltf_settings.as_string()).items()) if current_gltf_settings != None else False
|
gltf_settings_changed = sorted(json.loads(previous_gltf_settings.as_string()).items()) != sorted(json.loads(current_gltf_settings.as_string()).items()) if current_gltf_settings != None else False
|
||||||
@ -192,7 +200,6 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
print("execute")
|
print("execute")
|
||||||
# disable change detection while the operator runs
|
|
||||||
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
|
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
|
||||||
if self.direct_mode:
|
if self.direct_mode:
|
||||||
self.load_settings(context)
|
self.load_settings(context)
|
||||||
@ -203,11 +210,13 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
|
|||||||
if self.auto_export: # only do the actual exporting if auto export is actually enabled
|
if self.auto_export: # only do the actual exporting if auto export is actually enabled
|
||||||
#& do the export
|
#& do the export
|
||||||
if self.direct_mode: #Do not auto export when applying settings in the menu, do it on save only
|
if self.direct_mode: #Do not auto export when applying settings in the menu, do it on save only
|
||||||
|
# disable change detection while the operator runs
|
||||||
|
|
||||||
#determine changed parameters
|
#determine changed parameters
|
||||||
params_changed = self.did_export_settings_change()
|
params_changed = self.did_export_settings_change()
|
||||||
auto_export(changes_per_scene, params_changed, self)
|
auto_export(changes_per_scene, params_changed, self)
|
||||||
# cleanup
|
# cleanup
|
||||||
print("AUTO EXPORT DONE")
|
print("AUTO EXPORT DONE")
|
||||||
if bpy.context.window_manager.auto_export_tracker.exports_count == 0: # we need this in case there was nothing to export, to make sure change detection is enabled again
|
if bpy.context.window_manager.auto_export_tracker.exports_count == 0: # we need this in case there was nothing to export, to make sure change detection is enabled again
|
||||||
pass #print("YOLOOO")
|
pass #print("YOLOOO")
|
||||||
#py.context.window_manager.auto_export_tracker.enable_change_detection()
|
#py.context.window_manager.auto_export_tracker.enable_change_detection()
|
||||||
@ -217,14 +226,21 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
|
|||||||
#bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
|
#bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
|
||||||
else:
|
else:
|
||||||
print("auto export disabled, skipping")
|
print("auto export disabled, skipping")
|
||||||
|
|
||||||
|
"""if not self.direct_mode:
|
||||||
|
print("enabling")
|
||||||
|
bpy.context.window_manager.auto_export_tracker.enable_change_detection()"""
|
||||||
|
bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
|
print("invoke")
|
||||||
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
|
bpy.context.window_manager.auto_export_tracker.disable_change_detection()
|
||||||
self.load_settings(context)
|
self.load_settings(context)
|
||||||
|
|
||||||
addon_prefs = self
|
addon_prefs = self
|
||||||
[main_scene_names, level_scenes, library_scene_names, library_scenes]=get_scenes(addon_prefs)
|
"""[main_scene_names, level_scenes, library_scene_names, library_scenes]=get_scenes(addon_prefs)
|
||||||
(collections, _) = get_exportable_collections(level_scenes, library_scenes, addon_prefs)
|
(collections, _) = get_exportable_collections(level_scenes, library_scenes, addon_prefs)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -235,15 +251,20 @@ class AutoExportGLTF(Operator, AutoExportGltfAddonPreferences, ExportHelper):
|
|||||||
ui_info = bpy.context.window_manager.exportedCollections.add()
|
ui_info = bpy.context.window_manager.exportedCollections.add()
|
||||||
ui_info.name = collection_name
|
ui_info.name = collection_name
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
self.report({"ERROR"}, "Failed to populate list of exported collections/blueprints")
|
self.report({"ERROR"}, "Failed to populate list of exported collections/blueprints")"""
|
||||||
|
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
wm.fileselect_add(self)
|
wm.fileselect_add(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {'RUNNING_MODAL'}
|
return {'RUNNING_MODAL'}
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def cancel(self, context):
|
def cancel(self, context):
|
||||||
|
print("cancel")
|
||||||
|
#bpy.context.window_manager.auto_export_tracker.enable_change_detection()
|
||||||
bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
|
bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
import bpy
|
import bpy
|
||||||
from bpy.types import (PropertyGroup)
|
from bpy.types import (PropertyGroup)
|
||||||
from bpy.props import (PointerProperty, IntProperty)
|
from bpy.props import (PointerProperty, IntProperty, StringProperty)
|
||||||
|
|
||||||
|
from ..constants import TEMPSCENE_PREFIX
|
||||||
from .internals import CollectionsToExport
|
from .internals import CollectionsToExport
|
||||||
|
|
||||||
class AutoExportTracker(PropertyGroup):
|
class AutoExportTracker(PropertyGroup):
|
||||||
@ -21,6 +22,8 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
default=0
|
default=0
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker)
|
bpy.types.WindowManager.auto_export_tracker = PointerProperty(type=AutoExportTracker)
|
||||||
@ -59,10 +62,15 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def deps_update_handler(cls, scene, depsgraph):
|
def deps_update_handler(cls, scene, depsgraph):
|
||||||
print("change detection enabled", cls.change_detection_enabled, bpy.context.window_manager.auto_export_tracker.change_detection_enabled)
|
print("change detection enabled", cls.change_detection_enabled)
|
||||||
|
|
||||||
|
ops = bpy.context.window_manager.operators
|
||||||
|
print("last operators", ops)
|
||||||
|
for op in ops:
|
||||||
|
print("operator", op)
|
||||||
active_operator = bpy.context.active_operator
|
active_operator = bpy.context.active_operator
|
||||||
if active_operator:
|
if active_operator:
|
||||||
# print("Operator", active_operator.bl_label, active_operator.bl_idname)
|
print("Operator", active_operator.bl_label, active_operator.bl_idname)
|
||||||
if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" and active_operator.gltf_export_id == "gltf_auto_export":
|
if active_operator.bl_idname == "EXPORT_SCENE_OT_gltf" and active_operator.gltf_export_id == "gltf_auto_export":
|
||||||
# we backup any existing gltf export settings, if there were any
|
# we backup any existing gltf export settings, if there were any
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
@ -80,19 +88,21 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
active_operator.will_save_settings = True
|
active_operator.will_save_settings = True
|
||||||
active_operator.auto_export = True
|
active_operator.auto_export = True
|
||||||
|
|
||||||
if not scene.name.startswith("__temp_scene"):
|
# only deal with changes if we are NOT in the mids of saving/exporting
|
||||||
print("depsgraph_update_post", scene.name)
|
if cls.change_detection_enabled:
|
||||||
changed_scene = scene.name or ""
|
# ignore anything going on with temporary scenes
|
||||||
|
if not scene.name.startswith(TEMPSCENE_PREFIX):
|
||||||
|
print("depsgraph_update_post", scene.name)
|
||||||
|
changed_scene = scene.name or ""
|
||||||
|
|
||||||
# only deal with changes if we are no in the mids of saving/exporting
|
|
||||||
if cls.change_detection_enabled:
|
|
||||||
#print("-------------")
|
#print("-------------")
|
||||||
if not changed_scene in cls.changed_objects_per_scene:
|
if not changed_scene in cls.changed_objects_per_scene:
|
||||||
cls.changed_objects_per_scene[changed_scene] = {}
|
cls.changed_objects_per_scene[changed_scene] = {}
|
||||||
|
print("cls.changed_objects_per_scene", cls.changed_objects_per_scene)
|
||||||
# depsgraph = bpy.context.evaluated_depsgraph_get()
|
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||||
for obj in depsgraph.updates:
|
for obj in depsgraph.updates:
|
||||||
# print("depsgraph update", obj)
|
print("depsgraph update", obj)
|
||||||
if isinstance(obj.id, bpy.types.Object):
|
if isinstance(obj.id, bpy.types.Object):
|
||||||
# get the actual object
|
# get the actual object
|
||||||
object = bpy.data.objects[obj.id.name]
|
object = bpy.data.objects[obj.id.name]
|
||||||
@ -100,7 +110,7 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
print("FOO","transforms", obj.is_updated_transform, "geometry", obj.is_updated_geometry)
|
print("FOO","transforms", obj.is_updated_transform, "geometry", obj.is_updated_geometry)
|
||||||
cls.changed_objects_per_scene[scene.name][obj.id.name] = object
|
cls.changed_objects_per_scene[scene.name][obj.id.name] = object
|
||||||
elif isinstance(obj.id, bpy.types.Material): # or isinstance(obj.id, bpy.types.ShaderNodeTree):
|
elif isinstance(obj.id, bpy.types.Material): # or isinstance(obj.id, bpy.types.ShaderNodeTree):
|
||||||
# print("changed material", obj.id, "scene", scene.name,)
|
print("changed material", obj.id, "scene", scene.name,)
|
||||||
material = bpy.data.materials[obj.id.name]
|
material = bpy.data.materials[obj.id.name]
|
||||||
#now find which objects are using the material
|
#now find which objects are using the material
|
||||||
for obj in bpy.data.objects:
|
for obj in bpy.data.objects:
|
||||||
@ -113,10 +123,10 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
items += len(cls.changed_objects_per_scene[scene_name].keys())
|
items += len(cls.changed_objects_per_scene[scene_name].keys())
|
||||||
if items == 0:
|
if items == 0:
|
||||||
cls.changed_objects_per_scene.clear()
|
cls.changed_objects_per_scene.clear()
|
||||||
#print("changed_objects_per_scene", cls.changed_objects_per_scene)
|
print("changed_objects_per_scene", cls.changed_objects_per_scene)
|
||||||
else:
|
else:
|
||||||
cls.changed_objects_per_scene.clear()
|
cls.changed_objects_per_scene.clear()
|
||||||
|
|
||||||
"""depsgraph = bpy.context.evaluated_depsgraph_get()
|
"""depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||||
for update in depsgraph.updates:
|
for update in depsgraph.updates:
|
||||||
print("update", update)"""
|
print("update", update)"""
|
||||||
@ -125,13 +135,15 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
print("disable change detection")
|
print("disable change detection")
|
||||||
self.change_detection_enabled = False
|
self.change_detection_enabled = False
|
||||||
self.__class__.change_detection_enabled = False
|
self.__class__.change_detection_enabled = False
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def enable_change_detection(self):
|
def enable_change_detection(self):
|
||||||
print("enable change detection")
|
print("enable change detection")
|
||||||
self.change_detection_enabled = True
|
self.change_detection_enabled = True
|
||||||
self.__class__.change_detection_enabled = True
|
self.__class__.change_detection_enabled = True
|
||||||
|
#FIXME: not sure about these
|
||||||
|
self.changed_objects_per_scene.clear()
|
||||||
|
self.__class__.changed_objects_per_scene.clear()
|
||||||
# bpy.context.window_manager.auto_export_tracker.change_detection_enabled = True
|
# bpy.context.window_manager.auto_export_tracker.change_detection_enabled = True
|
||||||
print("bpy.context.window_manager.auto_export_tracker.change_detection_enabled", bpy.context.window_manager.auto_export_tracker.change_detection_enabled)
|
print("bpy.context.window_manager.auto_export_tracker.change_detection_enabled", bpy.context.window_manager.auto_export_tracker.change_detection_enabled)
|
||||||
return None
|
return None
|
||||||
@ -141,7 +153,7 @@ class AutoExportTracker(PropertyGroup):
|
|||||||
bpy.context.window_manager.auto_export_tracker.exports_count -= 1
|
bpy.context.window_manager.auto_export_tracker.exports_count -= 1
|
||||||
if bpy.context.window_manager.auto_export_tracker.exports_count == 0:
|
if bpy.context.window_manager.auto_export_tracker.exports_count == 0:
|
||||||
#print("preparing to reset change detection")
|
#print("preparing to reset change detection")
|
||||||
#bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
|
# bpy.app.timers.register(bpy.context.window_manager.auto_export_tracker.enable_change_detection, first_interval=1)
|
||||||
|
|
||||||
self.enable_change_detection()
|
self.enable_change_detection()
|
||||||
return None
|
return None
|
||||||
|
1
tools/gltf_auto_export/constants.py
Normal file
1
tools/gltf_auto_export/constants.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
TEMPSCENE_PREFIX = "__temp_scene"
|
@ -195,11 +195,12 @@ def test_export_changed_parameters(setup_data):
|
|||||||
|
|
||||||
# now same, but move the cube in the library
|
# now same, but move the cube in the library
|
||||||
print("----------------")
|
print("----------------")
|
||||||
print("library change")
|
print("library change (blueprint) ")
|
||||||
print("----------------")
|
print("----------------")
|
||||||
bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but ..
|
bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but ..
|
||||||
|
|
||||||
bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1]
|
bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1]
|
||||||
|
|
||||||
auto_export_operator(
|
auto_export_operator(
|
||||||
auto_export=True,
|
auto_export=True,
|
||||||
direct_mode=True,
|
direct_mode=True,
|
||||||
@ -212,16 +213,54 @@ def test_export_changed_parameters(setup_data):
|
|||||||
|
|
||||||
modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path]))
|
modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path]))
|
||||||
assert modification_times != modification_times_first
|
assert modification_times != modification_times_first
|
||||||
# only the "world" file should have changed
|
# the "world" file should have changed (TODO: double check: this is since changing an instances collection changes the instance too ?)
|
||||||
|
world_file_index = mapped_files_to_timestamps_and_index["World"][1]
|
||||||
|
# and the blueprint1 file too, since that is the collection we changed
|
||||||
blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1]
|
blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1]
|
||||||
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [blueprint1_file_index]]
|
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [world_file_index, blueprint1_file_index]]
|
||||||
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [blueprint1_file_index]]
|
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [world_file_index, blueprint1_file_index]]
|
||||||
|
|
||||||
|
assert modification_times[world_file_index] != modification_times_first[world_file_index]
|
||||||
assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index]
|
assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index]
|
||||||
assert other_files_modification_times == other_files_modification_times_first
|
assert other_files_modification_times == other_files_modification_times_first
|
||||||
# reset the comparing
|
# reset the comparing
|
||||||
modification_times_first = modification_times
|
modification_times_first = modification_times
|
||||||
|
|
||||||
|
|
||||||
|
# now change something in a nested blueprint
|
||||||
|
print("----------------")
|
||||||
|
print("library change (nested blueprint) ")
|
||||||
|
print("----------------")
|
||||||
|
bpy.context.window_manager.auto_export_tracker.enable_change_detection() # FIXME: should not be needed, but ..
|
||||||
|
|
||||||
|
bpy.data.objects["Blueprint3_mesh"]["test_component"] = 42
|
||||||
|
|
||||||
|
auto_export_operator(
|
||||||
|
auto_export=True,
|
||||||
|
direct_mode=True,
|
||||||
|
export_output_folder="./models",
|
||||||
|
export_scene_settings=True,
|
||||||
|
export_blueprints=True,
|
||||||
|
export_legacy_mode=False,
|
||||||
|
export_materials_library=False
|
||||||
|
)
|
||||||
|
|
||||||
|
modification_times = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths + [world_file_path]))
|
||||||
|
assert modification_times != modification_times_first
|
||||||
|
# the "world" file should have changed (TODO: double check: this is since changing an instances collection changes the instance too ?)
|
||||||
|
world_file_index = mapped_files_to_timestamps_and_index["World"][1]
|
||||||
|
# and the blueprint1 file too, since that is the collection we changed
|
||||||
|
blueprint1_file_index = mapped_files_to_timestamps_and_index["Blueprint1"][1]
|
||||||
|
other_files_modification_times = [value for index, value in enumerate(modification_times) if index not in [world_file_index, blueprint1_file_index]]
|
||||||
|
other_files_modification_times_first = [value for index, value in enumerate(modification_times_first) if index not in [world_file_index, blueprint1_file_index]]
|
||||||
|
|
||||||
|
assert modification_times[world_file_index] != modification_times_first[world_file_index]
|
||||||
|
assert modification_times[blueprint1_file_index] != modification_times_first[blueprint1_file_index]
|
||||||
|
assert other_files_modification_times == other_files_modification_times_first
|
||||||
|
# reset the comparing
|
||||||
|
modification_times_first = modification_times
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# now same, but using an operator
|
# now same, but using an operator
|
||||||
|
@ -47,8 +47,28 @@ def setup_data(request):
|
|||||||
- checks if timestamps have changed
|
- checks if timestamps have changed
|
||||||
- if all worked => test is a-ok
|
- if all worked => test is a-ok
|
||||||
- removes generated files
|
- removes generated files
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_no_parameters(setup_data):
|
||||||
|
root_path = "../../testing/bevy_example"
|
||||||
|
assets_root_path = os.path.join(root_path, "assets")
|
||||||
|
models_path = os.path.join(assets_root_path, "models")
|
||||||
|
auto_export_operator = bpy.ops.export_scenes.auto_gltf
|
||||||
|
|
||||||
|
|
||||||
|
# first test exporting withouth any parameters set, this should export with default parameters gracefully
|
||||||
|
|
||||||
|
auto_export_operator(
|
||||||
|
auto_export=True,
|
||||||
|
direct_mode=True,
|
||||||
|
export_output_folder="./models",
|
||||||
|
export_legacy_mode=False,
|
||||||
|
export_materials_library=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_export_changed_parameters(setup_data):
|
def test_export_changed_parameters(setup_data):
|
||||||
root_path = "../../testing/bevy_example"
|
root_path = "../../testing/bevy_example"
|
||||||
assets_root_path = os.path.join(root_path, "assets")
|
assets_root_path = os.path.join(root_path, "assets")
|
||||||
@ -77,11 +97,6 @@ def test_export_changed_parameters(setup_data):
|
|||||||
stored_gltf_settings.clear()
|
stored_gltf_settings.clear()
|
||||||
stored_gltf_settings.write(json.dumps(gltf_settings))
|
stored_gltf_settings.write(json.dumps(gltf_settings))
|
||||||
|
|
||||||
# move the main cube
|
|
||||||
bpy.data.objects["Cube"].location = [1, 0, 0]
|
|
||||||
# move the cube in the library
|
|
||||||
bpy.data.objects["Blueprint1_mesh"].location = [1, 2, 1]
|
|
||||||
|
|
||||||
auto_export_operator(
|
auto_export_operator(
|
||||||
auto_export=True,
|
auto_export=True,
|
||||||
direct_mode=True,
|
direct_mode=True,
|
||||||
|
4
tools/gltf_auto_export/todo.md
Normal file
4
tools/gltf_auto_export/todo.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
- investigate remove_blueprints_list_from_main_scene (could be a case of changes to bpy.data not being applied immediatly)
|
||||||
|
- investigate clearing of changed_objects_per_scene
|
||||||
|
- it seems bevy_components does not trigger updates
|
||||||
|
- undo redo is ignored: ie save, do something, undo it, you still get changes
|
@ -48,6 +48,15 @@ class GLTF_PT_auto_export_SidePanel(bpy.types.Panel):
|
|||||||
|
|
||||||
op = layout.operator("EXPORT_SCENES_OT_auto_gltf", text="Auto Export Settings")
|
op = layout.operator("EXPORT_SCENES_OT_auto_gltf", text="Auto Export Settings")
|
||||||
op.auto_export = True
|
op.auto_export = True
|
||||||
|
|
||||||
|
layout.label(text="changes since last save:")
|
||||||
|
changed_objects_per_scene = {}
|
||||||
|
for scene in context.window_manager.auto_export_tracker.changed_objects_per_scene:
|
||||||
|
if not scene in changed_objects_per_scene.keys():
|
||||||
|
changed_objects_per_scene[scene] = []
|
||||||
|
changed_objects_per_scene[scene]+= context.window_manager.auto_export_tracker.changed_objects_per_scene[scene].keys()
|
||||||
|
|
||||||
|
layout.label(text=str(changed_objects_per_scene))
|
||||||
#print("GLTF_PT_export_main", GLTF_PT_export_main.bl_parent_id)
|
#print("GLTF_PT_export_main", GLTF_PT_export_main.bl_parent_id)
|
||||||
|
|
||||||
# main ui in the file => export
|
# main ui in the file => export
|
||||||
|
Loading…
Reference in New Issue
Block a user