Skip to main content

bevy_gltf/
assets.rs

1//! Representation of assets present in a glTF file
2
3use core::ops::Deref;
4
5#[cfg(feature = "bevy_animation")]
6use bevy_animation::AnimationClip;
7use bevy_asset::{Asset, Handle};
8use bevy_ecs::{component::Component, reflect::ReflectComponent};
9use bevy_mesh::{skinning::SkinnedMeshInverseBindposes, Mesh};
10use bevy_pbr::StandardMaterial;
11use bevy_platform::collections::HashMap;
12use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
13use bevy_scene::Scene;
14
15use crate::GltfAssetLabel;
16
17/// Representation of a loaded glTF file.
18#[derive(Asset, Debug, TypePath)]
19pub struct Gltf {
20    /// All scenes loaded from the glTF file.
21    pub scenes: Vec<Handle<Scene>>,
22    /// Named scenes loaded from the glTF file.
23    pub named_scenes: HashMap<Box<str>, Handle<Scene>>,
24    /// All meshes loaded from the glTF file.
25    pub meshes: Vec<Handle<GltfMesh>>,
26    /// Named meshes loaded from the glTF file.
27    pub named_meshes: HashMap<Box<str>, Handle<GltfMesh>>,
28    /// All materials loaded from the glTF file.
29    pub materials: Vec<Handle<StandardMaterial>>,
30    /// Named materials loaded from the glTF file.
31    pub named_materials: HashMap<Box<str>, Handle<StandardMaterial>>,
32    /// All nodes loaded from the glTF file.
33    pub nodes: Vec<Handle<GltfNode>>,
34    /// Named nodes loaded from the glTF file.
35    pub named_nodes: HashMap<Box<str>, Handle<GltfNode>>,
36    /// All skins loaded from the glTF file.
37    pub skins: Vec<Handle<GltfSkin>>,
38    /// Named skins loaded from the glTF file.
39    pub named_skins: HashMap<Box<str>, Handle<GltfSkin>>,
40    /// Default scene to be displayed.
41    pub default_scene: Option<Handle<Scene>>,
42    /// All animations loaded from the glTF file.
43    #[cfg(feature = "bevy_animation")]
44    pub animations: Vec<Handle<AnimationClip>>,
45    /// Named animations loaded from the glTF file.
46    #[cfg(feature = "bevy_animation")]
47    pub named_animations: HashMap<Box<str>, Handle<AnimationClip>>,
48    /// The gltf root of the gltf asset, see <https://docs.rs/gltf/latest/gltf/struct.Gltf.html>. Only has a value when `GltfLoaderSettings::include_source` is true.
49    pub source: Option<gltf::Gltf>,
50}
51
52/// A glTF mesh, which may consist of multiple [`GltfPrimitives`](GltfPrimitive)
53/// and an optional [`GltfExtras`].
54///
55/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh).
56#[derive(Asset, Debug, Clone, TypePath)]
57pub struct GltfMesh {
58    /// Index of the mesh inside the scene
59    pub index: usize,
60    /// Computed name for a mesh - either a user defined mesh name from gLTF or a generated name from index
61    pub name: String,
62    /// Primitives of the glTF mesh.
63    pub primitives: Vec<GltfPrimitive>,
64    /// Additional data.
65    pub extras: Option<GltfExtras>,
66}
67
68impl GltfMesh {
69    /// Create a mesh extracting name and index from glTF def
70    pub fn new(
71        mesh: &gltf::Mesh,
72        primitives: Vec<GltfPrimitive>,
73        extras: Option<GltfExtras>,
74    ) -> Self {
75        Self {
76            index: mesh.index(),
77            name: if let Some(name) = mesh.name() {
78                name.to_string()
79            } else {
80                format!("GltfMesh{}", mesh.index())
81            },
82            primitives,
83            extras,
84        }
85    }
86
87    /// Subasset label for this mesh within the gLTF parent asset.
88    pub fn asset_label(&self) -> GltfAssetLabel {
89        GltfAssetLabel::Mesh(self.index)
90    }
91}
92
93/// A glTF node with all of its child nodes, its [`GltfMesh`],
94/// [`Transform`](bevy_transform::prelude::Transform), its optional [`GltfSkin`]
95/// and an optional [`GltfExtras`].
96///
97/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node).
98#[derive(Asset, Debug, Clone, TypePath)]
99pub struct GltfNode {
100    /// Index of the node inside the scene
101    pub index: usize,
102    /// Computed name for a node - either a user defined node name from gLTF or a generated name from index
103    pub name: String,
104    /// Direct children of the node.
105    pub children: Vec<Handle<GltfNode>>,
106    /// Mesh of the node.
107    pub mesh: Option<Handle<GltfMesh>>,
108    /// Skin of the node.
109    pub skin: Option<Handle<GltfSkin>>,
110    /// Local transform.
111    pub transform: bevy_transform::prelude::Transform,
112    /// Is this node used as an animation root
113    #[cfg(feature = "bevy_animation")]
114    pub is_animation_root: bool,
115    /// Additional data.
116    pub extras: Option<GltfExtras>,
117}
118
119impl GltfNode {
120    /// Create a node extracting name and index from glTF def
121    pub fn new(
122        node: &gltf::Node,
123        children: Vec<Handle<GltfNode>>,
124        mesh: Option<Handle<GltfMesh>>,
125        transform: bevy_transform::prelude::Transform,
126        skin: Option<Handle<GltfSkin>>,
127        extras: Option<GltfExtras>,
128    ) -> Self {
129        Self {
130            index: node.index(),
131            name: if let Some(name) = node.name() {
132                name.to_string()
133            } else {
134                format!("GltfNode{}", node.index())
135            },
136            children,
137            mesh,
138            transform,
139            skin,
140            #[cfg(feature = "bevy_animation")]
141            is_animation_root: false,
142            extras,
143        }
144    }
145
146    /// Create a node with animation root mark
147    #[cfg(feature = "bevy_animation")]
148    pub fn with_animation_root(self, is_animation_root: bool) -> Self {
149        Self {
150            is_animation_root,
151            ..self
152        }
153    }
154
155    /// Subasset label for this node within the gLTF parent asset.
156    pub fn asset_label(&self) -> GltfAssetLabel {
157        GltfAssetLabel::Node(self.index)
158    }
159}
160
161/// Part of a [`GltfMesh`] that consists of a [`Mesh`], an optional [`StandardMaterial`] and [`GltfExtras`].
162///
163/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh-primitive).
164#[derive(Asset, Debug, Clone, TypePath)]
165pub struct GltfPrimitive {
166    /// Index of the primitive inside the mesh
167    pub index: usize,
168    /// Index of the parent [`GltfMesh`] of this primitive
169    pub parent_mesh_index: usize,
170    /// Computed name for a primitive - either a user defined primitive name from gLTF or a generated name from index
171    pub name: String,
172    /// Topology to be rendered.
173    pub mesh: Handle<Mesh>,
174    /// Material to apply to the `mesh`.
175    pub material: Option<Handle<StandardMaterial>>,
176    /// Additional data.
177    pub extras: Option<GltfExtras>,
178    /// Additional data of the `material`.
179    pub material_extras: Option<GltfExtras>,
180}
181
182impl GltfPrimitive {
183    /// Create a primitive extracting name and index from glTF def
184    pub fn new(
185        gltf_mesh: &gltf::Mesh,
186        gltf_primitive: &gltf::Primitive,
187        mesh: Handle<Mesh>,
188        material: Option<Handle<StandardMaterial>>,
189        extras: Option<GltfExtras>,
190        material_extras: Option<GltfExtras>,
191    ) -> Self {
192        GltfPrimitive {
193            index: gltf_primitive.index(),
194            parent_mesh_index: gltf_mesh.index(),
195            name: {
196                let mesh_name = gltf_mesh.name().unwrap_or("Mesh");
197                if gltf_mesh.primitives().len() > 1 {
198                    format!("{}.{}", mesh_name, gltf_primitive.index())
199                } else {
200                    mesh_name.to_string()
201                }
202            },
203            mesh,
204            material,
205            extras,
206            material_extras,
207        }
208    }
209
210    /// Subasset label for this primitive within its parent [`GltfMesh`] within the gLTF parent asset.
211    pub fn asset_label(&self) -> GltfAssetLabel {
212        GltfAssetLabel::Primitive {
213            mesh: self.parent_mesh_index,
214            primitive: self.index,
215        }
216    }
217}
218
219/// A glTF skin with all of its joint nodes, [`SkinnedMeshInversiveBindposes`](bevy_mesh::skinning::SkinnedMeshInverseBindposes)
220/// and an optional [`GltfExtras`].
221///
222/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-skin).
223#[derive(Asset, Debug, Clone, TypePath)]
224pub struct GltfSkin {
225    /// Index of the skin inside the scene
226    pub index: usize,
227    /// Computed name for a skin - either a user defined skin name from gLTF or a generated name from index
228    pub name: String,
229    /// All the nodes that form this skin.
230    pub joints: Vec<Handle<GltfNode>>,
231    /// Inverse-bind matrices of this skin.
232    pub inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
233    /// Additional data.
234    pub extras: Option<GltfExtras>,
235}
236
237impl GltfSkin {
238    /// Create a skin extracting name and index from glTF def
239    pub fn new(
240        skin: &gltf::Skin,
241        joints: Vec<Handle<GltfNode>>,
242        inverse_bind_matrices: Handle<SkinnedMeshInverseBindposes>,
243        extras: Option<GltfExtras>,
244    ) -> Self {
245        Self {
246            index: skin.index(),
247            name: if let Some(name) = skin.name() {
248                name.to_string()
249            } else {
250                format!("GltfSkin{}", skin.index())
251            },
252            joints,
253            inverse_bind_matrices,
254            extras,
255        }
256    }
257
258    /// Subasset label for this skin within the gLTF parent asset.
259    pub fn asset_label(&self) -> GltfAssetLabel {
260        GltfAssetLabel::Skin(self.index)
261    }
262}
263
264/// Additional untyped data that can be present on most glTF types at the primitive level.
265///
266/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
267#[derive(Clone, Debug, Reflect, Default, Component)]
268#[reflect(Component, Clone, Default, Debug)]
269pub struct GltfExtras {
270    /// Content of the extra data.
271    pub value: String,
272}
273
274impl From<&serde_json::value::RawValue> for GltfExtras {
275    fn from(value: &serde_json::value::RawValue) -> Self {
276        GltfExtras {
277            value: value.get().to_string(),
278        }
279    }
280}
281
282/// Additional untyped data that can be present on most glTF types at the scene level.
283///
284/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
285#[derive(Clone, Debug, Reflect, Default, Component)]
286#[reflect(Component, Clone, Default, Debug)]
287pub struct GltfSceneExtras {
288    /// Content of the extra data.
289    pub value: String,
290}
291
292/// Additional untyped data that can be present on most glTF types at the mesh level.
293///
294/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
295#[derive(Clone, Debug, Reflect, Default, Component)]
296#[reflect(Component, Clone, Default, Debug)]
297pub struct GltfMeshExtras {
298    /// Content of the extra data.
299    pub value: String,
300}
301
302/// The mesh name of a glTF primitive.
303///
304/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh).
305#[derive(Clone, Debug, Reflect, Default, Component)]
306#[reflect(Component, Clone)]
307pub struct GltfMeshName(pub String);
308
309impl Deref for GltfMeshName {
310    type Target = str;
311
312    fn deref(&self) -> &Self::Target {
313        self.0.as_ref()
314    }
315}
316
317/// Additional untyped data that can be present on most glTF types at the material level.
318///
319/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-extras).
320#[derive(Clone, Debug, Reflect, Default, Component)]
321#[reflect(Component, Clone, Default, Debug)]
322pub struct GltfMaterialExtras {
323    /// Content of the extra data.
324    pub value: String,
325}
326
327/// The material name of a glTF primitive.
328///
329/// See [the relevant glTF specification section](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material).
330#[derive(Clone, Debug, Reflect, Default, Component)]
331#[reflect(Component, Clone)]
332pub struct GltfMaterialName(pub String);
333
334impl Deref for GltfMaterialName {
335    type Target = str;
336
337    fn deref(&self) -> &Self::Target {
338        self.0.as_ref()
339    }
340}