Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gltf/src/convert_coordinates.rs
9374 views
1
//! Utilities for converting from glTF's [standard coordinate system](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units)
2
//! to Bevy's.
3
use serde::{Deserialize, Serialize};
4
5
use bevy_math::{Mat4, Quat, Vec3};
6
use bevy_transform::components::Transform;
7
8
pub(crate) trait ConvertCoordinates {
9
/// Converts from glTF coordinates to Bevy's coordinate system. See
10
/// [`GltfConvertCoordinates`] for an explanation of the conversion.
11
fn convert_coordinates(self) -> Self;
12
}
13
14
impl ConvertCoordinates for Vec3 {
15
fn convert_coordinates(self) -> Self {
16
Vec3::new(-self.x, self.y, -self.z)
17
}
18
}
19
20
impl ConvertCoordinates for [f32; 3] {
21
fn convert_coordinates(self) -> Self {
22
[-self[0], self[1], -self[2]]
23
}
24
}
25
26
impl ConvertCoordinates for [f32; 4] {
27
fn convert_coordinates(self) -> Self {
28
// Solution of q' = r q r*
29
[-self[0], self[1], -self[2], self[3]]
30
}
31
}
32
33
/// 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)
34
/// (+Z forward) to Bevy's coordinate system (-Z forward).
35
///
36
/// _CAUTION: This is an experimental feature. Behavior may change in future versions._
37
///
38
/// The exact coordinate system conversion is as follows:
39
///
40
/// - glTF:
41
/// - forward: +Z
42
/// - up: +Y
43
/// - right: -X
44
/// - Bevy:
45
/// - forward: -Z
46
/// - up: +Y
47
/// - right: +X
48
///
49
/// Cameras and lights are an exception - they already use Bevy's coordinate
50
/// system. This means cameras and lights will match Bevy's forward even if
51
/// conversion is disabled.
52
///
53
/// If a glTF file uses the standard coordinate system, then the conversion
54
/// options will behave like so:
55
///
56
/// - `rotate_scene_entity` will make the glTF's scene forward align with the [`Transform::forward`]
57
/// of the entity with the [`SceneInstance`](bevy_scene::SceneInstance) component.
58
/// - `rotate_meshes` will do the same for entities with a `Mesh3d` component.
59
///
60
/// Other entities in the scene are not converted, so their forward may not
61
/// match `Transform::forward`. In particular, the entities that correspond to
62
/// glTF nodes are not converted.
63
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
64
pub struct GltfConvertCoordinates {
65
/// If true, convert scenes by rotating the top-level transform of the scene entity.
66
/// This will ensure that [`Transform::forward`] of the "root" entity (the one with [`SceneInstance`](bevy_scene::SceneInstance))
67
/// aligns with the "forward" of the glTF scene.
68
///
69
/// The scene entity is created by the glTF loader. Its parent is the entity
70
/// with the `SceneInstance` component, and its children are the root nodes
71
/// of the glTF scene.
72
///
73
/// This option only changes the transform of the scene entity. It does not
74
/// directly change the transforms of node entities - it only changes them
75
/// indirectly through transform inheritance.
76
pub rotate_scene_entity: bool,
77
78
/// If true, convert mesh assets and skinned mesh bind poses.
79
///
80
/// This option only changes mesh assets and the transforms of entities that
81
/// instance meshes through [`Mesh3d`](bevy_mesh::Mesh3d).
82
pub rotate_meshes: bool,
83
}
84
85
impl GltfConvertCoordinates {
86
const CONVERSION_TRANSFORM: Transform =
87
Transform::from_rotation(Quat::from_xyzw(0.0, 1.0, 0.0, 0.0));
88
89
fn conversion_mat4() -> Mat4 {
90
Mat4::from_scale(Vec3::new(-1.0, 1.0, -1.0))
91
}
92
93
pub(crate) fn scene_conversion_transform(&self) -> Transform {
94
if self.rotate_scene_entity {
95
Self::CONVERSION_TRANSFORM
96
} else {
97
Transform::IDENTITY
98
}
99
}
100
101
pub(crate) fn mesh_conversion_transform(&self) -> Transform {
102
if self.rotate_meshes {
103
Self::CONVERSION_TRANSFORM
104
} else {
105
Transform::IDENTITY
106
}
107
}
108
109
pub(crate) fn mesh_conversion_transform_inverse(&self) -> Transform {
110
// We magically know that the transform is its own inverse. We still
111
// make a distinction at the interface level in case that changes.
112
self.mesh_conversion_transform()
113
}
114
115
pub(crate) fn mesh_conversion_mat4(&self) -> Mat4 {
116
if self.rotate_meshes {
117
Self::conversion_mat4()
118
} else {
119
Mat4::IDENTITY
120
}
121
}
122
}
123
124