加载第一个 glTF
bevy 的 glTF 加载器随 DefaultPlugins 自动注册。加载一个 .gltf 或 .glb 文件只需要两步:AssetServer::load 取句柄,WorldAssetRoot 组件把场景挂上实体。
rust
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
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),
));
commands.spawn(WorldAssetRoot(
asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
));
}Listing 23-1:最小 glTF 加载——三行核心代码(examples/listing-23-01.rs)
console
cargo run -p ch23-gltf --example listing-23-01一个头盔出现在窗口里。
GltfAssetLabel::Scene(0) 是什么意思
glTF 文件内部可以包含多个场景(Scene)。GltfAssetLabel::Scene(0) 表示"取第一个场景"。.from_asset("path") 把标签拼到路径后面,等价于 "path#Scene0"。
为什么必须写标签?因为 AssetServer::load 不知道你要取 glTF 里的哪一部分——是整个场景、某个节点、还是单独一个网格。标签就是精确的取货地址。不写标签,加载器不知道该给你什么,行为未定义。
WorldAssetRoot 组件
WorldAssetRoot(Handle<WorldAsset>) 是 bevy_scene 提供的组件。挂上它,Bevy 的场景系统会在下一帧把 glTF 场景里的全部实体——网格、材质、变换层级——自动展开为 ECS 实体,作为该实体的子节点。
glTF 场景里的变换层级原样保留:如果模型在 Blender 里有父子关系,加载到 Bevy 后父子关系不变。
机位与灯
3D 场景的标配——Camera3d 和 DirectionalLight——在 Listing 23-1 里照旧需要手动 spawn。glTF 文件可能自带灯光信息(通过 KHR_lights_punctual 扩展),但 Bevy 默认不导入它们,你需要自己在场景里布置光照。