Repository: bevyengine/bevy
File: crates/bevy_gltf/src/convert_coordinates.rs (Rust)

Code before:
///
/// Note that some glTF files may not follow the glTF standard.
///
/// If your glTF scene is +Z forward and you want it converted to match Bevy's
/// `Transform::forward`, enable the `rotate_scene_entity` option. If you also want `Mesh`
/// assets to be converted, enable the `rotate_meshes` option.
///
/// Cameras and lights in glTF files are an exception - they already use Bevy's
/// coordinate system. This means cameras and lights will match
/// `Transform::forward` even if conversion is disabled.
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
pub struct GltfConvertCoordinates {
    /// If true, convert scenes by rotating the top-level transform of the scene entity.
    ///
    /// This will ensure that [`Transform::forward`] of the "root" entity (the one with [`SceneInstance`](bevy_scene::SceneInstance))
    /// aligns with the "forward" of the glTF scene.
    ///
    /// The glTF loader creates an entity for each glTF scene. Entities are
    /// then created for each node within the glTF scene. Nodes without a
    /// parent in the glTF scene become children of the scene entity.
    ///
    /// This option only changes the transform of the scene entity. It does not
    /// directly change the transforms of node entities - it only changes them
    /// indirectly through transform inheritance.
    pub rotate_scene_entity: bool,

    /// If true, convert mesh assets. This includes skinned mesh bind poses.
    ///
    /// This option only changes mesh assets and the transforms of entities that
    /// instance meshes. It does not change the transforms of entities that
    /// correspond to glTF nodes.
    pub rotate_meshes: bool,
}

impl GltfConvertCoordinates {
    const CONVERSION_TRANSFORM: Transform =
        Transform::from_rotation(Quat::from_xyzw(0.0, 1.0, 0.0, 0.0));

    fn conversion_mat4() -> Mat4 {
        Mat4::from_scale(Vec3::new(-1.0, 1.0, -1.0))
    }

    pub(crate) fn scene_conversion_transform(&self) -> Transform {
        if self.rotate_scene_entity {
            Self::CONVERSION_TRANSFORM
        } else {
            Transform::IDENTITY
        }
    }

    pub(crate) fn mesh_conversion_transform(&self) -> Transform {

Review comment (suggestion):
* Every entity is created by the glTF loader, not just the "scene entity"
* `SceneInstance` and `SceneRoot` are not part of a scene. If you spawn a scene using the `SceneSpawner` you will not have a `SceneInstance` *or* a `SceneRoot`.

Here's an alternative:


> Bevy's glTF loader creates an Entity for each glTF Scene to contain the glTF Scene's nodes. This Scene Entity's children are the entities created from the top-level nodes in the glTF Scene definition. Each node can also continue to have its own child nodes. The Scene Entity that was created to contain the glTF Scene's nodes is the one that becomes rotated.
>
> If you use `SceneRoot` to spawn the entire scene as a child, that means the Entity with the `SceneRoot` is parent of the full set of Scene nodes described in the previous paragraph, including the Scene Entity. The child Entity of the SceneRoot is the one that is rotated according to the previous paragraph.

Code after:
///   - forward: -Z
///   - up: +Y
///   - right: +X
///
/// Cameras and lights are an exception - they already use Bevy's coordinate
/// system. This means cameras and lights will match Bevy's forward even if
/// conversion is disabled.
///
/// If a glTF file uses the standard coordinate system, then the conversion
/// options will behave like so:
///
/// - `rotate_scene_entity` will make the glTF's scene forward align with the [`Transform::forward`]
///   of the entity with the [`SceneInstance`](bevy_scene::SceneInstance) component.
/// - `rotate_meshes` will do the same for entities with a `Mesh3d` component.
///
/// Other entities in the scene are not converted, so their forward may not
/// match `Transform::forward`. In particular, the entities that correspond to
/// glTF nodes are not converted.
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
pub struct GltfConvertCoordinates {
    /// If true, convert scenes by rotating the top-level transform of the scene entity.
    /// This will ensure that [`Transform::forward`] of the "root" entity (the one with [`SceneInstance`](bevy_scene::SceneInstance))
    /// aligns with the "forward" of the glTF scene.
    ///
    /// The scene entity is created by the glTF loader. Its parent is the entity
    /// with the `SceneInstance` component, and its children are the root nodes
    /// of the glTF scene.
    ///
    /// This option only changes the transform of the scene entity. It does not
    /// directly change the transforms of node entities - it only changes them
    /// indirectly through transform inheritance.
    pub rotate_scene_entity: bool,

    /// If true, convert mesh assets and skinned mesh bind poses.
    ///
    /// This option only changes mesh assets and the transforms of entities that
    /// instance meshes through [`Mesh3d`](bevy_mesh::Mesh3d).
    pub rotate_meshes: bool,
}

impl GltfConvertCoordinates {
    const CONVERSION_TRANSFORM: Transform =
        Transform::from_rotation(Quat::from_xyzw(0.0, 1.0, 0.0, 0.0));

    fn conversion_mat4() -> Mat4 {
        Mat4::from_scale(Vec3::new(-1.0, 1.0, -1.0))
    }

    pub(crate) fn scene_conversion_transform(&self) -> Transform {
        if self.rotate_scene_entity {
            Self::CONVERSION_TRANSFORM