按名字取实体
GltfAssetLabel 不只有 Scene 一个变体。它是一组精确的取货地址,覆盖 glTF 文件里的每一种子资产:
| 变体 | 取出的类型 | 说明 |
|---|---|---|
Scene(usize) | Handle<WorldAsset> | 第 N 个场景 |
Node(usize) | Handle<GltfNode> | 第 N 个节点 |
Mesh(usize) | Handle<GltfMesh> | 第 N 个网格 |
Primitive { mesh, primitive } | Handle<Mesh> | 第 N 个网格的第 M 个图元 |
Material { index, is_scale_inverted } | Handle<StandardMaterial> | 第 N 个材质 |
Texture(usize) | Handle<Image> | 第 N 张纹理 |
Animation(usize) | Handle<AnimationClip> | 第 N 段动画 |
Skin(usize) | Handle<GltfSkin> | 第 N 个蒙皮 |
from_asset 方法把标签拼到资产路径后面。等价的字符串写法是 format!("path#Scene0"),但 GltfAssetLabel 有类型检查,拼错了编译器会拦。
加载完整 Gltf 资产
GltfAssetLabel 取的是子资产的句柄。如果想拿到整个 glTF 文件的结构化信息——所有场景、节点、网格、材质的命名索引——应该直接加载 Gltf 类型:
rust
let gltf: Handle<Gltf> = asset_server.load("models/FlightHelmet/FlightHelmet.gltf");加载完成后,Assets<Gltf> 里的 Gltf 结构体提供一组 HashMap<Box<str>, Handle<T>>:
| 字段 | 类型 | 说明 |
|---|---|---|
named_scenes | HashMap<Box<str>, Handle<WorldAsset>> | 按名字索引的场景 |
named_nodes | HashMap<Box<str>, Handle<GltfNode>> | 按名字索引的节点 |
named_meshes | HashMap<Box<str>, Handle<GltfMesh>> | 按名字索引的网格 |
named_materials | HashMap<Box<str>, Handle<StandardMaterial>> | 按名字索引的材质 |
名字来自 Blender 里的命名。在 Blender 里给物体、材质起好名字,导出后 Bevy 就能按名字找到它们。
rust
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, print_named_entities)
.run();
}
#[derive(Resource)]
struct GltfAsset(Handle<Gltf>);
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
));
commands.spawn((
DirectionalLight {
contact_shadows_enabled: true,
..default()
},
Transform::from_xyz(4.0, 25.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
));
let handle = asset_server.load("models/FlightHelmet/FlightHelmet.gltf");
commands.insert_resource(GltfAsset(handle));
}
fn print_named_entities(
gltf_res: Res<GltfAsset>,
gltf_assets: Res<Assets<Gltf>>,
mut printed: Local<bool>,
) {
if *printed {
return;
}
let Some(gltf) = gltf_assets.get(&gltf_res.0) else {
return;
};
*printed = true;
println!("scenes: {}", gltf.scenes.len());
for (name, _) in &gltf.named_scenes {
println!(" named scene: {name}");
}
for (name, _) in &gltf.named_nodes {
println!(" named node: {name}");
}
for (name, _) in &gltf.named_meshes {
println!(" named mesh: {name}");
}
}Listing 23-3:加载完整 Gltf 资产,遍历命名的场景、节点和网格(examples/listing-23-03.rs)
console
cargo run -p ch23-gltf --example listing-23-03输出会列出 FlightHelmet 里的所有命名实体。这些名字直接对应 Blender 大纲视图里的物体名。
GltfNode 里有什么
每个 GltfNode 携带:
index:节点在 glTF 文件中的索引name:节点名(Blender 里的物体名)children:子节点句柄列表mesh:可选的网格句柄transform:该节点的局部变换
节点是 glTF 的骨架概念——它描述场景图里的一个位置,可能挂着网格、灯光或相机。Bevy 的 glTF 加载器会把节点结构转成 ECS 的父子层级。