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
6598 views
1
use bevy_math::Affine2;
2
use bevy_pbr::UvChannel;
3
use bevy_render::alpha::AlphaMode;
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_specular_textures",
15
feature = "pbr_multi_layer_material_textures"
16
))]
17
use {
18
super::texture::texture_handle_from_info,
19
bevy_asset::{Handle, LoadContext},
20
bevy_image::Image,
21
gltf::Document,
22
serde_json::{Map, Value},
23
};
24
25
/// Parses a texture that's part of a material extension block and returns its
26
/// UV channel and image reference.
27
#[cfg(any(
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
load_context: &mut LoadContext,
34
document: &Document,
35
extension: &Map<String, Value>,
36
texture_name: &str,
37
texture_kind: &str,
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(texture_handle_from_info(&json_info, document, load_context)),
46
),
47
None => (UvChannel::default(), None),
48
}
49
}
50
51
pub(crate) fn uv_channel(material: &Material, texture_kind: &str, tex_coord: u32) -> UvChannel {
52
match tex_coord {
53
0 => UvChannel::Uv0,
54
1 => UvChannel::Uv1,
55
_ => {
56
let material_name = material
57
.name()
58
.map(|n| format!("the material \"{n}\""))
59
.unwrap_or_else(|| "an unnamed material".to_string());
60
let material_index = material
61
.index()
62
.map(|i| format!("index {i}"))
63
.unwrap_or_else(|| "default".to_string());
64
tracing::warn!(
65
"Only 2 UV Channels are supported, but {material_name} ({material_index}) \
66
has the TEXCOORD attribute {} on texture kind {texture_kind}, which will fallback to 0.",
67
tex_coord,
68
);
69
UvChannel::Uv0
70
}
71
}
72
}
73
74
pub(crate) fn alpha_mode(material: &Material) -> AlphaMode {
75
match material.alpha_mode() {
76
gltf::material::AlphaMode::Opaque => AlphaMode::Opaque,
77
gltf::material::AlphaMode::Mask => AlphaMode::Mask(material.alpha_cutoff().unwrap_or(0.5)),
78
gltf::material::AlphaMode::Blend => AlphaMode::Blend,
79
}
80
}
81
82
/// Returns the index (within the `textures` array) of the texture with the
83
/// given field name in the data for the material extension with the given name,
84
/// if there is one.
85
pub(crate) fn extension_texture_index(
86
material: &Material,
87
extension_name: &str,
88
texture_field_name: &str,
89
) -> Option<usize> {
90
Some(
91
value::from_value::<Info>(
92
material
93
.extensions()?
94
.get(extension_name)?
95
.as_object()?
96
.get(texture_field_name)?
97
.clone(),
98
)
99
.ok()?
100
.index
101
.value(),
102
)
103
}
104
105
/// Returns true if the material needs mesh tangents in order to be successfully
106
/// rendered.
107
///
108
/// We generate them if this function returns true.
109
pub(crate) fn needs_tangents(material: &Material) -> bool {
110
[
111
material.normal_texture().is_some(),
112
#[cfg(feature = "pbr_multi_layer_material_textures")]
113
extension_texture_index(
114
material,
115
"KHR_materials_clearcoat",
116
"clearcoatNormalTexture",
117
)
118
.is_some(),
119
]
120
.into_iter()
121
.reduce(|a, b| a || b)
122
.unwrap_or(false)
123
}
124
125
pub(crate) fn warn_on_differing_texture_transforms(
126
material: &Material,
127
info: &gltf::texture::Info,
128
texture_transform: Affine2,
129
texture_kind: &str,
130
) {
131
let has_differing_texture_transform = info
132
.texture_transform()
133
.map(texture_transform_to_affine2)
134
.is_some_and(|t| t != texture_transform);
135
if has_differing_texture_transform {
136
let material_name = material
137
.name()
138
.map(|n| format!("the material \"{n}\""))
139
.unwrap_or_else(|| "an unnamed material".to_string());
140
let texture_name = info
141
.texture()
142
.name()
143
.map(|n| format!("its {texture_kind} texture \"{n}\""))
144
.unwrap_or_else(|| format!("its unnamed {texture_kind} texture"));
145
let material_index = material
146
.index()
147
.map(|i| format!("index {i}"))
148
.unwrap_or_else(|| "default".to_string());
149
tracing::warn!(
150
"Only texture transforms on base color textures are supported, but {material_name} ({material_index}) \
151
has a texture transform on {texture_name} (index {}), which will be ignored.", info.texture().index()
152
);
153
}
154
}
155
156
pub(crate) fn material_label(material: &Material, is_scale_inverted: bool) -> GltfAssetLabel {
157
if let Some(index) = material.index() {
158
GltfAssetLabel::Material {
159
index,
160
is_scale_inverted,
161
}
162
} else {
163
GltfAssetLabel::DefaultMaterial
164
}
165
}
166
167