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