Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gltf/src/loader/extensions/khr_materials_specular.rs
9475 views
1
use bevy_asset::{AssetPath, Handle};
2
use bevy_image::Image;
3
4
use gltf::Material;
5
6
use serde_json::Value;
7
8
#[cfg(feature = "pbr_specular_textures")]
9
use {crate::loader::gltf_ext::material::parse_material_extension_texture, bevy_mesh::UvChannel};
10
11
/// Parsed data from the `KHR_materials_specular` extension.
12
///
13
/// We currently don't parse `specularFactor` and `specularTexture`, since
14
/// they're incompatible with Filament.
15
///
16
/// Note that the map is a *specular map*, not a *reflectance map*. In Bevy and
17
/// Filament terms, the reflectance values in the specular map range from [0.0,
18
/// 0.5], rather than [0.0, 1.0]. This is an unfortunate
19
/// `KHR_materials_specular` specification requirement that stems from the fact
20
/// that glTF is specified in terms of a specular strength model, not the
21
/// reflectance model that Filament and Bevy use. A workaround, which is noted
22
/// in the [`StandardMaterial`](https://docs.rs/bevy/latest/bevy/pbr/struct.StandardMaterial.html) documentation, is to set the reflectance value
23
/// to 2.0, which spreads the specular map range from [0.0, 1.0] as normal.
24
///
25
/// See the specification:
26
/// <https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_specular/README.md>
27
#[derive(Default)]
28
pub(crate) struct SpecularExtension {
29
pub(crate) specular_factor: Option<f64>,
30
#[cfg(feature = "pbr_specular_textures")]
31
pub(crate) specular_channel: UvChannel,
32
#[cfg(feature = "pbr_specular_textures")]
33
pub(crate) specular_texture: Option<Handle<Image>>,
34
pub(crate) specular_color_factor: Option<[f64; 3]>,
35
#[cfg(feature = "pbr_specular_textures")]
36
pub(crate) specular_color_channel: UvChannel,
37
#[cfg(feature = "pbr_specular_textures")]
38
pub(crate) specular_color_texture: Option<Handle<Image>>,
39
}
40
41
impl SpecularExtension {
42
#[expect(
43
clippy::allow_attributes,
44
reason = "`unused_variables` is not always linted"
45
)]
46
#[allow(
47
unused_variables,
48
reason = "Depending on what features are used to compile this crate, certain parameters may end up unused."
49
)]
50
pub(crate) fn parse(
51
material: &Material,
52
textures: &[Handle<Image>],
53
asset_path: AssetPath<'_>,
54
) -> Option<Self> {
55
let extension = material
56
.extensions()?
57
.get("KHR_materials_specular")?
58
.as_object()?;
59
60
#[cfg(feature = "pbr_specular_textures")]
61
let (_specular_channel, _specular_texture) = parse_material_extension_texture(
62
material,
63
extension,
64
"specularTexture",
65
"specular",
66
textures,
67
asset_path.clone(),
68
);
69
70
#[cfg(feature = "pbr_specular_textures")]
71
let (_specular_color_channel, _specular_color_texture) = parse_material_extension_texture(
72
material,
73
extension,
74
"specularColorTexture",
75
"specular color",
76
textures,
77
asset_path,
78
);
79
80
Some(SpecularExtension {
81
specular_factor: extension.get("specularFactor").and_then(Value::as_f64),
82
#[cfg(feature = "pbr_specular_textures")]
83
specular_channel: _specular_channel,
84
#[cfg(feature = "pbr_specular_textures")]
85
specular_texture: _specular_texture,
86
specular_color_factor: extension
87
.get("specularColorFactor")
88
.and_then(Value::as_array)
89
.and_then(|json_array| {
90
if json_array.len() < 3 {
91
None
92
} else {
93
Some([
94
json_array[0].as_f64()?,
95
json_array[1].as_f64()?,
96
json_array[2].as_f64()?,
97
])
98
}
99
}),
100
#[cfg(feature = "pbr_specular_textures")]
101
specular_color_channel: _specular_color_channel,
102
#[cfg(feature = "pbr_specular_textures")]
103
specular_color_texture: _specular_color_texture,
104
})
105
}
106
}
107
108