mesh_tools/
models.rs

1//! # glTF Data Model Definitions
2//!
3//! This module contains the core data structures that represent a glTF 2.0 document.
4//! These structures match the JSON schema defined in the [glTF 2.0 specification](https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html).
5//!
6//! The structures in this module are designed to be serialized to JSON using serde,
7//! with optional fields that are skipped when None to produce valid glTF JSON.
8
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12/// Represents a complete glTF 2.0 document
13///
14/// A glTF document contains all the resources and metadata needed to represent a 3D scene or model.
15/// It includes scenes, nodes, meshes, materials, textures, and binary data references.
16#[derive(Serialize, Deserialize, Debug, Default)]
17pub struct Gltf {
18    pub asset: Asset,
19    
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub scene: Option<usize>,
22    
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub scenes: Option<Vec<Scene>>,
25    
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub nodes: Option<Vec<Node>>,
28    
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub meshes: Option<Vec<Mesh>>,
31    
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub accessors: Option<Vec<Accessor>>,
34    
35    #[serde(skip_serializing_if = "Option::is_none")]
36    #[serde(rename = "bufferViews")]
37    pub buffer_views: Option<Vec<BufferView>>,
38    
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub buffers: Option<Vec<Buffer>>,
41    
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub materials: Option<Vec<Material>>,
44    
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub textures: Option<Vec<Texture>>,
47    
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub images: Option<Vec<Image>>,
50    
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub samplers: Option<Vec<Sampler>>,
53    
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub animations: Option<Vec<Animation>>,
56    
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub extensions: Option<serde_json::Value>,
59    
60    #[serde(skip_serializing_if = "Option::is_none")]
61    #[serde(rename = "extensionsUsed")]
62    pub extensions_used: Option<Vec<String>>,
63    
64    #[serde(skip_serializing_if = "Option::is_none")]
65    #[serde(rename = "extensionsRequired")]
66    pub extensions_required: Option<Vec<String>>,
67    
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub extras: Option<HashMap<String, serde_json::Value>>,
70}
71
72/// Represents the glTF asset information
73#[derive(Serialize, Deserialize, Debug, Default)]
74pub struct Asset {
75    pub version: String,
76    
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub generator: Option<String>,
79    
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub copyright: Option<String>,
82}
83
84/// Represents a glTF scene
85#[derive(Serialize, Deserialize, Debug, Default)]
86pub struct Scene {
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub name: Option<String>,
89    
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub nodes: Option<Vec<usize>>,
92}
93
94/// Represents a glTF node
95#[derive(Serialize, Deserialize, Debug, Default)]
96pub struct Node {
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub name: Option<String>,
99    
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub mesh: Option<usize>,
102    
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub translation: Option<[f32; 3]>,
105    
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub rotation: Option<[f32; 4]>,
108    
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub scale: Option<[f32; 3]>,
111    
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub matrix: Option<[f32; 16]>,
114    
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub children: Option<Vec<usize>>,
117}
118
119/// Represents a glTF mesh
120#[derive(Serialize, Deserialize, Debug, Default)]
121pub struct Mesh {
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub name: Option<String>,
124    
125    pub primitives: Vec<Primitive>,
126}
127
128/// Represents a glTF mesh primitive
129#[derive(Serialize, Deserialize, Debug, Default)]
130pub struct Primitive {
131    pub attributes: HashMap<String, usize>,
132    
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub indices: Option<usize>,
135    
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub material: Option<usize>,
138    
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub mode: Option<usize>,
141}
142
143/// Represents a glTF accessor
144#[derive(Serialize, Deserialize, Debug)]
145pub struct Accessor {
146    #[serde(rename = "bufferView")]
147    pub buffer_view: usize,
148    #[serde(rename = "componentType")]
149    pub component_type: usize,
150    pub count: usize,
151    #[serde(rename = "type")]
152    pub type_: String,
153    
154    #[serde(skip_serializing_if = "Option::is_none")]
155    #[serde(rename = "byteOffset")]
156    pub byte_offset: Option<usize>,
157    
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub min: Option<Vec<f32>>,
160    
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub max: Option<Vec<f32>>,
163    
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub normalized: Option<bool>,
166}
167
168/// Represents a glTF buffer view
169#[derive(Serialize, Deserialize, Debug)]
170pub struct BufferView {
171    pub buffer: usize,
172    #[serde(rename = "byteOffset")]
173    pub byte_offset: usize,
174    #[serde(rename = "byteLength")]
175    pub byte_length: usize,
176    
177    #[serde(skip_serializing_if = "Option::is_none")]
178    #[serde(rename = "byteStride")]
179    pub byte_stride: Option<usize>,
180    
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub target: Option<usize>,
183}
184
185/// Represents a glTF buffer
186#[derive(Serialize, Deserialize, Debug)]
187pub struct Buffer {
188    #[serde(rename = "byteLength")]
189    pub byte_length: usize,
190    
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub uri: Option<String>,
193}
194
195/// Represents a glTF material
196#[derive(Serialize, Deserialize, Debug, Default)]
197pub struct Material {
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub name: Option<String>,
200    
201    #[serde(skip_serializing_if = "Option::is_none")]
202    #[serde(rename = "pbrMetallicRoughness")]
203    pub pbr_metallic_roughness: Option<PbrMetallicRoughness>,
204    
205    #[serde(skip_serializing_if = "Option::is_none")]
206    #[serde(rename = "normalTexture")]
207    pub normal_texture: Option<NormalTextureInfo>,
208    
209    #[serde(skip_serializing_if = "Option::is_none")]
210    #[serde(rename = "occlusionTexture")]
211    pub occlusion_texture: Option<OcclusionTextureInfo>,
212    
213    #[serde(skip_serializing_if = "Option::is_none")]
214    #[serde(rename = "emissiveTexture")]
215    pub emissive_texture: Option<TextureInfo>,
216    
217    #[serde(skip_serializing_if = "Option::is_none")]
218    #[serde(rename = "emissiveFactor")]
219    pub emissive_factor: Option<[f32; 3]>,
220    
221    #[serde(skip_serializing_if = "Option::is_none")]
222    #[serde(rename = "alphaMode")]
223    pub alpha_mode: Option<String>,
224    
225    #[serde(skip_serializing_if = "Option::is_none")]
226    #[serde(rename = "alphaCutoff")]
227    pub alpha_cutoff: Option<f32>,
228    
229    #[serde(skip_serializing_if = "Option::is_none")]
230    #[serde(rename = "doubleSided")]
231    pub double_sided: Option<bool>,
232    
233    #[serde(skip_serializing_if = "Option::is_none")]
234    pub extensions: Option<MaterialExtensions>,
235}
236
237/// Represents a glTF PBR material
238#[derive(Serialize, Deserialize, Debug, Default)]
239pub struct PbrMetallicRoughness {
240    #[serde(skip_serializing_if = "Option::is_none")]
241    #[serde(rename = "baseColorFactor")]
242    pub base_color_factor: Option<[f32; 4]>,
243    
244    #[serde(skip_serializing_if = "Option::is_none")]
245    #[serde(rename = "baseColorTexture")]
246    pub base_color_texture: Option<TextureInfo>,
247    
248    #[serde(skip_serializing_if = "Option::is_none")]
249    #[serde(rename = "metallicFactor")]
250    pub metallic_factor: Option<f32>,
251    
252    #[serde(skip_serializing_if = "Option::is_none")]
253    #[serde(rename = "roughnessFactor")]
254    pub roughness_factor: Option<f32>,
255    
256    #[serde(skip_serializing_if = "Option::is_none")]
257    #[serde(rename = "metallicRoughnessTexture")]
258    pub metallic_roughness_texture: Option<TextureInfo>,
259}
260
261/// Represents basic texture reference information
262#[derive(Serialize, Deserialize, Debug, Default)]
263pub struct TextureInfo {
264    pub index: usize,
265    
266    #[serde(skip_serializing_if = "Option::is_none")]
267    #[serde(rename = "texCoord")]
268    pub tex_coord: Option<usize>,
269}
270
271/// Represents normal texture reference information
272#[derive(Serialize, Deserialize, Debug, Default)]
273pub struct NormalTextureInfo {
274    pub index: usize,
275    
276    #[serde(skip_serializing_if = "Option::is_none")]
277    #[serde(rename = "texCoord")]
278    pub tex_coord: Option<usize>,
279    
280    #[serde(skip_serializing_if = "Option::is_none")]
281    pub scale: Option<f32>,
282}
283
284/// Represents occlusion texture reference information
285#[derive(Serialize, Deserialize, Debug, Default)]
286pub struct OcclusionTextureInfo {
287    pub index: usize,
288    
289    #[serde(skip_serializing_if = "Option::is_none")]
290    #[serde(rename = "texCoord")]
291    pub tex_coord: Option<usize>,
292    
293    #[serde(skip_serializing_if = "Option::is_none")]
294    pub strength: Option<f32>,
295}
296
297/// Represents a glTF texture
298#[derive(Serialize, Deserialize, Debug)]
299pub struct Texture {
300    #[serde(skip_serializing_if = "Option::is_none")]
301    pub name: Option<String>,
302    
303    pub source: usize,
304    
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub sampler: Option<usize>,
307}
308
309/// Represents a glTF image
310#[derive(Serialize, Deserialize, Debug)]
311pub struct Image {
312    #[serde(skip_serializing_if = "Option::is_none")]
313    pub name: Option<String>,
314    
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub uri: Option<String>,
317    
318    #[serde(skip_serializing_if = "Option::is_none")]
319    #[serde(rename = "mimeType")]
320    pub mime_type: Option<String>,
321    
322    #[serde(skip_serializing_if = "Option::is_none")]
323    #[serde(rename = "bufferView")]
324    pub buffer_view: Option<usize>,
325}
326
327/// Represents a glTF sampler
328#[derive(Serialize, Deserialize, Debug, Default)]
329pub struct Sampler {
330    #[serde(skip_serializing_if = "Option::is_none")]
331    #[serde(rename = "magFilter")]
332    pub mag_filter: Option<usize>,
333    
334    #[serde(skip_serializing_if = "Option::is_none")]
335    #[serde(rename = "minFilter")]
336    pub min_filter: Option<usize>,
337    
338    #[serde(skip_serializing_if = "Option::is_none")]
339    #[serde(rename = "wrapS")]
340    pub wrap_s: Option<usize>,
341    
342    #[serde(skip_serializing_if = "Option::is_none")]
343    #[serde(rename = "wrapT")]
344    pub wrap_t: Option<usize>,
345}
346
347/// Represents a glTF animation
348#[derive(Serialize, Deserialize, Debug, Default)]
349pub struct Animation {
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub name: Option<String>,
352    
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub channels: Option<Vec<AnimationChannel>>,
355    
356    #[serde(skip_serializing_if = "Option::is_none")]
357    pub samplers: Option<Vec<AnimationSampler>>
358}
359
360/// Represents a glTF animation channel
361#[derive(Serialize, Deserialize, Debug, Default)]
362pub struct AnimationChannel {
363    pub sampler: usize,
364    
365    pub target: AnimationChannelTarget
366}
367
368/// Represents a glTF animation channel target
369#[derive(Serialize, Deserialize, Debug, Default)]
370pub struct AnimationChannelTarget {
371    pub node: usize,
372    
373    pub path: String
374}
375
376/// Represents a glTF animation sampler
377#[derive(Serialize, Deserialize, Debug, Default)]
378pub struct AnimationSampler {
379    pub input: usize,
380    
381    #[serde(skip_serializing_if = "Option::is_none")]
382    pub interpolation: Option<String>,
383    
384    pub output: usize
385}
386
387/// Represents material extensions for glTF
388#[derive(Serialize, Deserialize, Debug, Default)]
389pub struct MaterialExtensions {
390    #[serde(skip_serializing_if = "Option::is_none")]
391    #[serde(rename = "KHR_materials_pbrSpecularGlossiness")]
392    pub pbr_specular_glossiness: Option<PbrSpecularGlossiness>,
393}
394
395/// Represents a glTF specular-glossiness PBR material extension
396#[derive(Serialize, Deserialize, Debug, Default)]
397pub struct PbrSpecularGlossiness {
398    #[serde(skip_serializing_if = "Option::is_none")]
399    #[serde(rename = "diffuseFactor")]
400    pub diffuse_factor: Option<[f32; 4]>,
401    
402    #[serde(skip_serializing_if = "Option::is_none")]
403    #[serde(rename = "diffuseTexture")]
404    pub diffuse_texture: Option<TextureInfo>,
405    
406    #[serde(skip_serializing_if = "Option::is_none")]
407    #[serde(rename = "specularFactor")]
408    pub specular_factor: Option<[f32; 3]>,
409    
410    #[serde(skip_serializing_if = "Option::is_none")]
411    #[serde(rename = "glossinessFactor")]
412    pub glossiness_factor: Option<f32>,
413    
414    #[serde(skip_serializing_if = "Option::is_none")]
415    #[serde(rename = "specularGlossinessTexture")]
416    pub specular_glossiness_texture: Option<TextureInfo>,
417}