fix(tools:bevy_gltf_blueprints): (#27)

* fix(tools:bevy_gltf_blueprints):
 * fixed missing rotation in blueprint collections (if there is any)
 * fixed similar issues with scale 
 * fixed issues with active collection at the time of saving/export being poluted by temporary data
* refactor(bevy_gltf_blueprints): minor cleanups
This commit is contained in:
Mark Moissette 2023-10-14 20:47:35 +02:00 committed by GitHub
parent 5683f01cea
commit 921a5ef331
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 20 additions and 33 deletions

Binary file not shown.

Binary file not shown.

View File

@ -50,7 +50,7 @@ pub(crate) fn spawn_from_blueprints(
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
blueprints_config: Res<BluePrintsConfig>, blueprints_config: Res<BluePrintsConfig>,
) { ) {
for (entity, name, blupeprint_name, global_transform) in spawn_placeholders.iter() { for (entity, name, blupeprint_name, transform) in spawn_placeholders.iter() {
debug!("need to spawn {:?}", blupeprint_name.0); debug!("need to spawn {:?}", blupeprint_name.0);
let what = &blupeprint_name.0; let what = &blupeprint_name.0;
let model_file_name = format!("{}.glb", &what); let model_file_name = format!("{}.glb", &what);
@ -59,7 +59,6 @@ pub(crate) fn spawn_from_blueprints(
debug!("attempting to spawn {:?}", model_path); debug!("attempting to spawn {:?}", model_path);
let scene: Handle<Gltf> = asset_server.load(model_path); let scene: Handle<Gltf> = asset_server.load(model_path);
// let scene = game_assets.models.get(&model_path).expect(&format!("no matching model {:?} found", model_path));
let world = game_world.single_mut(); let world = game_world.single_mut();
let world = world.1[0]; // FIXME: dangerous hack because our gltf data have a single child like this, but might not always be the case let world = world.1[0]; // FIXME: dangerous hack because our gltf data have a single child like this, but might not always be the case
@ -75,21 +74,16 @@ pub(crate) fn spawn_from_blueprints(
.expect("there should be at least one named scene in the gltf file to spawn"); .expect("there should be at least one named scene in the gltf file to spawn");
let scene = &gltf.named_scenes[main_scene_name]; let scene = &gltf.named_scenes[main_scene_name];
//spawn_requested_events.send(SpawnRequestedEvent { what: "enemy".into(), position, amount: 1, spawner_id: None });
let child_scene = commands let child_scene = commands
.spawn(( .spawn((
SceneBundle { SceneBundle {
scene: scene.clone(), scene: scene.clone(),
transform: global_transform.clone(), transform: transform.clone(),
..Default::default() ..Default::default()
}, },
bevy::prelude::Name::from(["scene_wrapper", &name.clone()].join("_")), bevy::prelude::Name::from(["scene_wrapper", &name.clone()].join("_")),
// Parent(world) // FIXME/ would be good if this worked directly // Parent(world) // FIXME/ would be good if this worked directly
SpawnedRoot, SpawnedRoot,
/*AnimationHelper{ // TODO: insert this at the ENTITY level, not the scene level
named_animations: gltf.named_animations.clone(),
// animations: gltf.named_animations.values().clone()
},*/
Original(entity), Original(entity),
)) ))
.id(); .id();

View File

@ -17,7 +17,6 @@ pub(crate) struct SpawnedRootProcessed;
/// this system updates the first (and normally only) child of a scene flaged SpawnedRoot /// this system updates the first (and normally only) child of a scene flaged SpawnedRoot
/// - adds a name based on parent component (spawned scene) which is named on the scene name/prefab to be instanciated /// - adds a name based on parent component (spawned scene) which is named on the scene name/prefab to be instanciated
/// - adds the initial physics impulse (FIXME: we would need to add a temporary physics component to those who do not have it)
// FIXME: updating hierarchy does not work in all cases ! this is sadly dependant on the structure of the exported blend data // FIXME: updating hierarchy does not work in all cases ! this is sadly dependant on the structure of the exported blend data
// - blender root-> object with properties => WORKS // - blender root-> object with properties => WORKS
// - scene instance -> does not work // - scene instance -> does not work
@ -78,28 +77,20 @@ pub(crate) fn update_spawned_root_first_child(
commands.entity(*root_entity).insert(( commands.entity(*root_entity).insert((
bevy::prelude::Name::from(name.clone()), bevy::prelude::Name::from(name.clone()),
// ItemType {name}, // ItemType {name},
// Spawned, // FIXME: not sure
)); ));
// flag the spawned_root as being processed // flag the spawned_root as being processed
commands.entity(scene_instance).insert(SpawnedRootProcessed); commands.entity(scene_instance).insert(SpawnedRootProcessed);
// let original_transforms =
// parent is either the world or an entity with a marker (BlueprintName) // parent is either the world or an entity with a marker (BlueprintName)
commands.entity(parent.get()).add_child(*root_entity); commands.entity(parent.get()).add_child(*root_entity);
// commands.entity(*root_entity).despawn_recursive();
// commands.entity(parent.get()).push_children(&actual_stuff);
//commands.entity(*root_entity).log_components();
let matching_animation_helper = animation_helpers.get(scene_instance); let matching_animation_helper = animation_helpers.get(scene_instance);
// println!("WE HAVE SOME ADDED ANIMATION PLAYERS {:?}", matching_animation_helper);
if let Ok(anim_helper) = matching_animation_helper { if let Ok(anim_helper) = matching_animation_helper {
for (added, _) in added_animation_helpers.iter() { for (added, _) in added_animation_helpers.iter() {
commands.entity(added).insert(AnimationHelper { commands.entity(added).insert(AnimationHelper {
// TODO: insert this at the ENTITY level, not the scene level
named_animations: anim_helper.named_animations.clone(), named_animations: anim_helper.named_animations.clone(),
// animations: gltf.named_animations.values().clone()
}); });
} }
} }

View File

@ -1,8 +1,8 @@
bl_info = { bl_info = {
"name": "gltf_auto_export", "name": "gltf_auto_export",
"author": "kaosigh", "author": "kaosigh",
"version": (0, 2), "version": (0, 3),
"blender": (3, 4, 1), "blender": (3, 4, 0),
"location": "File > Import-Export", "location": "File > Import-Export",
"description": "glTF/glb auto-export", "description": "glTF/glb auto-export",
"warning": "", "warning": "",
@ -30,9 +30,7 @@ from bpy.props import (BoolProperty,
#see here for original gltf exporter infos https://github.com/KhronosGroup/glTF-Blender-IO/blob/main/addons/io_scene_gltf2/__init__.py #see here for original gltf exporter infos https://github.com/KhronosGroup/glTF-Blender-IO/blob/main/addons/io_scene_gltf2/__init__.py
@persistent @persistent
def deps_update_handler(scene, depsgraph): def deps_update_handler(scene, depsgraph):
print("depsgraph_update_post", scene.name) print("depsgraph_update_post", scene.name)
print("toto")
print("-------------") print("-------------")
changed_objects = [] changed_objects = []
for obj in depsgraph.updates: for obj in depsgraph.updates:
@ -91,7 +89,9 @@ def get_collection_hierarchy(root_col, levels=1):
# the active collection is a View Layer concept, so you actually have to find the active LayerCollection # the active collection is a View Layer concept, so you actually have to find the active LayerCollection
# which must be done recursively # which must be done recursively
def find_layer_collection_recursive(find, col): def find_layer_collection_recursive(find, col):
print("root collection", col)
for c in col.children: for c in col.children:
print("child collection", c)
if c.collection == find: if c.collection == find:
return c return c
return None return None
@ -129,18 +129,16 @@ def make_empty2(name, location, collection):
collection.objects.link( empty_obj ) collection.objects.link( empty_obj )
return empty_obj return empty_obj
def make_empty3(name, location, collection): def make_empty3(name, location, rotation, scale, collection):
original_active_object = bpy.context.active_object original_active_object = bpy.context.active_object
bpy.ops.object.empty_add(type='PLAIN_AXES', location=location) bpy.ops.object.empty_add(type='PLAIN_AXES', location=location, rotation=rotation, scale=scale)
empty_obj = bpy.context.active_object empty_obj = bpy.context.active_object
empty_obj.name = name empty_obj.name = name
collection.objects.link( empty_obj ) empty_obj.scale = scale # scale is not set correctly ?????
bpy.context.view_layer.objects.active = original_active_object bpy.context.view_layer.objects.active = original_active_object
return empty_obj return empty_obj
# generate a copy of a scene that replaces collection instances with empties # generate a copy of a scene that replaces collection instances with empties
# FIXME: will not preserve original names
# alternative: copy original names before creating a new scene, & reset them # alternative: copy original names before creating a new scene, & reset them
# or create empties, hide original ones, and do the same renaming trick # or create empties, hide original ones, and do the same renaming trick
def generate_hollow_scene(scene): def generate_hollow_scene(scene):
@ -149,6 +147,8 @@ def generate_hollow_scene(scene):
copy_root_collection = temp_scene.collection copy_root_collection = temp_scene.collection
scene_objects = [o for o in root_collection.objects] scene_objects = [o for o in root_collection.objects]
# we set our active scene to be this one : this is needed otherwise the stand-in empties get generated in the wrong scene
bpy.context.window.scene = temp_scene
found = find_layer_collection_recursive(copy_root_collection, bpy.context.view_layer.layer_collection) found = find_layer_collection_recursive(copy_root_collection, bpy.context.view_layer.layer_collection)
if found: if found:
@ -171,7 +171,7 @@ def generate_hollow_scene(scene):
original_names.append(original_name) original_names.append(original_name)
object.name = original_name + "____bak" object.name = original_name + "____bak"
empty_obj = make_empty3(original_name, object.location, copy_root_collection) empty_obj = make_empty3(original_name, object.location, object.rotation_euler, object.scale, copy_root_collection)
"""we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object""" """we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object"""
empty_obj['BlueprintName'] = '"'+collection_name+'"' empty_obj['BlueprintName'] = '"'+collection_name+'"'
empty_obj['SpawnHere'] = '' empty_obj['SpawnHere'] = ''
@ -194,9 +194,7 @@ def clear_hollow_scene(temp_scene, original_scene, original_names):
for object in scene_objects: for object in scene_objects:
if object.instance_type == 'COLLECTION': if object.instance_type == 'COLLECTION':
print("object name to reset", object.name)
if object.name.endswith("____bak"): if object.name.endswith("____bak"):
print("reseting")
object.name = object.name.replace("____bak", "") object.name = object.name.replace("____bak", "")
# remove empties (only needed when we go via ops ????) # remove empties (only needed when we go via ops ????)
@ -204,7 +202,11 @@ def clear_hollow_scene(temp_scene, original_scene, original_names):
scene_objects = [o for o in root_collection.objects] scene_objects = [o for o in root_collection.objects]
for object in scene_objects: for object in scene_objects:
if object.type == 'EMPTY': if object.type == 'EMPTY':
if hasattr(object, "SpawnHere"):
bpy.data.objects.remove(object, do_unlink=True) bpy.data.objects.remove(object, do_unlink=True)
else:
bpy.context.scene.collection.objects.unlink(object)
#bpy.data.objects.remove(object, do_unlink=True)
bpy.data.scenes.remove(temp_scene) bpy.data.scenes.remove(temp_scene)