Skip to content

Conversation

rendaoer
Copy link
Contributor

Objective

Fixes #19286

Solution

Use material name for mesh entity's Name when available

Testing

Test code, modified from examples/load_gltf.rs

//! Loads and renders a glTF file as a scene.

use bevy::{gltf::GltfMaterialName, prelude::*, scene::SceneInstanceReady};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_observer(on_scene_load)
        .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 {
        shadows_enabled: true,
        ..default()
    },));

    commands.spawn(SceneRoot(asset_server.load(
        GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"),
    )));
}

fn on_scene_load(
    trigger: Trigger<SceneInstanceReady>,
    children: Query<&Children>,
    names: Query<&Name>,
    material_names: Query<&GltfMaterialName>,
) {
    let target = trigger.target();

    for child in children.iter_descendants(target) {
        let name = if let Ok(name) = names.get(child) {
            Some(name.to_string())
        } else {
            None
        };
        let material_name = if let Ok(name) = material_names.get(child) {
            Some(name.0.clone())
        } else {
            None
        };

        info!("Entity name:{:?} | material name:{:?}", name, material_name);
    }
}

Showcase

Run log:
Image

@greeble-dev greeble-dev added C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward A-glTF Related to the glTF 3D scene/model format M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide labels May 19, 2025
Copy link
Contributor

It looks like your PR is a breaking change, but you didn't provide a migration guide.

Please review the instructions for writing migration guides, then expand or revise the content in the migration guides directory to reflect your changes.

@greeble-dev
Copy link
Contributor

I've tagged this as M-Needs-Migration-Guide in case a user might have been relying on the old naming behaviour to find the entity. Which seems like a really niche case, but not impossible.

@alice-i-cecile alice-i-cecile added X-Contentious There are nontrivial implications that should be thought through and removed X-Contentious There are nontrivial implications that should be thought through labels May 19, 2025
Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL that we're spawning the materials as their own entities 🤔 Given that, this is reasonable behavior. Migration guide needs a bit of an editing pass; I'll do my best to fix it in suggestions.

@alice-i-cecile
Copy link
Member

I would also prefer if we had some sort of marker like GltfMaterial or something, and removed GltfMaterialName entirely, in favor of a joint query. That's a larger change though: this is a fine start.

@greeble-dev
Copy link
Contributor

TIL that we're spawning the materials as their own entities 🤔

This might be a misunderstanding? At least there's no entity that contains a material on its own. The entity named in this PR corresponds to a gltTF primitive, so it contains Mesh3d and MeshMaterial3d components. glTF primitives don't have names, but assigning them the material name does seem fairly intuitive for debugging.

This situation is always going to be a bit confusing because the Bevy notion of "mesh" doesn't match glTF's. I suspect a longer term improvement is to have a distinct GltfMeshName component, which could be more controversial. I might look into that as a potential follow up.

@rendaoer
Copy link
Contributor Author

When generating gltf in bevy, each material will have its own entity, and different mesh parts only belong to this material entity. According to the current situation, I think it is reasonable to display the material name. I think this might improve once we have our own editor, maybe in the bevy editor gltf will have its own display?

@greeble-dev
Copy link
Contributor

greeble-dev commented May 20, 2025

I'd agree that displaying the material name in inspectors is reasonable, particularly when a mesh has multiple materials. But after looking at this some more I think it's likely to break users who are using the name to find entities in code. But maybe that can be fixed by adding some more data.

Say there's a glTF that has a node named "fox", which has a mesh named "fox_mesh", which is a single primitive with a material named "fox_material". That gets turned into two entities:

  • (Name: "fox", Transform) <-- glTF node.
    • (Name: "fox_mesh", Transform, Mesh3d, MeshMaterial3d) <-- glTF primitive.

Before this PR the primitive entity would have been named "fox_mesh". After this PR, it will be named "fox_material". There won't be anything named "fox_mesh".

I don't think there's a simple and intuitive solution to this as Bevy's entity structure just doesn't match the glTF hierarchy.

