Skip to content

按名字取实体

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_scenesHashMap<Box<str>, Handle<WorldAsset>>按名字索引的场景
named_nodesHashMap<Box<str>, Handle<GltfNode>>按名字索引的节点
named_meshesHashMap<Box<str>, Handle<GltfMesh>>按名字索引的网格
named_materialsHashMap<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 的父子层级。