gltf_json/
material.rs

1use crate::validation::{Checked, Validate};
2use crate::{extensions, texture, Extras, Index};
3use gltf_derive::Validate;
4use serde::{de, ser};
5use serde_derive::{Deserialize, Serialize};
6use std::fmt;
7
8/// All valid alpha modes.
9pub const VALID_ALPHA_MODES: &[&str] = &["OPAQUE", "MASK", "BLEND"];
10
11/// The alpha rendering mode of a material.
12#[derive(Clone, Copy, Eq, PartialEq, Debug)]
13pub enum AlphaMode {
14    /// The alpha value is ignored and the rendered output is fully opaque.
15    Opaque = 1,
16
17    /// The rendered output is either fully opaque or fully transparent depending on
18    /// the alpha value and the specified alpha cutoff value.
19    Mask,
20
21    /// The alpha value is used, to determine the transparency of the rendered output.
22    /// The alpha cutoff value is ignored.
23    Blend,
24}
25
26impl ser::Serialize for AlphaMode {
27    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28    where
29        S: ser::Serializer,
30    {
31        match *self {
32            AlphaMode::Opaque => serializer.serialize_str("OPAQUE"),
33            AlphaMode::Mask => serializer.serialize_str("MASK"),
34            AlphaMode::Blend => serializer.serialize_str("BLEND"),
35        }
36    }
37}
38
39/// The material appearance of a primitive.
40#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
41#[serde(default)]
42pub struct Material {
43    /// The alpha cutoff value of the material.
44    #[serde(rename = "alphaCutoff")]
45    //#[cfg_attr(feature = "alphaCutoff", serde(skip_serializing_if = "Option::is_none"))]
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub alpha_cutoff: Option<AlphaCutoff>,
48
49    /// The alpha rendering mode of the material.
50    ///
51    /// The material's alpha rendering mode enumeration specifying the
52    /// interpretation of the alpha value of the main factor and texture.
53    ///
54    /// * In `Opaque` mode (default) the alpha value is ignored and the rendered
55    ///   output is fully opaque.
56    ///
57    /// * In `Mask` mode, the rendered output is either fully opaque or fully
58    ///   transparent depending on the alpha value and the specified alpha cutoff
59    ///   value.
60    ///
61    /// * In `Blend` mode, the alpha value is used to composite the source and
62    ///   destination areas and the rendered output is combined with the
63    ///   background using the normal painting operation (i.e. the Porter and
64    ///   Duff over operator).
65    #[serde(rename = "alphaMode")]
66    pub alpha_mode: Checked<AlphaMode>,
67
68    /// Specifies whether the material is double-sided.
69    ///
70    /// * When this value is false, back-face culling is enabled.
71    ///
72    /// * When this value is true, back-face culling is disabled and double sided
73    ///   lighting is enabled.
74    ///
75    /// The back-face must have its normals reversed before the lighting
76    /// equation is evaluated.
77    #[serde(rename = "doubleSided")]
78    pub double_sided: bool,
79
80    /// Optional user-defined name for this object.
81    #[cfg(feature = "names")]
82    #[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
83    pub name: Option<String>,
84
85    /// A set of parameter values that are used to define the metallic-roughness
86    /// material model from Physically-Based Rendering (PBR) methodology. When not
87    /// specified, all the default values of `pbrMetallicRoughness` apply.
88    #[serde(default, rename = "pbrMetallicRoughness")]
89    pub pbr_metallic_roughness: PbrMetallicRoughness,
90
91    /// A tangent space normal map. The texture contains RGB components in linear
92    /// space. Each texel represents the XYZ components of a normal vector in
93    /// tangent space. Red [0 to 255] maps to X [-1 to 1]. Green [0 to 255] maps to
94    /// Y [-1 to 1]. Blue [128 to 255] maps to Z [1/255 to 1]. The normal vectors
95    /// use OpenGL conventions where +X is right and +Y is up. +Z points toward the
96    /// viewer.
97    #[serde(rename = "normalTexture")]
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub normal_texture: Option<NormalTexture>,
100
101    /// The occlusion map texture. The occlusion values are sampled from the R
102    /// channel. Higher values indicate areas that should receive full indirect
103    /// lighting and lower values indicate no indirect lighting. These values are
104    /// linear. If other channels are present (GBA), they are ignored for occlusion
105    /// calculations.
106    #[serde(rename = "occlusionTexture")]
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub occlusion_texture: Option<OcclusionTexture>,
109
110    /// The emissive map controls the color and intensity of the light being emitted
111    /// by the material. This texture contains RGB components in sRGB color space.
112    /// If a fourth component (A) is present, it is ignored.
113    #[serde(rename = "emissiveTexture")]
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub emissive_texture: Option<texture::Info>,
116
117    /// The emissive color of the material.
118    #[serde(rename = "emissiveFactor")]
119    pub emissive_factor: EmissiveFactor,
120
121    /// Extension specific data.
122    #[serde(default, skip_serializing_if = "Option::is_none")]
123    pub extensions: Option<extensions::material::Material>,
124
125    /// Optional application specific data.
126    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
127    #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
128    pub extras: Extras,
129}
130
131/// A set of parameter values that are used to define the metallic-roughness
132/// material model from Physically-Based Rendering (PBR) methodology.
133#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
134#[serde(default)]
135pub struct PbrMetallicRoughness {
136    /// The material's base color factor.
137    #[serde(rename = "baseColorFactor")]
138    pub base_color_factor: PbrBaseColorFactor,
139
140    /// The base color texture.
141    #[serde(rename = "baseColorTexture")]
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub base_color_texture: Option<texture::Info>,
144
145    /// The metalness of the material.
146    #[serde(rename = "metallicFactor")]
147    pub metallic_factor: StrengthFactor,
148
149    /// The roughness of the material.
150    ///
151    /// * A value of 1.0 means the material is completely rough.
152    /// * A value of 0.0 means the material is completely smooth.
153    #[serde(rename = "roughnessFactor")]
154    pub roughness_factor: StrengthFactor,
155
156    /// The metallic-roughness texture.
157    ///
158    /// This texture has two components:
159    ///
160    /// The metalness values are sampled from the B channel.
161    /// The roughness values are sampled from the G channel.
162    /// These values are linear. If other channels are present (R or A),
163    /// they are ignored for metallic-roughness calculations.
164    #[serde(rename = "metallicRoughnessTexture")]
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub metallic_roughness_texture: Option<texture::Info>,
167
168    /// Extension specific data.
169    #[serde(default, skip_serializing_if = "Option::is_none")]
170    pub extensions: Option<extensions::material::PbrMetallicRoughness>,
171
172    /// Optional application specific data.
173    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
174    #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
175    pub extras: Extras,
176}
177
178/// Defines the normal texture of a material.
179#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
180pub struct NormalTexture {
181    /// The index of the texture.
182    pub index: Index<texture::Texture>,
183
184    /// The scalar multiplier applied to each normal vector of the texture.
185    ///
186    /// This value is ignored if normalTexture is not specified.
187    #[serde(default = "material_normal_texture_scale_default")]
188    pub scale: f32,
189
190    /// The set index of the texture's `TEXCOORD` attribute.
191    #[serde(default, rename = "texCoord")]
192    pub tex_coord: u32,
193
194    /// Extension specific data.
195    #[serde(default, skip_serializing_if = "Option::is_none")]
196    pub extensions: Option<extensions::material::NormalTexture>,
197
198    /// Optional application specific data.
199    #[serde(default)]
200    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
201    #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
202    pub extras: Extras,
203}
204
205fn material_normal_texture_scale_default() -> f32 {
206    1.0
207}
208
209/// Defines the occlusion texture of a material.
210#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
211pub struct OcclusionTexture {
212    /// The index of the texture.
213    pub index: Index<texture::Texture>,
214
215    /// The scalar multiplier controlling the amount of occlusion applied.
216    #[serde(default)]
217    pub strength: StrengthFactor,
218
219    /// The set index of the texture's `TEXCOORD` attribute.
220    #[serde(default, rename = "texCoord")]
221    pub tex_coord: u32,
222
223    /// Extension specific data.
224    #[serde(default, skip_serializing_if = "Option::is_none")]
225    pub extensions: Option<extensions::material::OcclusionTexture>,
226
227    /// Optional application specific data.
228    #[serde(default)]
229    #[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
230    #[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
231    pub extras: Extras,
232}
233
234/// The alpha cutoff value of a material.
235#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
236pub struct AlphaCutoff(pub f32);
237
238/// The emissive color of a material.
239#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
240pub struct EmissiveFactor(pub [f32; 3]);
241
242/// The base color factor of a material.
243#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
244pub struct PbrBaseColorFactor(pub [f32; 4]);
245
246/// A number in the inclusive range [0.0, 1.0] with a default value of 1.0.
247#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
248pub struct StrengthFactor(pub f32);
249
250impl Default for AlphaCutoff {
251    fn default() -> Self {
252        AlphaCutoff(0.5)
253    }
254}
255
256impl Validate for AlphaCutoff {}
257
258impl Default for AlphaMode {
259    fn default() -> Self {
260        AlphaMode::Opaque
261    }
262}
263
264impl<'de> de::Deserialize<'de> for Checked<AlphaMode> {
265    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
266    where
267        D: de::Deserializer<'de>,
268    {
269        struct Visitor;
270        impl<'de> de::Visitor<'de> for Visitor {
271            type Value = Checked<AlphaMode>;
272
273            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
274                write!(f, "any of: {:?}", VALID_ALPHA_MODES)
275            }
276
277            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
278            where
279                E: de::Error,
280            {
281                use self::AlphaMode::*;
282                use crate::validation::Checked::*;
283                Ok(match value {
284                    "OPAQUE" => Valid(Opaque),
285                    "MASK" => Valid(Mask),
286                    "BLEND" => Valid(Blend),
287                    _ => Invalid,
288                })
289            }
290        }
291        deserializer.deserialize_str(Visitor)
292    }
293}
294
295impl Validate for EmissiveFactor {}
296
297impl Default for PbrBaseColorFactor {
298    fn default() -> Self {
299        PbrBaseColorFactor([1.0, 1.0, 1.0, 1.0])
300    }
301}
302
303impl Validate for PbrBaseColorFactor {}
304
305impl Default for StrengthFactor {
306    fn default() -> Self {
307        StrengthFactor(1.0)
308    }
309}
310
311impl Validate for StrengthFactor {}