The least worst solution might be to add a new component to the primitive entity:

struct GltfPrimitiveComponent {
    mesh_name: String,
    index: usize
}

That way this PR can stay the same - the Name component can still change to be the material name. But the migration guide is "if you were searching for the mesh by Name::name, instead search for GltfPrimitiveComponent::mesh_name".

If this PR lands as-is then I can do a follow up PR to pitch adding GltfPrimitiveComponent.

@greeble-dev
Copy link
Contributor

After digging a bit more I think struct GltfMeshName(String) is better than GltfPrimitiveComponent. Is a little unintuitive that the GltfMeshName will be duplicated across multiple primitives, but might be the least worst solution.

Related: #13473, which has some more background and originally pitched GltfMeshName.

@rendaoer
Copy link
Contributor Author

I think the name can be changed to MeshName.MaterialName

@rendaoer
Copy link
Contributor Author

I also need to test the results in different situations

@greeble-dev
Copy link
Contributor

MeshName.MaterialName makes sense to me as an inspection friendly name.

@greeble-dev
Copy link
Contributor

greeble-dev commented May 20, 2025

Could also consider MeshName.MaterialName if a mesh has multiple primitives, and MeshName if it only has a single primitive. That keeps some backwards compatibility.

Use both mesh name and material name in the entity name component instead
of just using material name or primitive index. This makes entities more
identifiable in inspector tools with format "MeshName.MaterialName".
@rendaoer
Copy link
Contributor Author

If there is no material, it will keep MeshName. If there is a material, it will still use MeshName.MaterialName

@rendaoer
Copy link
Contributor Author

Thanks for your review, showing MeshName.MaterialName is definitely a better choice than just showing MaterialName

Copy link
Contributor

@greeble-dev greeble-dev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me once the markdown passes CI.

I'll look into following up with a PR that adds GltfMeshName. This will affect the migration guide as users should probably prefer that component - Name would be just for debugging/inspection.

@rendaoer
Copy link
Contributor Author

I think the usage rate of GltfMeshName should not be very high. Users usually don't modify Mesh, but the probability of modifying Material is still quite high. Usually there is no need to check the name of Mesh, because there is only one Mesh name in Gltf. Even if you want to modify Mesh, you have to look for it according to the name of GltfMaterialName.

@greeble-dev
Copy link
Contributor

My guess is that some users with single primitive meshes will have been using the mesh name to find the material. While they could switch to using GltfMaterialName, adding a distinct mesh name would make upgrading easier for them.

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 20, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue May 20, 2025
Merged via the queue into bevyengine:main with commit c62ca1a May 20, 2025
34 checks passed
@rendaoer
Copy link
Contributor Author

My guess is that some users with single primitive meshes will have been using the mesh name to find the material. While they could switch to using GltfMaterialName, adding a distinct mesh name would make upgrading easier for them.

Side effects appeared haha, now I think what you said makes a lot of sense, I decided to add GltfMeshNam

github-merge-queue bot pushed a commit that referenced this pull request May 23, 2025
Stores mesh names from glTF files in GltfMeshName component rather than
Name component, making both GltfMeshName and GltfMaterialName behave
like strings via Deref.

# Objective

Fixed the side effects of #19287
Fixes Examples that modify gltf materials are broken #19322

## Solution

Add GltfMeshName component and Deref implementations

Stores mesh names from glTF files in GltfMeshName component rather than
Name component, making both GltfMeshName and GltfMaterialName behave
like strings via Deref.


## Testing

cargo run --example depth_of_field
cargo run --example lightmaps
cargo run --example mixed_lighting
They are consistent with the situation before the error occurred.

---------

Co-authored-by: Alice Cecile <[email protected]>
Co-authored-by: Rob Parrett <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-glTF Related to the glTF 3D scene/model format C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Straightforward Simple bug fixes and API improvements, docs, test and examples M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Why not let GltfMaterialName display as Name?
3 participants