#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![forbid(unsafe_code)] #![doc( html_logo_url = "https://bevyengine.org/assets/icon.png", html_favicon_url = "https://bevyengine.org/assets/icon.png" )] //! Plugin providing an [`AssetLoader`](bevy_asset::AssetLoader) and type definitions //! for loading glTF 2.0 (a standard 3D scene definition format) files in Bevy. //! //! The [glTF 2.0 specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html) defines the format of the glTF files. //! //! # Quick Start //! //! Here's how to spawn a simple glTF scene //! //! ``` //! # use bevy_ecs::prelude::*; //! # use bevy_asset::prelude::*; //! # use bevy_scene::prelude::*; //! # use bevy_transform::prelude::*; //! # use bevy_gltf::prelude::*; //! //! fn spawn_gltf(mut commands: Commands, asset_server: Res) { //! commands.spawn(( //! // This is equivalent to "models/FlightHelmet/FlightHelmet.gltf#Scene0" //! // The `#Scene0` label here is very important because it tells bevy to load the first scene in the glTF file. //! // If this isn't specified bevy doesn't know which part of the glTF file to load. //! SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"))), //! // You can use the transform to give it a position //! Transform::from_xyz(2.0, 0.0, -5.0), //! )); //! } //! ``` //! # Loading parts of a glTF asset //! //! ## Using `Gltf` //! //! If you want to access part of the asset, you can load the entire `Gltf` using the `AssetServer`. //! Once the `Handle` is loaded you can then use it to access named parts of it. //! //! ``` //! # use bevy_ecs::prelude::*; //! # use bevy_asset::prelude::*; //! # use bevy_scene::prelude::*; //! # use bevy_transform::prelude::*; //! # use bevy_gltf::Gltf; //! //! // Holds the scene handle //! #[derive(Resource)] //! struct HelmetScene(Handle); //! //! fn load_gltf(mut commands: Commands, asset_server: Res) { //! let gltf = asset_server.load("models/FlightHelmet/FlightHelmet.gltf"); //! commands.insert_resource(HelmetScene(gltf)); //! } //! //! fn spawn_gltf_objects( //! mut commands: Commands, //! helmet_scene: Res, //! gltf_assets: Res>, //! mut loaded: Local, //! ) { //! // Only do this once //! if *loaded { //! return; //! } //! // Wait until the scene is loaded //! let Some(gltf) = gltf_assets.get(&helmet_scene.0) else { //! return; //! }; //! *loaded = true; //! //! // Spawns the first scene in the file //! commands.spawn(SceneRoot(gltf.scenes[0].clone())); //! //! // Spawns the scene named "Lenses_low" //! commands.spawn(( //! SceneRoot(gltf.named_scenes["Lenses_low"].clone()), //! Transform::from_xyz(1.0, 2.0, 3.0), //! )); //! } //! ``` //! //! ## Asset Labels //! //! The glTF loader let's you specify labels that let you target specific parts of the glTF. //! //! Be careful when using this feature, if you misspell a label it will simply ignore it without warning. //! //! You can use [`GltfAssetLabel`] to ensure you are using the correct label. mod assets; mod label; mod loader; mod vertex_attributes; extern crate alloc; use bevy_platform_support::collections::HashMap; use bevy_app::prelude::*; use bevy_asset::AssetApp; use bevy_image::CompressedImageFormats; use bevy_mesh::MeshVertexAttribute; use bevy_render::renderer::RenderDevice; /// The glTF prelude. /// /// This includes the most common types in this crate, re-exported for your convenience. pub mod prelude { #[doc(hidden)] pub use crate::{assets::Gltf, assets::GltfExtras, label::GltfAssetLabel}; } pub use {assets::*, label::GltfAssetLabel, loader::*}; /// Adds support for glTF file loading to the app. #[derive(Default)] pub struct GltfPlugin { custom_vertex_attributes: HashMap, MeshVertexAttribute>, } impl GltfPlugin { /// Register a custom vertex attribute so that it is recognized when loading a glTF file with the [`GltfLoader`]. /// /// `name` must be the attribute name as found in the glTF data, which must start with an underscore. /// See [this section of the glTF specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview) /// for additional details on custom attributes. pub fn add_custom_vertex_attribute( mut self, name: &str, attribute: MeshVertexAttribute, ) -> Self { self.custom_vertex_attributes.insert(name.into(), attribute); self } } impl Plugin for GltfPlugin { fn build(&self, app: &mut App) { app.register_type::() .register_type::() .register_type::() .register_type::() .register_type::() .init_asset::() .init_asset::() .init_asset::() .init_asset::() .init_asset::() .preregister_asset_loader::(&["gltf", "glb"]); } fn finish(&self, app: &mut App) { let supported_compressed_formats = match app.world().get_resource::() { Some(render_device) => CompressedImageFormats::from_features(render_device.features()), None => CompressedImageFormats::NONE, }; app.register_asset_loader(GltfLoader { supported_compressed_formats, custom_vertex_attributes: self.custom_vertex_attributes.clone(), }); } }