Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use workflows for model spawning #238

Merged
merged 39 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d37eb61
WIP skeleton for model workflow
luca-della-vedova Aug 6, 2024
bebffd3
Minimum example for despawn issue
luca-della-vedova Aug 7, 2024
0f5d9b1
WIP figuring out asset dependency management
luca-della-vedova Aug 7, 2024
07d0acf
WIP adding model workflows
luca-della-vedova Aug 29, 2024
ccc8a96
Merge remote-tracking branch 'origin/main' into luca/model_workflows
luca-della-vedova Aug 29, 2024
d2aa4e5
Partially fix workcell model spawning
luca-della-vedova Aug 29, 2024
f4f83aa
Fix scale being applied twice
luca-della-vedova Aug 29, 2024
0604af5
WIP model workflows working
luca-della-vedova Sep 3, 2024
c88c267
First round of cleanups
luca-della-vedova Sep 3, 2024
083dba1
Additional cleanup
luca-della-vedova Sep 3, 2024
62c3df7
Fix saving, propagation, make service blocking
luca-della-vedova Sep 3, 2024
f4161a9
Further cleanup
luca-della-vedova Sep 4, 2024
0cbe7f7
Fix failed API loading, add note for SDF exporter
luca-della-vedova Sep 4, 2024
c82a472
YAGNI run, fix saving of model previews
luca-della-vedova Sep 4, 2024
756e105
Minor cleanup
luca-della-vedova Sep 4, 2024
70931f4
Fix sdf exporter, corner cases with scales and errors
luca-della-vedova Sep 5, 2024
1ffd52f
Address TODOs
luca-della-vedova Sep 5, 2024
9bde074
Address model cleanup
luca-della-vedova Sep 5, 2024
ad502f0
Remove marker component
luca-della-vedova Sep 5, 2024
073e4f6
Simplify scene component adding logic
luca-della-vedova Sep 13, 2024
459cc23
Minor fixes
luca-della-vedova Sep 13, 2024
915edad
Reinstate ModelFailedLoading component
luca-della-vedova Nov 14, 2024
e85c37d
Clarify field name in ModelScene component
luca-della-vedova Nov 14, 2024
5351e94
Use SceneInstance with Deref
luca-della-vedova Nov 14, 2024
07b871a
Preempt multiple model loading requests to the same entity
luca-della-vedova Nov 14, 2024
7e132d1
Merge remote-tracking branch 'origin/main' into luca/model_workflows
luca-della-vedova Nov 15, 2024
f1c90ed
Update bevy_impulse dependency
luca-della-vedova Nov 15, 2024
5feaf8b
Use SystemParam based API
luca-della-vedova Nov 18, 2024
60f9695
WIP compile error on map_block
luca-della-vedova Nov 18, 2024
da47b27
Fix compile error, move to ok_or_else, fix error format
luca-della-vedova Nov 18, 2024
29e9783
Fix fuel asset preview visibility
luca-della-vedova Nov 18, 2024
760e80f
Cleanup skip_if_unchanged
luca-della-vedova Nov 18, 2024
fcc7fdb
Update rmf_site_editor/src/site/model.rs
luca-della-vedova Dec 5, 2024
1a918fa
Update rmf_site_editor/src/site/model.rs
luca-della-vedova Dec 5, 2024
66d3153
Return error if gltf contains no scene
luca-della-vedova Dec 5, 2024
a3a322f
Minor cleanup
luca-della-vedova Dec 5, 2024
a55f964
Update lockfile for wasm-bindgen build
luca-della-vedova Dec 5, 2024
82c4fd4
Update rmf_site_editor/src/site/model.rs
luca-della-vedova Dec 6, 2024
e1552ef
Update lockfile for bevy_impulse
mxgrey Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 7 additions & 31 deletions rmf_site_editor/src/interaction/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
use crate::{
animate::*,
interaction::*,
site::{AnchorBundle, Pending, SiteAssets, Trashcan},
site::{AnchorBundle, ModelSpawningExt, Pending, SiteAssets},
};
use bevy::{ecs::system::SystemParam, prelude::*, window::PrimaryWindow};
use bevy_mod_raycast::primitives::{rays::Ray3d, Primitive3d};

use rmf_site_format::{FloorMarker, Model, WallMarker, WorkcellModel};
use rmf_site_format::{FloorMarker, Model, WallMarker};
use std::collections::HashSet;

