mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
glTF labels: add enum to avoid misspelling and keep up-to-date list documented (#13586)
# Objective - Followup to #13548 - It added a list of all possible labels to documentation. This seems hard to keep up and doesn't stop people from making spelling mistake ## Solution - Add an enum that can create all the labels possible, and encourage its use rather than manually typed labels --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Rob Parrett <robparrett@gmail.com>
This commit is contained in:
parent
ce46d52536
commit
5559632977
30 changed files with 293 additions and 117 deletions
|
@ -19,12 +19,14 @@
|
|||
//! # 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<AssetServer>) {
|
||||
//! commands.spawn(SceneBundle {
|
||||
//! // 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.
|
||||
//! scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
//! scene: asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
//! // You can use the transform to give it a position
|
||||
//! transform: Transform::from_xyz(2.0, 0.0, -5.0),
|
||||
//! ..Default::default()
|
||||
|
@ -91,18 +93,7 @@
|
|||
//!
|
||||
//! Be careful when using this feature, if you misspell a label it will simply ignore it without warning.
|
||||
//!
|
||||
//! Here's the list of supported labels (`{}` is the index in the file):
|
||||
//!
|
||||
//! - `Scene{}`: glTF Scene as a Bevy `Scene`
|
||||
//! - `Node{}`: glTF Node as a `GltfNode`
|
||||
//! - `Mesh{}`: glTF Mesh as a `GltfMesh`
|
||||
//! - `Mesh{}/Primitive{}`: glTF Primitive as a Bevy `Mesh`
|
||||
//! - `Mesh{}/Primitive{}/MorphTargets`: Morph target animation data for a glTF Primitive
|
||||
//! - `Texture{}`: glTF Texture as a Bevy `Image`
|
||||
//! - `Material{}`: glTF Material as a Bevy `StandardMaterial`
|
||||
//! - `DefaultMaterial`: as above, if the glTF file contains a default material with no index
|
||||
//! - `Animation{}`: glTF Animation as Bevy `AnimationClip`
|
||||
//! - `Skin{}`: glTF mesh skin as Bevy `SkinnedMeshInverseBindposes`
|
||||
//! You can use [`GltfAssetLabel`] to ensure you are using the correct label.
|
||||
|
||||
#[cfg(feature = "bevy_animation")]
|
||||
use bevy_animation::AnimationClip;
|
||||
|
@ -113,7 +104,7 @@ mod vertex_attributes;
|
|||
pub use loader::*;
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_asset::{Asset, AssetApp, Handle};
|
||||
use bevy_asset::{Asset, AssetApp, AssetPath, Handle};
|
||||
use bevy_ecs::{prelude::Component, reflect::ReflectComponent};
|
||||
use bevy_pbr::StandardMaterial;
|
||||
use bevy_reflect::{Reflect, TypePath};
|
||||
|
@ -124,6 +115,12 @@ use bevy_render::{
|
|||
};
|
||||
use bevy_scene::Scene;
|
||||
|
||||
/// The `bevy_gltf` prelude.
|
||||
pub mod prelude {
|
||||
#[doc(hidden)]
|
||||
pub use crate::{Gltf, GltfAssetLabel, GltfExtras};
|
||||
}
|
||||
|
||||
/// Adds support for glTF file loading to the app.
|
||||
#[derive(Default)]
|
||||
pub struct GltfPlugin {
|
||||
|
@ -251,3 +248,118 @@ pub struct GltfExtras {
|
|||
/// Content of the extra data.
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
/// Labels that can be used to load part of a glTF
|
||||
///
|
||||
/// You can use [`GltfAssetLabel::from_asset`] to add it to an asset path
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_asset::prelude::*;
|
||||
/// # use bevy_scene::prelude::*;
|
||||
/// # use bevy_gltf::prelude::*;
|
||||
///
|
||||
/// fn load_gltf_scene(asset_server: Res<AssetServer>) {
|
||||
/// let gltf_scene: Handle<Scene> = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"));
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Or when formatting a string for the path
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_asset::prelude::*;
|
||||
/// # use bevy_scene::prelude::*;
|
||||
/// # use bevy_gltf::prelude::*;
|
||||
///
|
||||
/// fn load_gltf_scene(asset_server: Res<AssetServer>) {
|
||||
/// let gltf_scene: Handle<Scene> = asset_server.load(format!("models/FlightHelmet/FlightHelmet.gltf#{}", GltfAssetLabel::Scene(0)));
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum GltfAssetLabel {
|
||||
/// `Scene{}`: glTF Scene as a Bevy `Scene`
|
||||
Scene(usize),
|
||||
/// `Node{}`: glTF Node as a `GltfNode`
|
||||
Node(usize),
|
||||
/// `Mesh{}`: glTF Mesh as a `GltfMesh`
|
||||
Mesh(usize),
|
||||
/// `Mesh{}/Primitive{}`: glTF Primitive as a Bevy `Mesh`
|
||||
Primitive {
|
||||
/// Index of the mesh for this primitive
|
||||
mesh: usize,
|
||||
/// Index of this primitive in its parent mesh
|
||||
primitive: usize,
|
||||
},
|
||||
/// `Mesh{}/Primitive{}/MorphTargets`: Morph target animation data for a glTF Primitive
|
||||
MorphTarget {
|
||||
/// Index of the mesh for this primitive
|
||||
mesh: usize,
|
||||
/// Index of this primitive in its parent mesh
|
||||
primitive: usize,
|
||||
},
|
||||
/// `Texture{}`: glTF Texture as a Bevy `Image`
|
||||
Texture(usize),
|
||||
/// `Material{}`: glTF Material as a Bevy `StandardMaterial`
|
||||
Material {
|
||||
/// Index of this material
|
||||
index: usize,
|
||||
/// Used to set the [`Face`](bevy_render::render_resource::Face) of the material, useful if it is used with negative scale
|
||||
is_scale_inverted: bool,
|
||||
},
|
||||
/// `DefaultMaterial`: as above, if the glTF file contains a default material with no index
|
||||
DefaultMaterial,
|
||||
/// `Animation{}`: glTF Animation as Bevy `AnimationClip`
|
||||
Animation(usize),
|
||||
/// `Skin{}`: glTF mesh skin as Bevy `SkinnedMeshInverseBindposes`
|
||||
Skin(usize),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GltfAssetLabel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GltfAssetLabel::Scene(index) => f.write_str(&format!("Scene{index}")),
|
||||
GltfAssetLabel::Node(index) => f.write_str(&format!("Node{index}")),
|
||||
GltfAssetLabel::Mesh(index) => f.write_str(&format!("Mesh{index}")),
|
||||
GltfAssetLabel::Primitive { mesh, primitive } => {
|
||||
f.write_str(&format!("Mesh{mesh}/Primitive{primitive}"))
|
||||
}
|
||||
GltfAssetLabel::MorphTarget { mesh, primitive } => {
|
||||
f.write_str(&format!("Mesh{mesh}/Primitive{primitive}/MorphTargets"))
|
||||
}
|
||||
GltfAssetLabel::Texture(index) => f.write_str(&format!("Texture{index}")),
|
||||
GltfAssetLabel::Material {
|
||||
index,
|
||||
is_scale_inverted,
|
||||
} => f.write_str(&format!(
|
||||
"Material{index}{}",
|
||||
if *is_scale_inverted {
|
||||
" (inverted)"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)),
|
||||
GltfAssetLabel::DefaultMaterial => f.write_str("DefaultMaterial"),
|
||||
GltfAssetLabel::Animation(index) => f.write_str(&format!("Animation{index}")),
|
||||
GltfAssetLabel::Skin(index) => f.write_str(&format!("Skin{index}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GltfAssetLabel {
|
||||
/// Add this label to an asset path
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_asset::prelude::*;
|
||||
/// # use bevy_scene::prelude::*;
|
||||
/// # use bevy_gltf::prelude::*;
|
||||
///
|
||||
/// fn load_gltf_scene(asset_server: Res<AssetServer>) {
|
||||
/// let gltf_scene: Handle<Scene> = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn from_asset(&self, path: impl Into<AssetPath<'static>>) -> AssetPath<'static> {
|
||||
path.into().with_label(self.to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::GltfAssetLabel;
|
||||
use crate::{vertex_attributes::convert_attribute, Gltf, GltfExtras, GltfNode};
|
||||
#[cfg(feature = "bevy_animation")]
|
||||
use bevy_animation::{AnimationTarget, AnimationTargetId};
|
||||
|
@ -316,8 +317,10 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||
);
|
||||
}
|
||||
}
|
||||
let handle = load_context
|
||||
.add_labeled_asset(format!("Animation{}", animation.index()), animation_clip);
|
||||
let handle = load_context.add_labeled_asset(
|
||||
GltfAssetLabel::Animation(animation.index()).to_string(),
|
||||
animation_clip,
|
||||
);
|
||||
if let Some(name) = animation.name() {
|
||||
named_animations.insert(name.into(), handle.clone());
|
||||
}
|
||||
|
@ -337,7 +340,9 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||
texture: ImageOrPath,
|
||||
) {
|
||||
let handle = match texture {
|
||||
ImageOrPath::Image { label, image } => load_context.add_labeled_asset(label, image),
|
||||
ImageOrPath::Image { label, image } => {
|
||||
load_context.add_labeled_asset(label.to_string(), image)
|
||||
}
|
||||
ImageOrPath::Path {
|
||||
path,
|
||||
is_srgb,
|
||||
|
@ -435,7 +440,10 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||
for gltf_mesh in gltf.meshes() {
|
||||
let mut primitives = vec![];
|
||||
for primitive in gltf_mesh.primitives() {
|
||||
let primitive_label = primitive_label(&gltf_mesh, &primitive);
|
||||
let primitive_label = GltfAssetLabel::Primitive {
|
||||
mesh: gltf_mesh.index(),
|
||||
primitive: primitive.index(),
|
||||
};
|
||||
let primitive_topology = get_primitive_topology(primitive.mode())?;
|
||||
|
||||
let mut mesh = Mesh::new(primitive_topology, settings.load_meshes);
|
||||
|
@ -478,14 +486,17 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||
{
|
||||
let morph_target_reader = reader.read_morph_targets();
|
||||
if morph_target_reader.len() != 0 {
|
||||
let morph_targets_label = morph_targets_label(&gltf_mesh, &primitive);
|
||||
let morph_targets_label = GltfAssetLabel::MorphTarget {
|
||||
mesh: gltf_mesh.index(),
|
||||
primitive: primitive.index(),
|
||||
};
|
||||
let morph_target_image = MorphTargetImage::new(
|
||||
morph_target_reader.map(PrimitiveMorphAttributesIter),
|
||||
mesh.count_vertices(),
|
||||
RenderAssetUsages::default(),
|
||||
)?;
|
||||
let handle =
|
||||
load_context.add_labeled_asset(morph_targets_label, morph_target_image.0);
|
||||
let handle = load_context
|
||||
.add_labeled_asset(morph_targets_label.to_string(), morph_target_image.0);
|
||||
|
||||
mesh.set_morph_targets(handle);
|
||||
let extras = gltf_mesh.extras().as_ref();
|
||||
|
@ -540,7 +551,7 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||
});
|
||||
}
|
||||
|
||||
let mesh = load_context.add_labeled_asset(primitive_label, mesh);
|
||||
let mesh = load_context.add_labeled_asset(primitive_label.to_string(), mesh);
|
||||
primitives.push(super::GltfPrimitive {
|
||||
mesh,
|
||||
material: primitive
|
||||
|
@ -553,7 +564,7 @@ async fn load_gltf<'a, 'b, 'c>(
|
|||
}
|
||||
|
||||
let handle = load_context.add_labeled_asset(
|
||||
mesh_label(&gltf_mesh),
|
||||
GltfAssetLabel::Mesh(gltf_mesh.index()).to_string(),
|
||||
super::GltfMesh {
|
||||
primitives,
|
||||
extras: get_gltf_extras(gltf_mesh.extras()),
|
||||
|
@ -808,7 +819,7 @@ async fn load_image<'a, 'b>(
|
|||
)?;
|
||||
Ok(ImageOrPath::Image {
|
||||
image,
|
||||
label: texture_label(&gltf_texture),
|
||||
label: GltfAssetLabel::Texture(gltf_texture.index()),
|
||||
})
|
||||
}
|
||||
gltf::image::Source::Uri { uri, mime_type } => {
|
||||
|
@ -830,7 +841,7 @@ async fn load_image<'a, 'b>(
|
|||
ImageSampler::Descriptor(sampler_descriptor),
|
||||
render_asset_usages,
|
||||
)?,
|
||||
label: texture_label(&gltf_texture),
|
||||
label: GltfAssetLabel::Texture(gltf_texture.index()),
|
||||
})
|
||||
} else {
|
||||
let image_path = parent_path.join(uri);
|
||||
|
@ -1247,12 +1258,15 @@ fn load_node(
|
|||
load_material(&material, load_context, document, is_scale_inverted);
|
||||
}
|
||||
|
||||
let primitive_label = primitive_label(&mesh, &primitive);
|
||||
let primitive_label = GltfAssetLabel::Primitive {
|
||||
mesh: mesh.index(),
|
||||
primitive: primitive.index(),
|
||||
};
|
||||
let bounds = primitive.bounding_box();
|
||||
|
||||
let mut mesh_entity = parent.spawn(PbrBundle {
|
||||
// TODO: handle missing label handle errors here?
|
||||
mesh: load_context.get_label_handle(&primitive_label),
|
||||
mesh: load_context.get_label_handle(primitive_label.to_string()),
|
||||
material: load_context.get_label_handle(&material_label),
|
||||
..Default::default()
|
||||
});
|
||||
|
@ -1400,8 +1414,12 @@ fn load_node(
|
|||
// Only include meshes in the output if they're set to be retained in the MAIN_WORLD and/or RENDER_WORLD by the load_meshes flag
|
||||
if !settings.load_meshes.is_empty() {
|
||||
if let (Some(mesh), Some(weights)) = (gltf_node.mesh(), morph_weights) {
|
||||
let primitive_label = mesh.primitives().next().map(|p| primitive_label(&mesh, &p));
|
||||
let first_mesh = primitive_label.map(|label| load_context.get_label_handle(label));
|
||||
let primitive_label = mesh.primitives().next().map(|p| GltfAssetLabel::Primitive {
|
||||
mesh: mesh.index(),
|
||||
primitive: p.index(),
|
||||
});
|
||||
let first_mesh =
|
||||
primitive_label.map(|label| load_context.get_label_handle(label.to_string()));
|
||||
node.insert(MorphWeights::new(weights, first_mesh)?);
|
||||
}
|
||||
}
|
||||
|
@ -1413,16 +1431,6 @@ fn load_node(
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the label for the `mesh`.
|
||||
fn mesh_label(mesh: &gltf::Mesh) -> String {
|
||||
format!("Mesh{}", mesh.index())
|
||||
}
|
||||
|
||||
/// Returns the label for the `mesh` and `primitive`.
|
||||
fn primitive_label(mesh: &gltf::Mesh, primitive: &Primitive) -> String {
|
||||
format!("Mesh{}/Primitive{}", mesh.index(), primitive.index())
|
||||
}
|
||||
|
||||
fn primitive_name(mesh: &gltf::Mesh, primitive: &Primitive) -> String {
|
||||
let mesh_name = mesh.name().unwrap_or("Mesh");
|
||||
if mesh.primitives().len() > 1 {
|
||||
|
@ -1432,37 +1440,23 @@ fn primitive_name(mesh: &gltf::Mesh, primitive: &Primitive) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the label for the morph target of `primitive`.
|
||||
fn morph_targets_label(mesh: &gltf::Mesh, primitive: &Primitive) -> String {
|
||||
format!(
|
||||
"Mesh{}/Primitive{}/MorphTargets",
|
||||
mesh.index(),
|
||||
primitive.index()
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the label for the `material`.
|
||||
fn material_label(material: &Material, is_scale_inverted: bool) -> String {
|
||||
if let Some(index) = material.index() {
|
||||
format!(
|
||||
"Material{index}{}",
|
||||
if is_scale_inverted { " (inverted)" } else { "" }
|
||||
)
|
||||
GltfAssetLabel::Material {
|
||||
index,
|
||||
is_scale_inverted,
|
||||
}
|
||||
.to_string()
|
||||
} else {
|
||||
"MaterialDefault".to_string()
|
||||
GltfAssetLabel::DefaultMaterial.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the label for the `texture`.
|
||||
fn texture_label(texture: &gltf::Texture) -> String {
|
||||
format!("Texture{}", texture.index())
|
||||
}
|
||||
|
||||
fn texture_handle(load_context: &mut LoadContext, texture: &gltf::Texture) -> Handle<Image> {
|
||||
match texture.source().source() {
|
||||
Source::View { .. } => {
|
||||
let label = texture_label(texture);
|
||||
load_context.get_label_handle(&label)
|
||||
load_context.get_label_handle(GltfAssetLabel::Texture(texture.index()).to_string())
|
||||
}
|
||||
Source::Uri { uri, .. } => {
|
||||
let uri = percent_encoding::percent_decode_str(uri)
|
||||
|
@ -1470,8 +1464,7 @@ fn texture_handle(load_context: &mut LoadContext, texture: &gltf::Texture) -> Ha
|
|||
.unwrap();
|
||||
let uri = uri.as_ref();
|
||||
if let Ok(_data_uri) = DataUri::parse(uri) {
|
||||
let label = texture_label(texture);
|
||||
load_context.get_label_handle(&label)
|
||||
load_context.get_label_handle(GltfAssetLabel::Texture(texture.index()).to_string())
|
||||
} else {
|
||||
let parent = load_context.path().parent().unwrap();
|
||||
let image_path = parent.join(uri);
|
||||
|
@ -1501,16 +1494,16 @@ fn texture_handle_from_info(
|
|||
|
||||
/// Returns the label for the `node`.
|
||||
fn node_label(node: &Node) -> String {
|
||||
format!("Node{}", node.index())
|
||||
GltfAssetLabel::Node(node.index()).to_string()
|
||||
}
|
||||
|
||||
/// Returns the label for the `scene`.
|
||||
fn scene_label(scene: &gltf::Scene) -> String {
|
||||
format!("Scene{}", scene.index())
|
||||
GltfAssetLabel::Scene(scene.index()).to_string()
|
||||
}
|
||||
|
||||
fn skin_label(skin: &gltf::Skin) -> String {
|
||||
format!("Skin{}", skin.index())
|
||||
GltfAssetLabel::Skin(skin.index()).to_string()
|
||||
}
|
||||
|
||||
/// Extracts the texture sampler data from the glTF texture.
|
||||
|
@ -1687,7 +1680,7 @@ fn resolve_node_hierarchy(
|
|||
enum ImageOrPath {
|
||||
Image {
|
||||
image: Image,
|
||||
label: String,
|
||||
label: GltfAssetLabel,
|
||||
},
|
||||
Path {
|
||||
path: PathBuf,
|
||||
|
|
|
@ -66,3 +66,7 @@ pub use crate::gilrs::*;
|
|||
#[doc(hidden)]
|
||||
#[cfg(feature = "bevy_state")]
|
||||
pub use crate::state::prelude::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "bevy_gltf")]
|
||||
pub use crate::gltf::prelude::*;
|
||||
|
|
|
@ -42,7 +42,13 @@ fn setup(
|
|||
mut materials: ResMut<Assets<CustomMaterial>>,
|
||||
) {
|
||||
// Add a mesh loaded from a glTF file. This mesh has data for `ATTRIBUTE_BARYCENTRIC`.
|
||||
let mesh = asset_server.load("models/barycentric/barycentric.gltf#Mesh0/Primitive0");
|
||||
let mesh = asset_server.load(
|
||||
GltfAssetLabel::Primitive {
|
||||
mesh: 0,
|
||||
primitive: 0,
|
||||
}
|
||||
.from_asset("models/barycentric/barycentric.gltf"),
|
||||
);
|
||||
commands.spawn(MaterialMesh2dBundle {
|
||||
mesh: Mesh2dHandle(mesh),
|
||||
material: materials.add(CustomMaterial {}),
|
||||
|
|
|
@ -282,7 +282,8 @@ fn setup(
|
|||
|
||||
// Flight Helmet
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -72,7 +72,8 @@ fn setup_terrain_scene(
|
|||
|
||||
// Terrain
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/terrain/Mountains.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/terrain/Mountains.gltf")),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -149,7 +149,8 @@ fn spawn_coated_glass_bubble_sphere(
|
|||
fn spawn_golf_ball(commands: &mut Commands, asset_server: &AssetServer) {
|
||||
commands
|
||||
.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/GolfBall/GolfBall.glb#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/GolfBall/GolfBall.glb")),
|
||||
transform: Transform::from_xyz(1.0, 1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
|
||||
..default()
|
||||
})
|
||||
|
|
|
@ -381,13 +381,16 @@ fn add_camera(commands: &mut Commands, asset_server: &AssetServer, color_grading
|
|||
fn add_basic_scene(commands: &mut Commands, asset_server: &AssetServer) {
|
||||
// Spawn the main scene.
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/TonemappingTest/TonemappingTest.gltf#Scene0"),
|
||||
scene: asset_server.load(
|
||||
GltfAssetLabel::Scene(0).from_asset("models/TonemappingTest/TonemappingTest.gltf"),
|
||||
),
|
||||
..default()
|
||||
});
|
||||
|
||||
// Spawn the flight helmet.
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
transform: Transform::from_xyz(0.5, 0.0, -0.5)
|
||||
.with_rotation(Quat::from_rotation_y(-0.15 * PI)),
|
||||
..default()
|
||||
|
|
|
@ -80,7 +80,8 @@ fn setup(
|
|||
});
|
||||
|
||||
// FlightHelmet
|
||||
let helmet_scene = asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0");
|
||||
let helmet_scene = asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"));
|
||||
|
||||
commands.spawn(SceneBundle {
|
||||
scene: helmet_scene.clone(),
|
||||
|
|
|
@ -88,7 +88,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, app_settings: R
|
|||
|
||||
// Spawn the scene.
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/DepthOfFieldExample/DepthOfFieldExample.glb#Scene0"),
|
||||
scene: asset_server.load(
|
||||
GltfAssetLabel::Scene(0)
|
||||
.from_asset("models/DepthOfFieldExample/DepthOfFieldExample.glb"),
|
||||
),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -503,16 +503,19 @@ fn handle_mouse_clicks(
|
|||
|
||||
impl FromWorld for ExampleAssets {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let fox_animation = world.load_asset("models/animated/Fox.glb#Animation1");
|
||||
let fox_animation =
|
||||
world.load_asset(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb"));
|
||||
let (fox_animation_graph, fox_animation_node) =
|
||||
AnimationGraph::from_clip(fox_animation.clone());
|
||||
|
||||
ExampleAssets {
|
||||
main_sphere: world.add_asset(Sphere::default().mesh().uv(32, 18)),
|
||||
fox: world.load_asset("models/animated/Fox.glb#Scene0"),
|
||||
fox: world.load_asset(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
|
||||
main_sphere_material: world.add_asset(Color::from(SILVER)),
|
||||
main_scene: world
|
||||
.load_asset("models/IrradianceVolumeExample/IrradianceVolumeExample.glb#Scene0"),
|
||||
main_scene: world.load_asset(
|
||||
GltfAssetLabel::Scene(0)
|
||||
.from_asset("models/IrradianceVolumeExample/IrradianceVolumeExample.glb"),
|
||||
),
|
||||
irradiance_volume: world.load_asset("irradiance_volumes/Example.vxgi.ktx2"),
|
||||
fox_animation_graph: world.add_asset(fox_animation_graph),
|
||||
fox_animation_node,
|
||||
|
|
|
@ -14,7 +14,8 @@ fn main() {
|
|||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/CornellBox/CornellBox.glb#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/CornellBox/CornellBox.glb")),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
..default()
|
||||
});
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ fn setup(
|
|||
// Spawns the cubes, light, and camera.
|
||||
fn spawn_scene(commands: &mut Commands, asset_server: &AssetServer) {
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/cubes/Cubes.glb#Scene0"),
|
||||
scene: asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/cubes/Cubes.glb")),
|
||||
..SceneBundle::default()
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ fn setup(
|
|||
});
|
||||
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
|
||||
scene: asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -164,7 +164,8 @@ fn spawn_cube(
|
|||
fn spawn_flight_helmet(commands: &mut Commands, asset_server: &AssetServer) {
|
||||
commands
|
||||
.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
transform: Transform::from_scale(Vec3::splat(2.5)),
|
||||
..default()
|
||||
})
|
||||
|
|
|
@ -93,7 +93,9 @@ fn setup_basic_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
// Main scene
|
||||
commands
|
||||
.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/TonemappingTest/TonemappingTest.gltf#Scene0"),
|
||||
scene: asset_server.load(
|
||||
GltfAssetLabel::Scene(0).from_asset("models/TonemappingTest/TonemappingTest.gltf"),
|
||||
),
|
||||
..default()
|
||||
})
|
||||
.insert(SceneNumber(1));
|
||||
|
@ -101,7 +103,8 @@ fn setup_basic_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
// Flight Helmet
|
||||
commands.spawn((
|
||||
SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
transform: Transform::from_xyz(0.5, 0.0, -0.5)
|
||||
.with_rotation(Quat::from_rotation_y(-0.15 * PI)),
|
||||
..default()
|
||||
|
|
|
@ -40,14 +40,16 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
// Spawn the scene as a child of this entity at the given transform
|
||||
commands.spawn(SceneBundle {
|
||||
transform: Transform::from_xyz(-1.0, 0.0, 0.0),
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
..default()
|
||||
});
|
||||
|
||||
// Spawn a second scene, and add a tag component to be able to target it later
|
||||
commands.spawn((
|
||||
SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
..default()
|
||||
},
|
||||
MovedScene,
|
||||
|
|
|
@ -104,14 +104,18 @@ fn setup(
|
|||
|
||||
commands
|
||||
.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
|
||||
..default()
|
||||
})
|
||||
.insert(MainModel::HighPoly);
|
||||
|
||||
commands
|
||||
.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmetLowPoly/FlightHelmetLowPoly.gltf#Scene0"),
|
||||
scene: asset_server.load(
|
||||
GltfAssetLabel::Scene(0)
|
||||
.from_asset("models/FlightHelmetLowPoly/FlightHelmetLowPoly.gltf"),
|
||||
),
|
||||
..default()
|
||||
})
|
||||
.insert(MainModel::LowPoly);
|
||||
|
|
|
@ -29,7 +29,10 @@ fn main() {
|
|||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
// Spawn the glTF scene.
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/VolumetricFogExample/VolumetricFogExample.glb#Scene0"),
|
||||
scene: asset_server.load(
|
||||
GltfAssetLabel::Scene(0)
|
||||
.from_asset("models/VolumetricFogExample/VolumetricFogExample.glb"),
|
||||
),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -41,9 +41,9 @@ fn setup(
|
|||
let animations = graph
|
||||
.add_clips(
|
||||
[
|
||||
"models/animated/Fox.glb#Animation2",
|
||||
"models/animated/Fox.glb#Animation1",
|
||||
"models/animated/Fox.glb#Animation0",
|
||||
GltfAssetLabel::Animation(2).from_asset("models/animated/Fox.glb"),
|
||||
GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb"),
|
||||
GltfAssetLabel::Animation(0).from_asset("models/animated/Fox.glb"),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|path| asset_server.load(path)),
|
||||
|
@ -91,7 +91,7 @@ fn setup(
|
|||
|
||||
// Fox
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
|
||||
scene: asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
|
||||
..default()
|
||||
});
|
||||
|
||||
|
|
|
@ -160,17 +160,17 @@ fn setup_assets_programmatically(
|
|||
let mut animation_graph = AnimationGraph::new();
|
||||
let blend_node = animation_graph.add_blend(0.5, animation_graph.root);
|
||||
animation_graph.add_clip(
|
||||
asset_server.load("models/animated/Fox.glb#Animation0"),
|
||||
asset_server.load(GltfAssetLabel::Animation(0).from_asset("models/animated/Fox.glb")),
|
||||
1.0,
|
||||
animation_graph.root,
|
||||
);
|
||||
animation_graph.add_clip(
|
||||
asset_server.load("models/animated/Fox.glb#Animation1"),
|
||||
asset_server.load(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb")),
|
||||
1.0,
|
||||
blend_node,
|
||||
);
|
||||
animation_graph.add_clip(
|
||||
asset_server.load("models/animated/Fox.glb#Animation2"),
|
||||
asset_server.load(GltfAssetLabel::Animation(2).from_asset("models/animated/Fox.glb")),
|
||||
1.0,
|
||||
blend_node,
|
||||
);
|
||||
|
@ -236,7 +236,7 @@ fn setup_scene(
|
|||
});
|
||||
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
|
||||
scene: asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
|
||||
transform: Transform::from_scale(Vec3::splat(0.07)),
|
||||
..default()
|
||||
});
|
||||
|
|
|
@ -27,7 +27,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
|
||||
// Spawn the first scene in `models/SimpleSkin/SimpleSkin.gltf`
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/SimpleSkin/SimpleSkin.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/SimpleSkin/SimpleSkin.gltf")),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
|
|
@ -36,11 +36,19 @@ struct MorphData {
|
|||
|
||||
fn setup(asset_server: Res<AssetServer>, mut commands: Commands) {
|
||||
commands.insert_resource(MorphData {
|
||||
the_wave: asset_server.load("models/animated/MorphStressTest.gltf#Animation2"),
|
||||
mesh: asset_server.load("models/animated/MorphStressTest.gltf#Mesh0/Primitive0"),
|
||||
the_wave: asset_server
|
||||
.load(GltfAssetLabel::Animation(2).from_asset("models/animated/MorphStressTest.gltf")),
|
||||
mesh: asset_server.load(
|
||||
GltfAssetLabel::Primitive {
|
||||
mesh: 0,
|
||||
primitive: 0,
|
||||
}
|
||||
.from_asset("models/animated/MorphStressTest.gltf"),
|
||||
),
|
||||
});
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/animated/MorphStressTest.gltf#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/animated/MorphStressTest.gltf")),
|
||||
..default()
|
||||
});
|
||||
commands.spawn(DirectionalLightBundle {
|
||||
|
|
|
@ -16,15 +16,27 @@ fn setup(
|
|||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
// By default AssetServer will load assets from inside the "assets" folder.
|
||||
// For example, the next line will load "ROOT/assets/models/cube/cube.gltf#Mesh0/Primitive0",
|
||||
// For example, the next line will load GltfAssetLabel::Primitive{mesh:0,primitive:0}.from_asset("ROOT/assets/models/cube/cube.gltf"),
|
||||
// where "ROOT" is the directory of the Application.
|
||||
//
|
||||
// This can be overridden by setting the "CARGO_MANIFEST_DIR" environment variable (see
|
||||
// https://doc.rust-lang.org/cargo/reference/environment-variables.html)
|
||||
// to another directory. When the Application is run through Cargo, "CARGO_MANIFEST_DIR" is
|
||||
// automatically set to your crate (workspace) root directory.
|
||||
let cube_handle = asset_server.load("models/cube/cube.gltf#Mesh0/Primitive0");
|
||||
let sphere_handle = asset_server.load("models/sphere/sphere.gltf#Mesh0/Primitive0");
|
||||
let cube_handle = asset_server.load(
|
||||
GltfAssetLabel::Primitive {
|
||||
mesh: 0,
|
||||
primitive: 0,
|
||||
}
|
||||
.from_asset("models/cube/cube.gltf"),
|
||||
);
|
||||
let sphere_handle = asset_server.load(
|
||||
GltfAssetLabel::Primitive {
|
||||
mesh: 0,
|
||||
primitive: 0,
|
||||
}
|
||||
.from_asset("models/sphere/sphere.gltf"),
|
||||
);
|
||||
|
||||
// All assets end up in their Assets<T> collection once they are done loading:
|
||||
if let Some(sphere) = meshes.get(&sphere_handle) {
|
||||
|
@ -49,7 +61,13 @@ fn setup(
|
|||
// It will _not_ be loaded a second time.
|
||||
// The LoadedFolder asset will ultimately also hold handles to the assets, but waiting for it to load
|
||||
// and finding the right handle is more work!
|
||||
let torus_handle = asset_server.load("models/torus/torus.gltf#Mesh0/Primitive0");
|
||||
let torus_handle = asset_server.load(
|
||||
GltfAssetLabel::Primitive {
|
||||
mesh: 0,
|
||||
primitive: 0,
|
||||
}
|
||||
.from_asset("models/torus/torus.gltf"),
|
||||
);
|
||||
|
||||
// You can also add assets directly to their Assets<T> storage:
|
||||
let material_handle = materials.add(StandardMaterial {
|
||||
|
|
|
@ -16,7 +16,8 @@ fn main() {
|
|||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
// Load our mesh:
|
||||
let scene_handle = asset_server.load("models/torus/torus.gltf#Scene0");
|
||||
let scene_handle =
|
||||
asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/torus/torus.gltf"));
|
||||
|
||||
// Any changes to the mesh will be reloaded automatically! Try making a change to torus.gltf.
|
||||
// You should see the changes immediately show up in your app.
|
||||
|
|
|
@ -133,7 +133,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
});
|
||||
|
||||
// spawn the game board
|
||||
let cell_scene = asset_server.load("models/AlienCake/tile.glb#Scene0");
|
||||
let cell_scene =
|
||||
asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/AlienCake/tile.glb"));
|
||||
game.board = (0..BOARD_SIZE_J)
|
||||
.map(|j| {
|
||||
(0..BOARD_SIZE_I)
|
||||
|
@ -163,14 +164,16 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
rotation: Quat::from_rotation_y(-PI / 2.),
|
||||
..default()
|
||||
},
|
||||
scene: asset_server.load("models/AlienCake/alien.glb#Scene0"),
|
||||
scene: asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/AlienCake/alien.glb")),
|
||||
..default()
|
||||
})
|
||||
.id(),
|
||||
);
|
||||
|
||||
// load the scene for the cake
|
||||
game.bonus.handle = asset_server.load("models/AlienCake/cakeBirthday.glb#Scene0");
|
||||
game.bonus.handle =
|
||||
asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/AlienCake/cakeBirthday.glb"));
|
||||
|
||||
// scoreboard
|
||||
commands.spawn(
|
||||
|
|
|
@ -150,7 +150,7 @@ fn load_level_1(
|
|||
));
|
||||
|
||||
// Save the asset into the `loading_assets` vector.
|
||||
let fox = asset_server.load("models/animated/Fox.glb#Scene0");
|
||||
let fox = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb"));
|
||||
loading_data.loading_assets.push(fox.clone().into());
|
||||
// Spawn the fox.
|
||||
commands.spawn((
|
||||
|
@ -192,7 +192,8 @@ fn load_level_2(
|
|||
));
|
||||
|
||||
// Spawn the helmet.
|
||||
let helmet_scene = asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0");
|
||||
let helmet_scene = asset_server
|
||||
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"));
|
||||
loading_data
|
||||
.loading_assets
|
||||
.push(helmet_scene.clone().into());
|
||||
|
|
|
@ -118,9 +118,9 @@ fn setup(
|
|||
|
||||
// Insert a resource with the current scene information
|
||||
let animation_clips = [
|
||||
asset_server.load("models/animated/Fox.glb#Animation2"),
|
||||
asset_server.load("models/animated/Fox.glb#Animation1"),
|
||||
asset_server.load("models/animated/Fox.glb#Animation0"),
|
||||
asset_server.load(GltfAssetLabel::Animation(2).from_asset("models/animated/Fox.glb")),
|
||||
asset_server.load(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb")),
|
||||
asset_server.load(GltfAssetLabel::Animation(0).from_asset("models/animated/Fox.glb")),
|
||||
];
|
||||
let mut animation_graph = AnimationGraph::new();
|
||||
let node_indices = animation_graph
|
||||
|
@ -136,7 +136,8 @@ fn setup(
|
|||
// The foxes in each ring are spaced at least 2m apart around its circumference.'
|
||||
|
||||
// NOTE: This fox model faces +z
|
||||
let fox_handle = asset_server.load("models/animated/Fox.glb#Scene0");
|
||||
let fox_handle =
|
||||
asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb"));
|
||||
|
||||
let ring_directions = [
|
||||
(
|
||||
|
|
|
@ -13,7 +13,7 @@ fn main() {
|
|||
fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
// add entities to the world
|
||||
commands.spawn(SceneBundle {
|
||||
scene: asset_server.load("models/torus/torus.gltf#Scene0"),
|
||||
scene: asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/torus/torus.gltf")),
|
||||
..default()
|
||||
});
|
||||
// light
|
||||
|
|
Loading…
Reference in a new issue