[go: up one dir, main page]

gltf/
material.rs

1use crate::{texture, Document};
2
3pub use json::material::AlphaMode;
4#[cfg(feature = "extensions")]
5use serde_json::{Map, Value};
6
7lazy_static! {
8    static ref DEFAULT_MATERIAL: json::material::Material = Default::default();
9}
10
11/// The material appearance of a primitive.
12#[derive(Clone, Debug)]
13pub struct Material<'a> {
14    /// The parent `Document` struct.
15    document: &'a Document,
16
17    /// The corresponding JSON index - `None` when the default material.
18    index: Option<usize>,
19
20    /// The corresponding JSON struct.
21    json: &'a json::material::Material,
22}
23
24impl<'a> Material<'a> {
25    /// Constructs a `Material`.
26    pub(crate) fn new(
27        document: &'a Document,
28        index: usize,
29        json: &'a json::material::Material,
30    ) -> Self {
31        Self {
32            document,
33            index: Some(index),
34            json,
35        }
36    }
37
38    /// Constructs the default `Material`.
39    pub(crate) fn default(document: &'a Document) -> Self {
40        Self {
41            document,
42            index: None,
43            json: &DEFAULT_MATERIAL,
44        }
45    }
46
47    /// Returns the internal JSON index if this `Material` was explicity defined.
48    ///
49    /// This function returns `None` if the `Material` is the default material.
50    pub fn index(&self) -> Option<usize> {
51        self.index
52    }
53
54    ///  The optional alpha cutoff value of the material.
55    pub fn alpha_cutoff(&self) -> Option<f32> {
56        self.json.alpha_cutoff.map(|value| value.0)
57    }
58
59    /// The alpha rendering mode of the material.  The material's alpha rendering
60    /// mode enumeration specifying the interpretation of the alpha value of the main
61    /// factor and texture.
62    ///
63    /// * In `Opaque` mode (default) the alpha value is ignored
64    ///   and the rendered output is fully opaque.
65    /// * In `Mask` mode, the rendered
66    ///   output is either fully opaque or fully transparent depending on the alpha
67    ///   value and the specified alpha cutoff value.
68    /// * In `Blend` mode, the alpha value is used to composite the source and
69    ///   destination areas and the rendered output is combined with the background
70    ///   using the normal painting operation (i.e. the Porter and Duff over
71    ///   operator).
72    pub fn alpha_mode(&self) -> AlphaMode {
73        self.json.alpha_mode.unwrap()
74    }
75
76    /// Specifies whether the material is double-sided.
77    ///
78    /// * When this value is false, back-face culling is enabled.
79    /// * When this value is true, back-face culling is disabled and double sided
80    ///   lighting is enabled.  The back-face must have its normals reversed before
81    ///   the lighting equation is evaluated.
82    pub fn double_sided(&self) -> bool {
83        self.json.double_sided
84    }
85
86    /// Optional user-defined name for this object.
87    #[cfg(feature = "names")]
88    #[cfg_attr(docsrs, doc(cfg(feature = "names")))]
89    pub fn name(&self) -> Option<&'a str> {
90        self.json.name.as_deref()
91    }
92
93    /// Parameter values that define the metallic-roughness material model from
94    /// Physically-Based Rendering (PBR) methodology.
95    pub fn pbr_metallic_roughness(&self) -> PbrMetallicRoughness<'a> {
96        PbrMetallicRoughness::new(self.document, &self.json.pbr_metallic_roughness)
97    }
98
99    /// Returns extension data unknown to this crate version.
100    #[cfg(feature = "extensions")]
101    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
102    pub fn extensions(&self) -> Option<&Map<String, Value>> {
103        let ext = self.json.extensions.as_ref()?;
104        Some(&ext.others)
105    }
106
107    /// Get the value of an extension based on the name of the extension
108    #[cfg(feature = "extensions")]
109    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
110    pub fn extension_value(&self, key: &str) -> Option<&Value> {
111        let ext = self.json.extensions.as_ref()?;
112        ext.others.get(key)
113    }
114
115    /// Parameter values that define the specular-glossiness material model from
116    /// Physically-Based Rendering (PBR) methodology.
117    #[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
118    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
119    pub fn pbr_specular_glossiness(&self) -> Option<PbrSpecularGlossiness<'a>> {
120        self.json
121            .extensions
122            .as_ref()?
123            .pbr_specular_glossiness
124            .as_ref()
125            .map(|x| PbrSpecularGlossiness::new(self.document, x))
126    }
127
128    /// Parameter values that define the transmission of light through the material
129    #[cfg(feature = "KHR_materials_transmission")]
130    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
131    pub fn transmission(&self) -> Option<Transmission<'a>> {
132        self.json
133            .extensions
134            .as_ref()?
135            .transmission
136            .as_ref()
137            .map(|x| Transmission::new(self.document, x))
138    }
139
140    /// Parameter values that define the index of refraction of the material
141    #[cfg(feature = "KHR_materials_ior")]
142    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_ior")))]
143    pub fn ior(&self) -> Option<f32> {
144        self.json.extensions.as_ref()?.ior.as_ref().map(|x| x.ior.0)
145    }
146
147    /// Parameter value that adjusts the strength of emissive material properties
148    #[cfg(feature = "KHR_materials_emissive_strength")]
149    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_emissive_strength")))]
150    pub fn emissive_strength(&self) -> Option<f32> {
151        self.json
152            .extensions
153            .as_ref()?
154            .emissive_strength
155            .as_ref()
156            .map(|x| x.emissive_strength.0)
157    }
158
159    /// Parameter values that define a volume for the transmission of light through the material
160    #[cfg(feature = "KHR_materials_volume")]
161    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
162    pub fn volume(&self) -> Option<Volume<'a>> {
163        self.json
164            .extensions
165            .as_ref()?
166            .volume
167            .as_ref()
168            .map(|x| Volume::new(self.document, x))
169    }
170
171    /// Parameter values that define the strength and colour of the specular reflection of the material
172    #[cfg(feature = "KHR_materials_specular")]
173    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
174    pub fn specular(&self) -> Option<Specular<'a>> {
175        self.json
176            .extensions
177            .as_ref()?
178            .specular
179            .as_ref()
180            .map(|x| Specular::new(self.document, x))
181    }
182
183    /// A tangent space normal map.
184    ///
185    /// The texture contains RGB components in linear space. Each texel represents
186    /// the XYZ components of a normal vector in tangent space.
187    ///
188    /// * Red [0 to 255] maps to X [-1 to 1].
189    /// * Green [0 to 255] maps to Y [-1 to 1].
190    /// * Blue [128 to 255] maps to Z [1/255 to 1].
191    ///
192    /// The normal vectors use OpenGL conventions where +X is right, +Y is up, and
193    /// +Z points toward the viewer.
194    pub fn normal_texture(&self) -> Option<NormalTexture<'a>> {
195        self.json.normal_texture.as_ref().map(|json| {
196            let texture = self.document.textures().nth(json.index.value()).unwrap();
197            NormalTexture::new(texture, json)
198        })
199    }
200
201    /// The occlusion map texture.
202    ///
203    /// The occlusion values are sampled from the R channel. Higher values indicate
204    /// areas that should receive full indirect lighting and lower values indicate
205    /// no indirect lighting. These values are linear.
206    ///
207    /// If other channels are present (GBA), they are ignored for occlusion
208    /// calculations.
209    pub fn occlusion_texture(&self) -> Option<OcclusionTexture<'a>> {
210        self.json.occlusion_texture.as_ref().map(|json| {
211            let texture = self.document.textures().nth(json.index.value()).unwrap();
212            OcclusionTexture::new(texture, json)
213        })
214    }
215
216    /// The emissive map texture.
217    ///
218    /// The emissive map controls the color and intensity of the light being
219    /// emitted by the material.
220    ///
221    /// This texture contains RGB components in sRGB color space. If a fourth
222    /// component (A) is present, it is ignored.
223    pub fn emissive_texture(&self) -> Option<texture::Info<'a>> {
224        self.json.emissive_texture.as_ref().map(|json| {
225            let texture = self.document.textures().nth(json.index.value()).unwrap();
226            texture::Info::new(texture, json)
227        })
228    }
229
230    /// The emissive color of the material.
231    ///
232    /// The default value is `[0.0, 0.0, 0.0]`.
233    pub fn emissive_factor(&self) -> [f32; 3] {
234        self.json.emissive_factor.0
235    }
236
237    /// Specifies whether the material is unlit.
238    ///
239    /// Returns `true` if the [`KHR_materials_unlit`] property was specified, in which
240    /// case the renderer should prefer to ignore all PBR values except `baseColor`.
241    ///
242    /// [`KHR_materials_unlit`]: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit#overview
243    #[cfg(feature = "KHR_materials_unlit")]
244    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_unlit")))]
245    pub fn unlit(&self) -> bool {
246        self.json
247            .extensions
248            .as_ref()
249            .map_or(false, |extensions| extensions.unlit.is_some())
250    }
251
252    /// Optional application specific data.
253    pub fn extras(&self) -> &'a json::Extras {
254        &self.json.extras
255    }
256}
257
258/// A set of parameter values that are used to define the metallic-roughness
259/// material model from Physically-Based Rendering (PBR) methodology.
260pub struct PbrMetallicRoughness<'a> {
261    /// The parent `Document` struct.
262    document: &'a Document,
263
264    /// The corresponding JSON struct.
265    json: &'a json::material::PbrMetallicRoughness,
266}
267
268impl<'a> PbrMetallicRoughness<'a> {
269    /// Constructs `PbrMetallicRoughness`.
270    pub(crate) fn new(
271        document: &'a Document,
272        json: &'a json::material::PbrMetallicRoughness,
273    ) -> Self {
274        Self { document, json }
275    }
276
277    /// Returns the material's base color factor.
278    ///
279    /// The default value is `[1.0, 1.0, 1.0, 1.0]`.
280    pub fn base_color_factor(&self) -> [f32; 4] {
281        self.json.base_color_factor.0
282    }
283
284    /// Returns the base color texture. The texture contains RGB(A) components
285    /// in sRGB color space.
286    pub fn base_color_texture(&self) -> Option<texture::Info<'a>> {
287        self.json.base_color_texture.as_ref().map(|json| {
288            let texture = self.document.textures().nth(json.index.value()).unwrap();
289            texture::Info::new(texture, json)
290        })
291    }
292
293    /// Returns the metalness factor of the material.
294    ///
295    /// The default value is `1.0`.
296    pub fn metallic_factor(&self) -> f32 {
297        self.json.metallic_factor.0
298    }
299
300    /// Returns the roughness factor of the material.
301    ///
302    /// * A value of 1.0 means the material is completely rough.
303    /// * A value of 0.0 means the material is completely smooth.
304    ///
305    /// The default value is `1.0`.
306    pub fn roughness_factor(&self) -> f32 {
307        self.json.roughness_factor.0
308    }
309
310    /// The metallic-roughness texture.
311    ///
312    /// The metalness values are sampled from the B channel.
313    /// The roughness values are sampled from the G channel.
314    /// These values are linear. If other channels are present (R or A),
315    /// they are ignored for metallic-roughness calculations.
316    pub fn metallic_roughness_texture(&self) -> Option<texture::Info<'a>> {
317        self.json.metallic_roughness_texture.as_ref().map(|json| {
318            let texture = self.document.textures().nth(json.index.value()).unwrap();
319            texture::Info::new(texture, json)
320        })
321    }
322
323    /// Returns extension data unknown to this crate version.
324    #[cfg(feature = "extensions")]
325    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
326    pub fn extensions(&self) -> Option<&Map<String, Value>> {
327        let ext = self.json.extensions.as_ref()?;
328        Some(&ext.others)
329    }
330
331    /// Get the value of an extension based on the name of the extension
332    #[cfg(feature = "extensions")]
333    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
334    pub fn extension_value(&self, key: &str) -> Option<&Value> {
335        let ext = self.json.extensions.as_ref()?;
336        ext.others.get(key)
337    }
338
339    /// Optional application specific data.
340    pub fn extras(&self) -> &'a json::Extras {
341        &self.json.extras
342    }
343}
344
345/// A set of parameter values that are used to define the transmissions
346/// factor of the material
347#[cfg(feature = "KHR_materials_transmission")]
348#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
349pub struct Transmission<'a> {
350    /// The parent `Document` struct.
351    document: &'a Document,
352
353    /// The corresponding JSON struct.
354    json: &'a json::extensions::material::Transmission,
355}
356
357#[cfg(feature = "KHR_materials_transmission")]
358#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_transmission")))]
359impl<'a> Transmission<'a> {
360    /// Constructs `Ior`.
361    pub(crate) fn new(
362        document: &'a Document,
363        json: &'a json::extensions::material::Transmission,
364    ) -> Self {
365        Self { document, json }
366    }
367
368    /// Returns the material's transmission factor.
369    ///
370    /// The default value is `0.0`.
371    pub fn transmission_factor(&self) -> f32 {
372        self.json.transmission_factor.0
373    }
374
375    /// Returns the transmission texture.
376    pub fn transmission_texture(&self) -> Option<texture::Info<'a>> {
377        self.json.transmission_texture.as_ref().map(|json| {
378            let texture = self.document.textures().nth(json.index.value()).unwrap();
379            texture::Info::new(texture, json)
380        })
381    }
382
383    /// Optional application specific data.
384    pub fn extras(&self) -> &'a json::Extras {
385        &self.json.extras
386    }
387}
388
389/// Parameter values that define a volume for the transmission of light through the material
390#[cfg(feature = "KHR_materials_volume")]
391#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
392pub struct Volume<'a> {
393    /// The parent `Document` struct.
394    document: &'a Document,
395
396    /// The corresponding JSON struct.
397    json: &'a json::extensions::material::Volume,
398}
399
400#[cfg(feature = "KHR_materials_volume")]
401#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_volume")))]
402impl<'a> Volume<'a> {
403    /// Constructs `Volume`.
404    pub(crate) fn new(
405        document: &'a Document,
406        json: &'a json::extensions::material::Volume,
407    ) -> Self {
408        Self { document, json }
409    }
410
411    /// The thickness of the volume beneath the surface. The value is
412    /// given in the coordinate space of the mesh. If the value is 0
413    /// the material is thin-walled. Otherwise the material is a
414    /// volume boundary. The `doubleSided` property has no effect on
415    /// volume boundaries. Range is [0, +inf).
416    pub fn thickness_factor(&self) -> f32 {
417        self.json.thickness_factor.0
418    }
419
420    /// A texture that defines the thickness, stored in the G channel.
421    /// This will be multiplied by `thickness_factor`. Range is [0, 1].
422    pub fn thickness_texture(&self) -> Option<texture::Info<'a>> {
423        self.json.thickness_texture.as_ref().map(|json| {
424            let texture = self.document.textures().nth(json.index.value()).unwrap();
425            texture::Info::new(texture, json)
426        })
427    }
428
429    /// Density of the medium given as the average distance that light
430    /// travels in the medium before interacting with a particle. The
431    /// value is given in world space. Range is (0, +inf).
432    pub fn attenuation_distance(&self) -> f32 {
433        self.json.attenuation_distance.0
434    }
435
436    /// The color that white light turns into due to absorption when
437    /// reaching the attenuation distance.
438    pub fn attenuation_color(&self) -> [f32; 3] {
439        self.json.attenuation_color.0
440    }
441
442    /// Optional application specific data.
443    pub fn extras(&self) -> &'a json::Extras {
444        &self.json.extras
445    }
446}
447
448/// Parameter values that define the strength and colour of the specular reflection of the material
449#[cfg(feature = "KHR_materials_specular")]
450#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
451pub struct Specular<'a> {
452    /// The parent `Document` struct.
453    document: &'a Document,
454
455    /// The corresponding JSON struct.
456    json: &'a json::extensions::material::Specular,
457}
458
459#[cfg(feature = "KHR_materials_specular")]
460#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_specular")))]
461impl<'a> Specular<'a> {
462    /// Constructs `Volume`.
463    pub(crate) fn new(
464        document: &'a Document,
465        json: &'a json::extensions::material::Specular,
466    ) -> Self {
467        Self { document, json }
468    }
469
470    /// The strength of the specular reflection.
471    pub fn specular_factor(&self) -> f32 {
472        self.json.specular_factor.0
473    }
474
475    /// A texture that defines the strength of the specular reflection,
476    /// stored in the alpha (`A`) channel. This will be multiplied by
477    /// `specular_factor`.
478    pub fn specular_texture(&self) -> Option<texture::Info<'a>> {
479        self.json.specular_texture.as_ref().map(|json| {
480            let texture = self.document.textures().nth(json.index.value()).unwrap();
481            texture::Info::new(texture, json)
482        })
483    }
484
485    /// The F0 color of the specular reflection (linear RGB).
486    pub fn specular_color_factor(&self) -> [f32; 3] {
487        self.json.specular_color_factor.0
488    }
489
490    /// A texture that defines the F0 color of the specular reflection,
491    /// stored in the `RGB` channels and encoded in sRGB. This texture
492    /// will be multiplied by `specular_color_factor`.
493    pub fn specular_color_texture(&self) -> Option<texture::Info<'a>> {
494        self.json.specular_color_texture.as_ref().map(|json| {
495            let texture = self.document.textures().nth(json.index.value()).unwrap();
496            texture::Info::new(texture, json)
497        })
498    }
499
500    /// Optional application specific data.
501    pub fn extras(&self) -> &'a json::Extras {
502        &self.json.extras
503    }
504}
505
506/// A set of parameter values that are used to define the specular-glossiness
507/// material model from Physically-Based Rendering (PBR) methodology.
508#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
509#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
510pub struct PbrSpecularGlossiness<'a> {
511    /// The parent `Document` struct.
512    document: &'a Document,
513
514    /// The corresponding JSON struct.
515    json: &'a json::extensions::material::PbrSpecularGlossiness,
516}
517
518#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
519#[cfg_attr(docsrs, doc(cfg(feature = "KHR_materials_pbrSpecularGlossiness")))]
520impl<'a> PbrSpecularGlossiness<'a> {
521    /// Constructs `PbrSpecularGlossiness`.
522    pub(crate) fn new(
523        document: &'a Document,
524        json: &'a json::extensions::material::PbrSpecularGlossiness,
525    ) -> Self {
526        Self { document, json }
527    }
528
529    /// Returns the material's base color factor.
530    ///
531    /// The default value is `[1.0, 1.0, 1.0, 1.0]`.
532    pub fn diffuse_factor(&self) -> [f32; 4] {
533        self.json.diffuse_factor.0
534    }
535
536    /// Returns the base color texture.
537    pub fn diffuse_texture(&self) -> Option<texture::Info<'a>> {
538        self.json.diffuse_texture.as_ref().map(|json| {
539            let texture = self.document.textures().nth(json.index.value()).unwrap();
540            texture::Info::new(texture, json)
541        })
542    }
543
544    /// Returns the specular factor of the material.
545    ///
546    /// The default value is `[1.0, 1.0, 1.0]`.
547    pub fn specular_factor(&self) -> [f32; 3] {
548        self.json.specular_factor.0
549    }
550
551    /// Returns the glossiness factor of the material.
552    ///
553    /// A value of 1.0 means the material has full glossiness or is perfectly
554    /// smooth. A value of 0.0 means the material has no glossiness or is
555    /// completely rough. This value is linear.
556    ///
557    /// The default value is `1.0`.
558    pub fn glossiness_factor(&self) -> f32 {
559        self.json.glossiness_factor.0
560    }
561
562    /// The specular-glossiness texture.
563    ///
564    /// A RGBA texture, containing the specular color of the material (RGB
565    /// components) and its glossiness (A component). The color values are in
566    /// sRGB space.
567    pub fn specular_glossiness_texture(&self) -> Option<texture::Info<'a>> {
568        self.json.specular_glossiness_texture.as_ref().map(|json| {
569            let texture = self.document.textures().nth(json.index.value()).unwrap();
570            texture::Info::new(texture, json)
571        })
572    }
573
574    /// Optional application specific data.
575    pub fn extras(&self) -> &'a json::Extras {
576        &self.json.extras
577    }
578}
579
580/// Defines the normal texture of a material.
581pub struct NormalTexture<'a> {
582    /// The parent `Texture` struct.
583    texture: texture::Texture<'a>,
584
585    /// The corresponding JSON struct.
586    json: &'a json::material::NormalTexture,
587}
588
589impl<'a> NormalTexture<'a> {
590    /// Constructs a `NormalTexture`.
591    pub(crate) fn new(
592        texture: texture::Texture<'a>,
593        json: &'a json::material::NormalTexture,
594    ) -> Self {
595        Self { texture, json }
596    }
597
598    /// Returns the scalar multiplier applied to each normal vector of the texture.
599    pub fn scale(&self) -> f32 {
600        self.json.scale
601    }
602
603    /// The set index of the texture's `TEXCOORD` attribute.
604    pub fn tex_coord(&self) -> u32 {
605        self.json.tex_coord
606    }
607
608    /// Returns the referenced texture.
609    pub fn texture(&self) -> texture::Texture<'a> {
610        self.texture.clone()
611    }
612
613    /// Returns extension data unknown to this crate version.
614    #[cfg(feature = "extensions")]
615    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
616    pub fn extensions(&self) -> Option<&Map<String, Value>> {
617        let ext = self.json.extensions.as_ref()?;
618        Some(&ext.others)
619    }
620
621    /// Get the value of an extension based on the name of the extension
622    #[cfg(feature = "extensions")]
623    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
624    pub fn extension_value(&self, key: &str) -> Option<&Value> {
625        let ext = self.json.extensions.as_ref()?;
626        ext.others.get(key)
627    }
628
629    /// Optional application specific data.
630    pub fn extras(&self) -> &'a json::Extras {
631        &self.json.extras
632    }
633}
634
635/// Defines the occlusion texture of a material.
636pub struct OcclusionTexture<'a> {
637    /// The parent `Texture` struct.
638    texture: texture::Texture<'a>,
639
640    /// The corresponding JSON struct.
641    json: &'a json::material::OcclusionTexture,
642}
643
644impl<'a> OcclusionTexture<'a> {
645    /// Constructs a `OcclusionTexture`.
646    pub(crate) fn new(
647        texture: texture::Texture<'a>,
648        json: &'a json::material::OcclusionTexture,
649    ) -> Self {
650        Self { texture, json }
651    }
652
653    /// Returns the scalar multiplier controlling the amount of occlusion applied.
654    pub fn strength(&self) -> f32 {
655        self.json.strength.0
656    }
657
658    /// Returns the set index of the texture's `TEXCOORD` attribute.
659    pub fn tex_coord(&self) -> u32 {
660        self.json.tex_coord
661    }
662
663    /// Returns the referenced texture.
664    pub fn texture(&self) -> texture::Texture<'a> {
665        self.texture.clone()
666    }
667
668    /// Returns extension data unknown to this crate version.
669    #[cfg(feature = "extensions")]
670    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
671    pub fn extensions(&self) -> Option<&Map<String, Value>> {
672        let ext = self.json.extensions.as_ref()?;
673        Some(&ext.others)
674    }
675
676    /// Get the value of an extension based on the name of the extension
677    #[cfg(feature = "extensions")]
678    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
679    pub fn extension_value(&self, key: &str) -> Option<&Value> {
680        let ext = self.json.extensions.as_ref()?;
681        ext.others.get(key)
682    }
683
684    /// Optional application specific data.
685    pub fn extras(&self) -> &'a json::Extras {
686        &self.json.extras
687    }
688}
689
690impl<'a> AsRef<texture::Texture<'a>> for NormalTexture<'a> {
691    fn as_ref(&self) -> &texture::Texture<'a> {
692        &self.texture
693    }
694}
695
696impl<'a> AsRef<texture::Texture<'a>> for OcclusionTexture<'a> {
697    fn as_ref(&self) -> &texture::Texture<'a> {
698        &self.texture
699    }
700}