/// A resource that keeps track of the unique entities that play a role in
Expand All @@ -37,7 +37,6 @@ pub struct Cursor {
pub level_anchor_placement: Entity,
pub site_anchor_placement: Entity,
pub frame_placement: Entity,
pub trashcan: Entity,
pub preview_model: Option<Entity>,
dependents: HashSet<Entity>,
/// Use a &str to label each mode that might want to turn the cursor on
Expand Down Expand Up @@ -116,37 +115,17 @@ impl Cursor {
}

pub fn remove_preview(&mut self, commands: &mut Commands) {
if let Some(current_preview) = self.preview_model {
commands.get_entity(current_preview).map(|mut e_mut| {
e_mut.set_parent(self.trashcan);
});
self.preview_model = None;
if let Some(current_preview) = self.preview_model.take() {
commands.entity(current_preview).despawn_recursive();
}
}

// TODO(luca) reduce duplication here
pub fn set_model_preview(&mut self, commands: &mut Commands, model: Option<Model>) {
self.remove_preview(commands);
self.preview_model = if let Some(model) = model {
let e = commands.spawn(model).insert(Pending).id();
commands.entity(self.frame).push_children(&[e]);
Some(e)
} else {
None
}
}

pub fn set_workcell_model_preview(
&mut self,
commands: &mut Commands,
model: Option<WorkcellModel>,
) {
self.remove_preview(commands);
self.preview_model = if let Some(model) = model {
let mut cmd = commands.spawn(Pending);
let e = cmd.id();
model.add_bevy_components(&mut cmd);
commands.entity(self.frame).push_children(&[e]);
let source = model.source.clone();
let e = commands.spawn((model, Pending)).set_parent(self.frame).id();
commands.spawn_model((e, source).into());
Some(e)
} else {
None
Expand Down Expand Up @@ -261,16 +240,13 @@ impl FromWorld for Cursor {
})
.id();

let trashcan = world.spawn(Trashcan).id();

Self {
frame: cursor,
halo,
dagger,
level_anchor_placement,
site_anchor_placement,
frame_placement,
trashcan,
preview_model: None,
dependents: Default::default(),
modes: Default::default(),
Expand Down
12 changes: 10 additions & 2 deletions rmf_site_editor/src/interaction/select/place_object_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
*
*/

use crate::{interaction::select::*, site::Model};
use crate::{
interaction::select::*,
site::{Model, ModelSpawningExt},
};
use bevy::prelude::Input as UserInput;

pub const PLACE_OBJECT_2D_MODE_LABEL: &'static str = "place_object_2d";
Expand Down Expand Up @@ -201,7 +204,12 @@ pub fn on_placement_chosen_2d(
let mut state = access.pull().or_broken_state()?;

state.object.pose = placement.into();
commands.spawn(state.object).set_parent(state.level);
let source = state.object.source.clone();
let id = commands
.spawn((Category::Model, state.object))
.set_parent(state.level)
.id();
commands.spawn_model((id, source).into());

Ok(())
}
56 changes: 36 additions & 20 deletions rmf_site_editor/src/interaction/select/place_object_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
use crate::{
interaction::select::*,
site::{
Anchor, AnchorBundle, Dependents, FrameMarker, Model, NameInSite, NameInWorkcell, Pending,
SiteID, WorkcellModel,
Anchor, AnchorBundle, Dependents, FrameMarker, Model, ModelLoadingRequest,
ModelSpawningExt, NameInWorkcell, Pending, SiteID,
},
widgets::canvas_tooltips::CanvasTooltips,
workcell::flatten_loaded_model_hierarchy,
};
use bevy::{
ecs::system::{EntityCommands, SystemParam},
prelude::Input as UserInput,
};
use bevy::{ecs::system::SystemParam, prelude::Input as UserInput};
use bevy_mod_raycast::deferred::RaycastSource;
use std::borrow::Cow;

Expand Down Expand Up @@ -150,8 +154,8 @@ pub struct PlaceObject3d {
pub enum PlaceableObject {
Model(Model),
Anchor,
VisualMesh(WorkcellModel),
CollisionMesh(WorkcellModel),
VisualMesh(Model),
CollisionMesh(Model),
}

pub fn place_object_3d_setup(
Expand All @@ -174,18 +178,14 @@ pub fn place_object_3d_setup(
set_visibility(cursor.dagger, &mut visibility, true);
set_visibility(cursor.halo, &mut visibility, true);
}
PlaceableObject::Model(m) => {
PlaceableObject::Model(m)
| PlaceableObject::VisualMesh(m)
| PlaceableObject::CollisionMesh(m) => {
// Spawn the model as a child of the cursor
cursor.set_model_preview(&mut commands, Some(m.clone()));
set_visibility(cursor.dagger, &mut visibility, false);
set_visibility(cursor.halo, &mut visibility, false);
}
PlaceableObject::VisualMesh(m) | PlaceableObject::CollisionMesh(m) => {
// Spawn the model as a child of the cursor
cursor.set_workcell_model_preview(&mut commands, Some(m.clone()));
set_visibility(cursor.dagger, &mut visibility, false);
set_visibility(cursor.halo, &mut visibility, false);
}
}

if let Some(parent) = state.parent {
Expand Down Expand Up @@ -238,7 +238,7 @@ pub fn place_object_3d_find_placement(
hovering: Res<Hovering>,
mouse_button_input: Res<UserInput<MouseButton>>,
blockers: Option<Res<PickingBlockers>>,
meta: Query<(Option<&'static NameInSite>, Option<&'static SiteID>)>,
meta: Query<(Option<&'static NameInWorkcell>, Option<&'static SiteID>)>,
mut filter: PlaceObject3dFilter,
) {
let Some(mut orders) = orders.get_mut(&srv_key) else {
Expand Down Expand Up @@ -458,6 +458,10 @@ pub fn on_placement_chosen_3d(
let placement_tf = placement.compute_affine();
let pose = Transform::from_matrix((inv_tf * placement_tf).into()).into();

let flatten_models = flatten_loaded_model_hierarchy.into_blocking_callback();
let add_model_components = |object: Model, mut cmd: EntityCommands| {
cmd.insert((NameInWorkcell(object.name.0), object.pose, object.scale));
};
let id = match state.object {
PlaceableObject::Anchor => commands
.spawn((
Expand All @@ -467,7 +471,11 @@ pub fn on_placement_chosen_3d(
))
.id(),
PlaceableObject::Model(object) => {
let model_id = commands.spawn((object, VisualCue::outline())).id();
let model_id = commands.spawn(VisualCue::outline()).id();
let source = object.source.clone();
add_model_components(object, commands.entity(model_id));
let req = ModelLoadingRequest::new(model_id, source).then(flatten_models);
commands.spawn_model(req);
// Create a parent anchor to contain the new model in
commands
.spawn((
Expand All @@ -480,16 +488,24 @@ pub fn on_placement_chosen_3d(
.id()
}
PlaceableObject::VisualMesh(mut object) => {
let id = commands.spawn((VisualMeshMarker, Category::Visual)).id();
object.pose = pose;
let mut cmd = commands.spawn(VisualMeshMarker);
object.add_bevy_components(&mut cmd);
cmd.id()
let source = object.source.clone();
add_model_components(object, commands.entity(id));
let req = ModelLoadingRequest::new(id, source).then(flatten_models);
commands.spawn_model(req);
id
}
PlaceableObject::CollisionMesh(mut object) => {
let id = commands
.spawn((CollisionMeshMarker, Category::Collision))
.id();
object.pose = pose;
let mut cmd = commands.spawn(CollisionMeshMarker);
object.add_bevy_components(&mut cmd);
cmd.id()
let source = object.source.clone();
add_model_components(object, commands.entity(id));
let req = ModelLoadingRequest::new(id, source).then(flatten_models);
commands.spawn_model(req);
id
}
};

Expand Down
8 changes: 6 additions & 2 deletions rmf_site_editor/src/sdf_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl AssetLoader for SdfLoader {
let mut bytes = Vec::new();
// TODO(luca) remove unwrap
reader.read_to_end(&mut bytes).await.unwrap();
Ok(load_model(bytes, load_context).await?)
Ok(load_model(bytes, load_context)?)
})
}

Expand Down Expand Up @@ -131,8 +131,12 @@ fn compute_model_source<'a, 'b>(
Ok(asset_source)
} else {
// It's a path relative to this model, concatenate it to the current context path.
// Note that since the current path is the file (i.e. path/subfolder/model.sdf) we need to
// concatenate to its parent
let path = load_context
.asset_path()
.parent()
.unwrap()
.resolve(subasset_uri)
.or_else(|e| Err(SdfError::UnsupportedAssetSource(e.to_string())))?;
AssetSource::try_from(path.to_string().as_str()).map_err(SdfError::UnsupportedAssetSource)
Expand Down Expand Up @@ -239,7 +243,7 @@ fn spawn_geometry<'a, 'b>(
Ok(geometry)
}

async fn load_model<'a, 'b>(
fn load_model<'a, 'b>(
bytes: Vec<u8>,
load_context: &'a mut LoadContext<'b>,
) -> Result<bevy::scene::Scene, SdfError> {
Expand Down
8 changes: 4 additions & 4 deletions rmf_site_editor/src/site/fuel_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*
*/

use crate::site::{ModelMarker, ModelSceneRoot, TentativeModelFormat};
use crate::site::{AssetSource, ModelScene, ModelSpawningExt};
use crate::site_asset_io::FUEL_API_KEY;
use crate::widgets::AssetGalleryStatus;
use bevy::prelude::*;
Expand Down Expand Up @@ -127,7 +127,7 @@ pub fn read_update_fuel_cache_results(
pub fn reload_failed_models_with_new_api_key(
mut commands: Commands,
mut api_key_events: EventReader<SetFuelApiKey>,
failed_models: Query<Entity, (With<ModelMarker>, Without<ModelSceneRoot>)>,
failed_models: Query<(Entity, &AssetSource), Without<ModelScene>>,
) {
if let Some(key) = api_key_events.read().last() {
info!("New API Key set, attempting to re-download failed models");
Expand All @@ -136,8 +136,8 @@ pub fn reload_failed_models_with_new_api_key(
Err(poisoned) => poisoned.into_inner(),
};
*key_guard = Some((**key).clone());
for e in &failed_models {
commands.entity(e).insert(TentativeModelFormat::default());
for (e, source) in &failed_models {
commands.spawn_model((e, source.clone()).into());
}
}
}
15 changes: 10 additions & 5 deletions rmf_site_editor/src/site/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,6 @@ fn generate_site_entities(
consider_id(*light_id);
}

for (model_id, model) in &level_data.models {
level.spawn(model.clone()).insert(SiteID(*model_id));
consider_id(*model_id);
}

for (physical_camera_id, physical_camera) in &level_data.physical_cameras {
level
.spawn(physical_camera.clone())
Expand All @@ -230,6 +225,16 @@ fn generate_site_entities(
}
});

for (model_id, model) in &level_data.models {
let source = model.source.clone();
let model_entity = commands
.spawn((Category::Model, model.clone(), SiteID(*model_id)))
.set_parent(level_entity)
.id();
commands.spawn_model((model_entity, source).into());
consider_id(*model_id);
}

// TODO(MXG): Log when a RecencyRanking fails to load correctly.
commands
.entity(level_entity)
Expand Down
17 changes: 1 addition & 16 deletions rmf_site_editor/src/site/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ impl Plugin for SitePlugin {
.init_resource::<PhysicalLightToggle>()
.init_resource::<FuelCacheUpdateChannel>()
.init_resource::<FuelCacheProgressChannel>()
.init_resource::<ModelTrashcan>()
.register_type::<NameInSite>()
.register_type::<AssetSource>()
.register_type::<Pose>()
Expand Down Expand Up @@ -263,6 +262,7 @@ impl Plugin for SitePlugin {
DeletionPlugin,
DrawingEditorPlugin,
SiteVisualizerPlugin,
ModelLoadingPlugin::default(),
))
.add_issue_type(&DUPLICATED_DOOR_NAME_ISSUE_UUID, "Duplicate door name")
.add_issue_type(&DUPLICATED_LIFT_NAME_ISSUE_UUID, "Duplicate lift name")
Expand All @@ -278,7 +278,6 @@ impl Plugin for SitePlugin {
(
update_lift_cabin,
update_lift_edge,
update_model_tentative_formats,
update_drawing_pixels_per_meter,
update_drawing_children_to_pixel_coordinates,
check_for_duplicated_door_names,
Expand Down Expand Up @@ -320,7 +319,6 @@ impl Plugin for SitePlugin {
add_category_to_graphs,
add_tags_to_lift,
add_material_for_display_colors,
clear_model_trashcan,
add_physical_lights,
)
.run_if(AppState::in_site_mode())
Expand Down Expand Up @@ -392,22 +390,9 @@ impl Plugin for SitePlugin {
.add_systems(
PostUpdate,
(
(
propagate_model_properties,
make_models_selectable,
// Counter-intuitively, we want to expand the model scenes
// after propagating the model properties through the scene.
// The reason is that the entities for the scene won't be
// available until the next cycle is finished, so we want to
// wait until the next cycle before propagating the properties
// of any newly added scenes.
handle_model_loaded_events,
)
.chain(),
add_measurement_visuals,
update_changed_measurement,
update_measurement_for_moved_anchors,
update_model_scenes,
update_affiliations,
update_members_of_groups.after(update_affiliations),
update_model_scales,
Expand Down
Loading
Loading