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

Code before:
}

/// Options for converting scenes and assets from glTF's [standard coordinate system](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units)
/// (+Z forward) to Bevy's coordinate system (-Z forward).
///
/// The exact coordinate system conversion is as follows:
/// - glTF:
///   - forward: +Z
///   - up: +Y
///   - right: -X
/// - Bevy:
///   - forward: -Z
///   - up: +Y
///   - right: +X
///
/// 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 `scenes` option. If you also want `Mesh`
/// assets to be converted, enable the `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 via the transform of the scene entity.
    ///
    /// 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 scenes: 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 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))

Review comment (bug):
It seems to me like the big downside of this new approach is that local transforms within a scene (that correspond to nodes) will now no longer have "correct" forward directions. This relies on nesting the scene underneath a top level entity that is "uncorrected", which we use to call "forward" on. Trying to do that _within_ the scene will not produce the expected "forward" behavior.

This is likely to be problematic in the world of BSN "scene inheritance", where rather than spawning the gltf scene root underneath a higher level "bevy scene root", we would instead treat the gltf scene root as the root, and write our changes directly on top. I believe this is the better model when compared to the current "add another root on top" approach, as it allows developers to think about and interact with GLTF scenes exactly as if they were bevy scenes (ex: if the root node has a property, then when we inherit from it, we can directly read/write that property on the root).

I believe this will also come into play if developers try to animate the root transform of the scene, which will snap our corrections back to whatever the animation thinks is correct.

The benefit of course is that the scene is "locally consistent". But within that space, everything is still "uncorrected". If a "player" node exists inside a larger GLTF "world" scene, that player scene's forward will be wrong. 

Code after:
}

/// Options for converting scenes and assets from glTF's [standard coordinate system](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units)
/// (+Z forward) to Bevy's coordinate system (-Z forward).
///
/// The exact coordinate system conversion is as follows:
/// - glTF:
///   - forward: +Z
///   - up: +Y
///   - right: -X
/// - Bevy:
///   - forward: -Z
///   - up: +Y
///   - right: +X
///
/// 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));