mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 05:33:04 +00:00
add handling of all missing gltf extras: scene, mesh & materials (#13453)
# Objective - fixes #4823 ## Solution As outlined in the discussion in the linked issue as the best current solution, this PR adds specific GltfExtras for - scenes - meshes - materials - As it is , it is not a breaking change, I hesitated to rename the current "GltfExtras" component to "PrimitiveGltfExtras", but that would result in a breaking change and might be a bit confusing as to what "primitive" that refers to. ## Testing - I included a bare-bones example & asset (exported gltf file from Blender) with gltf extras at all the relevant levels : scene, mesh, material --- ## Changelog - adds "SceneGltfExtras" injected at the scene level if any - adds "MeshGltfExtras", injected at the mesh level if any - adds "MaterialGltfExtras", injected at the mesh level if any: ie if a mesh has a material that has gltf extras, the component will be injected there.
This commit is contained in:
parent
061bee7e3c
commit
d26900a9ea
6 changed files with 171 additions and 4 deletions
11
Cargo.toml
11
Cargo.toml
|
@ -802,6 +802,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"
|
||||
|
|
BIN
assets/models/extras/gltf_extras.glb
Normal file
BIN
assets/models/extras/gltf_extras.glb
Normal file
Binary file not shown.
|
@ -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>()
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
|
|
@ -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::{
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
|
97
examples/3d/load_gltf_extras.rs
Normal file
97
examples/3d/load_gltf_extras.rs
Normal file
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue