Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add handling of all missing gltf extras: scene, mesh & materials #13453

Merged
merged 12 commits into from
Jun 3, 2024
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,17 @@ description = "Loads and renders a glTF file as a scene"
category = "3D Rendering"
wasm = true

[[example]]
name = "load_gltf_extras"
path = "examples/3d/load_gltf_extras.rs"
doc-scrape-examples = true

[package.metadata.example.load_gltf_extras]
name = "Load glTF extras"
description = "Loads and renders a glTF file as a scene, including the gltf extras"
category = "3D Rendering"
wasm = true

[[example]]
name = "motion_blur"
path = "examples/3d/motion_blur.rs"
Expand Down
Binary file added assets/models/extras/gltf_extras.glb
Binary file not shown.
35 changes: 34 additions & 1 deletion crates/bevy_gltf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ impl GltfPlugin {
impl Plugin for GltfPlugin {
fn build(&self, app: &mut App) {
app.register_type::<GltfExtras>()
.register_type::<GltfSceneExtras>()
.register_type::<GltfMeshExtras>()
.register_type::<GltfMaterialExtras>()
.init_asset::<Gltf>()
.init_asset::<GltfNode>()
.init_asset::<GltfPrimitive>()
Expand Down Expand Up @@ -239,7 +242,7 @@ pub struct GltfPrimitive {
pub material_extras: Option<GltfExtras>,
}

/// Additional untyped data that can be present on most glTF types.
/// Additional untyped data that can be present on most glTF types at the primitive level.
///
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
#[derive(Clone, Debug, Reflect, Default, Component)]
Expand All @@ -249,6 +252,36 @@ pub struct GltfExtras {
pub value: String,
}

/// Additional untyped data that can be present on most glTF types at the scene level.
///
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component)]
pub struct GltfSceneExtras {
/// Content of the extra data.
pub value: String,
}

/// Additional untyped data that can be present on most glTF types at the mesh level.
///
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component)]
pub struct GltfMeshExtras {
/// Content of the extra data.
pub value: String,
}

/// Additional untyped data that can be present on most glTF types at the material level.
///
/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
#[derive(Clone, Debug, Reflect, Default, Component)]
#[reflect(Component)]
pub struct GltfMaterialExtras {
/// 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
Expand Down
31 changes: 28 additions & 3 deletions crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::GltfAssetLabel;
use crate::{vertex_attributes::convert_attribute, Gltf, GltfExtras, GltfNode};
use crate::{
vertex_attributes::convert_attribute, Gltf, GltfAssetLabel, GltfExtras, GltfMaterialExtras,
GltfMeshExtras, GltfNode, GltfSceneExtras,
};

#[cfg(feature = "bevy_animation")]
use bevy_animation::{AnimationTarget, AnimationTargetId};
use bevy_asset::{
Expand Down Expand Up @@ -634,7 +637,8 @@ async fn load_gltf<'a, 'b, 'c>(
let mut node_index_to_entity_map = HashMap::new();
let mut entity_to_skin_index_map = EntityHashMap::default();
let mut scene_load_context = load_context.begin_labeled_asset();
world

let world_root_id = world
.spawn(SpatialBundle::INHERITED_IDENTITY)
.with_children(|parent| {
for node in scene.nodes() {
Expand All @@ -659,7 +663,15 @@ async fn load_gltf<'a, 'b, 'c>(
return;
}
}
})
.id();

if let Some(extras) = scene.extras().as_ref() {
world.entity_mut(world_root_id).insert(GltfSceneExtras {
value: extras.get().to_string(),
});
}

if let Some(Err(err)) = err {
return Err(err);
}
Expand Down Expand Up @@ -1270,6 +1282,7 @@ fn load_node(
material: load_context.get_label_handle(&material_label),
..Default::default()
});

let target_count = primitive.morph_targets().len();
if target_count != 0 {
let weights = match mesh.weights() {
Expand Down Expand Up @@ -1300,6 +1313,18 @@ fn load_node(
});
}

if let Some(extras) = mesh.extras() {
mesh_entity.insert(GltfMeshExtras {
value: extras.get().to_string(),
});
}

if let Some(extras) = material.extras() {
mesh_entity.insert(GltfMaterialExtras {
value: extras.get().to_string(),
});
}

mesh_entity.insert(Name::new(primitive_name(&mesh, &primitive)));
// Mark for adding skinned mesh
if let Some(skin) = gltf_node.skin() {
Expand Down
97 changes: 97 additions & 0 deletions examples/3d/load_gltf_extras.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//! Loads and renders a glTF file as a scene, and list all the different `gltf_extras`.

use bevy::{
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
prelude::*,
};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, check_for_gltf_extras)
.run();
}

#[derive(Component)]
struct ExampleDisplay;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(2.0, 2.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});

commands.spawn(DirectionalLightBundle {
directional_light: DirectionalLight {
shadows_enabled: true,
..default()
},
..default()
});
// a barebones scene containing one of each gltf_extra type
commands.spawn(SceneBundle {
scene: asset_server.load("models/extras/gltf_extras.glb#Scene0"),
..default()
});

// a place to display the extras on screen
commands.spawn((
TextBundle::from_section(
"",
TextStyle {
font_size: 18.,
..default()
},
)
.with_style(Style {
position_type: PositionType::Absolute,
top: Val::Px(12.0),
left: Val::Px(12.0),
..default()
}),
ExampleDisplay,
));
}

fn check_for_gltf_extras(
gltf_extras_per_entity: Query<(
Entity,
Option<&Name>,
Option<&GltfSceneExtras>,
Option<&GltfExtras>,
Option<&GltfMeshExtras>,
Option<&GltfMaterialExtras>,
)>,
mut display: Query<&mut Text, With<ExampleDisplay>>,
) {
let mut gltf_extra_infos_lines: Vec<String> = vec![];

for (id, name, scene_extras, extras, mesh_extras, material_extras) in
gltf_extras_per_entity.iter()
{
if scene_extras.is_some()
|| extras.is_some()
|| mesh_extras.is_some()
|| material_extras.is_some()
{
let formatted_extras = format!(
"Extras per entity {} ('Name: {}'):
- scene extras: {:?}
- primitive extras: {:?}
- mesh extras: {:?}
- material extras: {:?}
",
id,
name.unwrap_or(&Name::default()),
scene_extras,
extras,
mesh_extras,
material_extras
);
gltf_extra_infos_lines.push(formatted_extras);
}
let mut display = display.single_mut();
display.sections[0].value = gltf_extra_infos_lines.join("\n");
}
}
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ Example | Description
[Lightmaps](../examples/3d/lightmaps.rs) | Rendering a scene with baked lightmaps
[Lines](../examples/3d/lines.rs) | Create a custom material to draw 3d lines
[Load glTF](../examples/3d/load_gltf.rs) | Loads and renders a glTF file as a scene
[Load glTF extras](../examples/3d/load_gltf_extras.rs) | Loads and renders a glTF file as a scene, including the gltf extras
[Meshlet](../examples/3d/meshlet.rs) | Meshlet rendering for dense high-poly scenes (experimental)
[Motion Blur](../examples/3d/motion_blur.rs) | Demonstrates per-pixel motion blur
[Orthographic View](../examples/3d/orthographic.rs) | Shows how to create a 3D orthographic view (for isometric-look in games or CAD applications)
Expand Down