Reacting to Loaded GLTF Asset #9246
-
I am pretty sure I am doing this wrong, and while I definitely would appreciate being told the correct way to do this, I'd also appreciate understanding why this isn't working as I expect it to. I am trying to use Blender as a level editor, creating both the level itself as well as collisions, triggers, and the player spawn. I have exported my scene to fn load_modular_house(asset: Res<AssetServer>) {
let _: Handle<Gltf> = asset.load("ModularHouse.gltf");
} Looking at the Unofficial Bevy Cheatbook, I found out about reacting to assets loading using the fn spawn_modular_house(
mut commands: Commands,
assets: Res<Assets<Gltf>>,
mut asset_event_reader: EventReader<AssetEvent<Gltf>>,
) {
if let Some(asset_event) = asset_event_reader.iter().next() {
match asset_event {
AssetEvent::Created { handle } => {
// Unwrap is ok since we know for a fact that it's loaded.
let modular_house = assets.get(handle).unwrap();
commands.spawn(SceneBundle {
scene: modular_house.scenes[0].clone(),
..Default::default()
});
}
_ => ()
}
}
} This works great! The scene gets spawned as expected and the camera within my scene gets appropriately loaded. However, it isn't what I need. Since I need to also handle collisions, I want to be able to spawn each mesh individually so that I can detect which ones are actually collision and spawn a collider instead of a mesh. To test this I modified the function to do this: fn spawn_modular_house(
mut commands: Commands,
assets: Res<Assets<Gltf>>,
mut asset_event_reader: EventReader<AssetEvent<Gltf>>,
) {
if let Some(asset_event) = asset_event_reader.iter().next() {
match asset_event {
AssetEvent::Created { handle } => {
// Unwrap is ok since we know for a fact that it's loaded.
let modular_house = assets.get(handle).unwrap();
for node in modular_house.named_materials.keys() {
log::info!("FOUND NODE: {}", node);
}
}
_ => ()
}
}
} My comment is ironic since this is where bevy panics right on the unwrap. Why does this happen? Did I misinterpret what Also, I just realized I used |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 1 reply
-
I'm currently not capable to answer your question about why it happens (might come back to this later) But I can answer how to fix it. I would directly load the asset as a |
Beta Was this translation helpful? Give feedback.
-
Regarding the question on why it panics. I think the second code listing might be missing something. Do you mean it panics on let modular_house = assets.get(handle).unwrap(); Yet I don't see how it could, up to this point, it is the exact same code as the non-panicking code. Did you mean to post different code? Like maybe trying to access a Hmm from my understanding of the gltf loader this shouldn't happen. Can you give more details. |
Beta Was this translation helpful? Give feedback.
-
Here's the extra details
As a sanity check I decided to retest my code to verify the above bullet points and... the sanity check failed which means I might be insane. The code now crashes on unwrap as expected when I use the following code: fn load_modular_house(asset: Res<AssetServer>) {
let _: Handle<Gltf> = asset.load("ModularHouse.gltf");
}
fn spawn_modular_house(
mut commands: Commands,
assets: Res<Assets<Gltf>>,
mut asset_event_reader: EventReader<AssetEvent<Gltf>>,
) {
if let Some(asset_event) = asset_event_reader.iter().next() {
match asset_event {
AssetEvent::Created { handle } => {
// Unwrap is ok since we know for a fact that it's loaded.
let modular_house = assets.get(handle).unwrap();
/*
for node in modular_house.named_nodes.keys() {
log::info!("FOUND NODE: {}", node);
}
*/
commands.spawn(SceneBundle {
scene: modular_house.scenes[0].clone(),
..Default::default()
});
}
_ => ()
}
}
} Didn't change anything about this code (other than changing Unless there's anything else you can notice or point out about it, I'll probably just mark your bevy-scene-hook reply as the answer and chalk this up to some weird ghost story. |
Beta Was this translation helpful? Give feedback.
-
I now understand what is going on. You are dropping the handle, and the In this: fn load_modular_house(asset: Res<AssetServer>) {
let _: Handle<Gltf> = asset.load("ModularHouse.gltf");
} You drop the handle immediately after loading the asset. When there is no more handles referencing an asset existing, the asset is unloaded (https://docs.rs/bevy/latest/bevy/asset/struct.Handle.html#strong-and-weak). I suspect sometimes the asset systems notice before/after your If you want to keep an asset loaded, you should store the handle in a |
Beta Was this translation helpful? Give feedback.
I now understand what is going on.
You are dropping the handle, and the
Gltf
asset gets unloaded before you have time to retrieve it from theAssets
.In this:
You drop the handle immediately after loading the asset. When there is no more handles referencing an asset existing, the asset is unloaded (https://docs.rs/bevy/latest/bevy/asset/struct.Handle.html#strong-and-weak).
I suspect sometimes the asset systems notice before/after your
spawn_modular_house
system runs, which lead to the inconsistent behavior.If you want to keep an asset loaded, you should store the handle in a
Reso…