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