Path: blob/main/crates/bevy_gltf/src/loader/gltf_ext/material.rs
9416 views
use bevy_material::AlphaMode;1use bevy_math::Affine2;2use bevy_mesh::UvChannel;34use gltf::{json::texture::Info, Material};56use serde_json::value;78use crate::GltfAssetLabel;910use super::texture::texture_transform_to_affine2;1112#[cfg(any(13feature = "pbr_anisotropy_texture",14feature = "pbr_specular_textures",15feature = "pbr_multi_layer_material_textures"16))]17use {18bevy_asset::{AssetPath, Handle},19bevy_image::Image,20serde_json::{Map, Value},21};2223/// Parses a texture that's part of a material extension block and returns its24/// UV channel and image reference.25#[cfg(any(26feature = "pbr_anisotropy_texture",27feature = "pbr_specular_textures",28feature = "pbr_multi_layer_material_textures"29))]30pub(crate) fn parse_material_extension_texture(31material: &Material,32extension: &Map<String, Value>,33texture_name: &str,34texture_kind: &str,35textures: &[Handle<Image>],36asset_path: AssetPath<'_>,37) -> (UvChannel, Option<Handle<Image>>) {38match extension39.get(texture_name)40.and_then(|value| value::from_value::<Info>(value.clone()).ok())41{42Some(json_info) => (43uv_channel(material, texture_kind, json_info.tex_coord),44Some({45match textures.get(json_info.index.value()).cloned() {46None => {47tracing::warn!("Gltf at path \"{asset_path}\" contains invalid texture index <{}> for texture {texture_name}. Using default image.", json_info.index.value());48Handle::default()49}50Some(handle) => handle,51}52}),53),54None => (UvChannel::default(), None),55}56}5758pub(crate) fn uv_channel(material: &Material, texture_kind: &str, tex_coord: u32) -> UvChannel {59match tex_coord {600 => UvChannel::Uv0,611 => UvChannel::Uv1,62_ => {63let material_name = material64.name()65.map(|n| format!("the material \"{n}\""))66.unwrap_or_else(|| "an unnamed material".to_string());67let material_index = material68.index()69.map(|i| format!("index {i}"))70.unwrap_or_else(|| "default".to_string());71tracing::warn!(72"Only 2 UV Channels are supported, but {material_name} ({material_index}) \73has the TEXCOORD attribute {} on texture kind {texture_kind}, which will fallback to 0.",74tex_coord,75);76UvChannel::Uv077}78}79}8081pub(crate) fn alpha_mode(material: &Material) -> AlphaMode {82match material.alpha_mode() {83gltf::material::AlphaMode::Opaque => AlphaMode::Opaque,84gltf::material::AlphaMode::Mask => AlphaMode::Mask(material.alpha_cutoff().unwrap_or(0.5)),85gltf::material::AlphaMode::Blend => AlphaMode::Blend,86}87}8889/// Returns the index (within the `textures` array) of the texture with the90/// given field name in the data for the material extension with the given name,91/// if there is one.92pub(crate) fn extension_texture_index(93material: &Material,94extension_name: &str,95texture_field_name: &str,96) -> Option<usize> {97Some(98value::from_value::<Info>(99material100.extensions()?101.get(extension_name)?102.as_object()?103.get(texture_field_name)?104.clone(),105)106.ok()?107.index108.value(),109)110}111112/// Returns true if the material needs mesh tangents in order to be successfully113/// rendered.114///115/// We generate them if this function returns true.116pub(crate) fn needs_tangents(material: &Material) -> bool {117[118material.normal_texture().is_some(),119#[cfg(feature = "pbr_multi_layer_material_textures")]120extension_texture_index(121material,122"KHR_materials_clearcoat",123"clearcoatNormalTexture",124)125.is_some(),126]127.into_iter()128.reduce(|a, b| a || b)129.unwrap_or(false)130}131132pub(crate) fn warn_on_differing_texture_transforms(133material: &Material,134info: &gltf::texture::Info,135texture_transform: Affine2,136texture_kind: &str,137) {138let has_differing_texture_transform = info139.texture_transform()140.map(texture_transform_to_affine2)141.is_some_and(|t| t != texture_transform);142if has_differing_texture_transform {143let material_name = material144.name()145.map(|n| format!("the material \"{n}\""))146.unwrap_or_else(|| "an unnamed material".to_string());147let texture_name = info148.texture()149.name()150.map(|n| format!("its {texture_kind} texture \"{n}\""))151.unwrap_or_else(|| format!("its unnamed {texture_kind} texture"));152let material_index = material153.index()154.map(|i| format!("index {i}"))155.unwrap_or_else(|| "default".to_string());156tracing::warn!(157"Only texture transforms on base color textures are supported, but {material_name} ({material_index}) \158has a texture transform on {texture_name} (index {}), which will be ignored.", info.texture().index()159);160}161}162163pub(crate) fn material_label(material: &Material, is_scale_inverted: bool) -> GltfAssetLabel {164if let Some(index) = material.index() {165GltfAssetLabel::Material {166index,167is_scale_inverted,168}169} else {170GltfAssetLabel::DefaultMaterial171}172}173174175