Skip to main content

gltf/
material.rs

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