Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gltf/src/loader/gltf_ext/scene.rs
6598 views
1
use bevy_ecs::name::Name;
2
use bevy_math::{Mat4, Vec3};
3
use bevy_transform::components::Transform;
4
5
use gltf::scene::Node;
6
7
use fixedbitset::FixedBitSet;
8
use itertools::Itertools;
9
10
#[cfg(feature = "bevy_animation")]
11
use bevy_platform::collections::{HashMap, HashSet};
12
13
use crate::{
14
convert_coordinates::{ConvertCameraCoordinates as _, ConvertCoordinates as _},
15
GltfError,
16
};
17
18
pub(crate) fn node_name(node: &Node) -> Name {
19
let name = node
20
.name()
21
.map(ToString::to_string)
22
.unwrap_or_else(|| format!("GltfNode{}", node.index()));
23
Name::new(name)
24
}
25
26
/// Calculate the transform of gLTF [`Node`].
27
///
28
/// This should be used instead of calling [`gltf::scene::Transform::matrix()`]
29
/// on [`Node::transform()`](gltf::Node::transform) directly because it uses optimized glam types and
30
/// if `libm` feature of `bevy_math` crate is enabled also handles cross
31
/// platform determinism properly.
32
pub(crate) fn node_transform(node: &Node, convert_coordinates: bool) -> Transform {
33
let transform = match node.transform() {
34
gltf::scene::Transform::Matrix { matrix } => {
35
Transform::from_matrix(Mat4::from_cols_array_2d(&matrix))
36
}
37
gltf::scene::Transform::Decomposed {
38
translation,
39
rotation,
40
scale,
41
} => Transform {
42
translation: Vec3::from(translation),
43
rotation: bevy_math::Quat::from_array(rotation),
44
scale: Vec3::from(scale),
45
},
46
};
47
if convert_coordinates {
48
if node.camera().is_some() || node.light().is_some() {
49
transform.convert_camera_coordinates()
50
} else {
51
transform.convert_coordinates()
52
}
53
} else {
54
transform
55
}
56
}
57
58
#[cfg_attr(
59
not(target_arch = "wasm32"),
60
expect(
61
clippy::result_large_err,
62
reason = "need to be signature compatible with `load_gltf`"
63
)
64
)]
65
/// Check if [`Node`] is part of cycle
66
pub(crate) fn check_is_part_of_cycle(
67
node: &Node,
68
visited: &mut FixedBitSet,
69
) -> Result<(), GltfError> {
70
// Do we have a cycle?
71
if visited.contains(node.index()) {
72
return Err(GltfError::CircularChildren(format!(
73
"glTF nodes form a cycle: {} -> {}",
74
visited.ones().map(|bit| bit.to_string()).join(" -> "),
75
node.index()
76
)));
77
}
78
79
// Recurse.
80
visited.insert(node.index());
81
for kid in node.children() {
82
check_is_part_of_cycle(&kid, visited)?;
83
}
84
visited.remove(node.index());
85
86
Ok(())
87
}
88
89
#[cfg(feature = "bevy_animation")]
90
pub(crate) fn collect_path(
91
node: &Node,
92
current_path: &[Name],
93
paths: &mut HashMap<usize, (usize, Vec<Name>)>,
94
root_index: usize,
95
visited: &mut HashSet<usize>,
96
) {
97
let mut path = current_path.to_owned();
98
path.push(node_name(node));
99
visited.insert(node.index());
100
for child in node.children() {
101
if !visited.contains(&child.index()) {
102
collect_path(&child, &path, paths, root_index, visited);
103
}
104
}
105
paths.insert(node.index(), (root_index, path));
106
}
107
108