bevy_pbr/pbr_material.rs
1use bevy_asset::Asset;
2use bevy_color::{Alpha, ColorToComponents};
3use bevy_math::{Affine2, Affine3, Mat2, Mat3, Vec2, Vec3, Vec4};
4use bevy_reflect::{std_traits::ReflectDefault, Reflect};
5use bevy_render::{
6 mesh::MeshVertexBufferLayoutRef, render_asset::RenderAssets, render_resource::*,
7 texture::GpuImage,
8};
9use bitflags::bitflags;
10
11use crate::{deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID, *};
12
13/// An enum to define which UV attribute to use for a texture.
14///
15/// It is used for every texture in the [`StandardMaterial`].
16/// It only supports two UV attributes, [`bevy_render::mesh::Mesh::ATTRIBUTE_UV_0`] and
17/// [`bevy_render::mesh::Mesh::ATTRIBUTE_UV_1`].
18/// The default is [`UvChannel::Uv0`].
19#[derive(Reflect, Default, Debug, Clone, PartialEq, Eq)]
20#[reflect(Default, Debug, Clone, PartialEq)]
21pub enum UvChannel {
22 #[default]
23 Uv0,
24 Uv1,
25}
26
27/// A material with "standard" properties used in PBR lighting.
28/// Standard property values with pictures here:
29/// <https://google.github.io/filament/Material%20Properties.pdf>.
30///
31/// May be created directly from a [`Color`] or an [`Image`].
32#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]
33#[bind_group_data(StandardMaterialKey)]
34#[data(0, StandardMaterialUniform, binding_array(10))]
35#[bindless(index_table(range(0..31)))]
36#[reflect(Default, Debug, Clone)]
37pub struct StandardMaterial {
38 /// The color of the surface of the material before lighting.
39 ///
40 /// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything
41 /// in between. If used together with a `base_color_texture`, this is factored into the final
42 /// base color as `base_color * base_color_texture_value`.
43 ///
44 /// Defaults to [`Color::WHITE`].
45 pub base_color: Color,
46
47 /// The UV channel to use for the [`StandardMaterial::base_color_texture`].
48 ///
49 /// Defaults to [`UvChannel::Uv0`].
50 pub base_color_channel: UvChannel,
51
52 /// The texture component of the material's color before lighting.
53 /// The actual pre-lighting color is `base_color * this_texture`.
54 ///
55 /// See [`base_color`] for details.
56 ///
57 /// You should set `base_color` to [`Color::WHITE`] (the default)
58 /// if you want the texture to show as-is.
59 ///
60 /// Setting `base_color` to something else than white will tint
61 /// the texture. For example, setting `base_color` to pure red will
62 /// tint the texture red.
63 ///
64 /// [`base_color`]: StandardMaterial::base_color
65 #[texture(1)]
66 #[sampler(2)]
67 #[dependency]
68 pub base_color_texture: Option<Handle<Image>>,
69
70 // Use a color for user friendliness even though we technically don't use the alpha channel
71 // Might be used in the future for exposure correction in HDR
72 /// Color the material "emits" to the camera.
73 ///
74 /// This is typically used for monitor screens or LED lights.
75 /// Anything that can be visible even in darkness.
76 ///
77 /// The emissive color is added to what would otherwise be the material's visible color.
78 /// This means that for a light emissive value, in darkness,
79 /// you will mostly see the emissive component.
80 ///
81 /// The default emissive color is [`LinearRgba::BLACK`], which doesn't add anything to the material color.
82 ///
83 /// To increase emissive strength, channel values for `emissive`
84 /// colors can exceed `1.0`. For instance, a `base_color` of
85 /// `LinearRgba::rgb(1.0, 0.0, 0.0)` represents the brightest
86 /// red for objects that reflect light, but an emissive color
87 /// like `LinearRgba::rgb(1000.0, 0.0, 0.0)` can be used to create
88 /// intensely bright red emissive effects.
89 ///
90 /// Increasing the emissive strength of the color will impact visual effects
91 /// like bloom, but it's important to note that **an emissive material won't
92 /// light up surrounding areas like a light source**,
93 /// it just adds a value to the color seen on screen.
94 pub emissive: LinearRgba,
95
96 /// The weight in which the camera exposure influences the emissive color.
97 /// A value of `0.0` means the emissive color is not affected by the camera exposure.
98 /// In opposition, a value of `1.0` means the emissive color is multiplied by the camera exposure.
99 ///
100 /// Defaults to `0.0`
101 pub emissive_exposure_weight: f32,
102
103 /// The UV channel to use for the [`StandardMaterial::emissive_texture`].
104 ///
105 /// Defaults to [`UvChannel::Uv0`].
106 pub emissive_channel: UvChannel,
107
108 /// The emissive map, multiplies pixels with [`emissive`]
109 /// to get the final "emitting" color of a surface.
110 ///
111 /// This color is multiplied by [`emissive`] to get the final emitted color.
112 /// Meaning that you should set [`emissive`] to [`Color::WHITE`]
113 /// if you want to use the full range of color of the emissive texture.
114 ///
115 /// [`emissive`]: StandardMaterial::emissive
116 #[texture(3)]
117 #[sampler(4)]
118 #[dependency]
119 pub emissive_texture: Option<Handle<Image>>,
120
121 /// Linear perceptual roughness, clamped to `[0.089, 1.0]` in the shader.
122 ///
123 /// Defaults to `0.5`.
124 ///
125 /// Low values result in a "glossy" material with specular highlights,
126 /// while values close to `1` result in rough materials.
127 ///
128 /// If used together with a roughness/metallic texture, this is factored into the final base
129 /// color as `roughness * roughness_texture_value`.
130 ///
131 /// 0.089 is the minimum floating point value that won't be rounded down to 0 in the
132 /// calculations used.
133 // Technically for 32-bit floats, 0.045 could be used.
134 // See <https://google.github.io/filament/Filament.html#materialsystem/parameterization/>
135 pub perceptual_roughness: f32,
136
137 /// How "metallic" the material appears, within `[0.0, 1.0]`.
138 ///
139 /// This should be set to 0.0 for dielectric materials or 1.0 for metallic materials.
140 /// For a hybrid surface such as corroded metal, you may need to use in-between values.
141 ///
142 /// Defaults to `0.00`, for dielectric.
143 ///
144 /// If used together with a roughness/metallic texture, this is factored into the final base
145 /// color as `metallic * metallic_texture_value`.
146 pub metallic: f32,
147
148 /// The UV channel to use for the [`StandardMaterial::metallic_roughness_texture`].
149 ///
150 /// Defaults to [`UvChannel::Uv0`].
151 pub metallic_roughness_channel: UvChannel,
152
153 /// Metallic and roughness maps, stored as a single texture.
154 ///
155 /// The blue channel contains metallic values,
156 /// and the green channel contains the roughness values.
157 /// Other channels are unused.
158 ///
159 /// Those values are multiplied by the scalar ones of the material,
160 /// see [`metallic`] and [`perceptual_roughness`] for details.
161 ///
162 /// Note that with the default values of [`metallic`] and [`perceptual_roughness`],
163 /// setting this texture has no effect. If you want to exclusively use the
164 /// `metallic_roughness_texture` values for your material, make sure to set [`metallic`]
165 /// and [`perceptual_roughness`] to `1.0`.
166 ///
167 /// [`metallic`]: StandardMaterial::metallic
168 /// [`perceptual_roughness`]: StandardMaterial::perceptual_roughness
169 #[texture(5)]
170 #[sampler(6)]
171 #[dependency]
172 pub metallic_roughness_texture: Option<Handle<Image>>,
173
174 /// Specular intensity for non-metals on a linear scale of `[0.0, 1.0]`.
175 ///
176 /// Use the value as a way to control the intensity of the
177 /// specular highlight of the material, i.e. how reflective is the material,
178 /// rather than the physical property "reflectance."
179 ///
180 /// Set to `0.0`, no specular highlight is visible, the highlight is strongest
181 /// when `reflectance` is set to `1.0`.
182 ///
183 /// Defaults to `0.5` which is mapped to 4% reflectance in the shader.
184 #[doc(alias = "specular_intensity")]
185 pub reflectance: f32,
186
187 /// A color with which to modulate the [`StandardMaterial::reflectance`] for
188 /// non-metals.
189 ///
190 /// The specular highlights and reflection are tinted with this color. Note
191 /// that it has no effect for non-metals.
192 ///
193 /// This feature is currently unsupported in the deferred rendering path, in
194 /// order to reduce the size of the geometry buffers.
195 ///
196 /// Defaults to [`Color::WHITE`].
197 #[doc(alias = "specular_color")]
198 pub specular_tint: Color,
199
200 /// The amount of light transmitted _diffusely_ through the material (i.e. “translucency”).
201 ///
202 /// Implemented as a second, flipped [Lambertian diffuse](https://en.wikipedia.org/wiki/Lambertian_reflectance) lobe,
203 /// which provides an inexpensive but plausible approximation of translucency for thin dielectric objects (e.g. paper,
204 /// leaves, some fabrics) or thicker volumetric materials with short scattering distances (e.g. porcelain, wax).
205 ///
206 /// For specular transmission usecases with refraction (e.g. glass) use the [`StandardMaterial::specular_transmission`] and
207 /// [`StandardMaterial::ior`] properties instead.
208 ///
209 /// - When set to `0.0` (the default) no diffuse light is transmitted;
210 /// - When set to `1.0` all diffuse light is transmitted through the material;
211 /// - Values higher than `0.5` will cause more diffuse light to be transmitted than reflected, resulting in a “darker”
212 /// appearance on the side facing the light than the opposite side. (e.g. plant leaves)
213 ///
214 /// ## Notes
215 ///
216 /// - The material's [`StandardMaterial::base_color`] also modulates the transmitted light;
217 /// - To receive transmitted shadows on the diffuse transmission lobe (i.e. the “backside”) of the material,
218 /// use the [`TransmittedShadowReceiver`] component.
219 #[doc(alias = "translucency")]
220 pub diffuse_transmission: f32,
221
222 /// The UV channel to use for the [`StandardMaterial::diffuse_transmission_texture`].
223 ///
224 /// Defaults to [`UvChannel::Uv0`].
225 #[cfg(feature = "pbr_transmission_textures")]
226 pub diffuse_transmission_channel: UvChannel,
227
228 /// A map that modulates diffuse transmission via its alpha channel. Multiplied by [`StandardMaterial::diffuse_transmission`]
229 /// to obtain the final result.
230 ///
231 /// **Important:** The [`StandardMaterial::diffuse_transmission`] property must be set to a value higher than 0.0,
232 /// or this texture won't have any effect.
233 #[cfg_attr(feature = "pbr_transmission_textures", texture(19))]
234 #[cfg_attr(feature = "pbr_transmission_textures", sampler(20))]
235 #[cfg(feature = "pbr_transmission_textures")]
236 pub diffuse_transmission_texture: Option<Handle<Image>>,
237
238 /// The amount of light transmitted _specularly_ through the material (i.e. via refraction).
239 ///
240 /// - When set to `0.0` (the default) no light is transmitted.
241 /// - When set to `1.0` all light is transmitted through the material.
242 ///
243 /// The material's [`StandardMaterial::base_color`] also modulates the transmitted light.
244 ///
245 /// **Note:** Typically used in conjunction with [`StandardMaterial::thickness`], [`StandardMaterial::ior`] and [`StandardMaterial::perceptual_roughness`].
246 ///
247 /// ## Performance
248 ///
249 /// Specular transmission is implemented as a relatively expensive screen-space effect that allows occluded objects to be seen through the material,
250 /// with distortion and blur effects.
251 ///
252 /// - [`Camera3d::screen_space_specular_transmission_steps`](bevy_core_pipeline::core_3d::Camera3d::screen_space_specular_transmission_steps) can be used to enable transmissive objects
253 /// to be seen through other transmissive objects, at the cost of additional draw calls and texture copies; (Use with caution!)
254 /// - If a simplified approximation of specular transmission using only environment map lighting is sufficient, consider setting
255 /// [`Camera3d::screen_space_specular_transmission_steps`](bevy_core_pipeline::core_3d::Camera3d::screen_space_specular_transmission_steps) to `0`.
256 /// - If purely diffuse light transmission is needed, (i.e. “translucency”) consider using [`StandardMaterial::diffuse_transmission`] instead,
257 /// for a much less expensive effect.
258 /// - Specular transmission is rendered before alpha blending, so any material with [`AlphaMode::Blend`], [`AlphaMode::Premultiplied`], [`AlphaMode::Add`] or [`AlphaMode::Multiply`]
259 /// won't be visible through specular transmissive materials.
260 #[doc(alias = "refraction")]
261 pub specular_transmission: f32,
262
263 /// The UV channel to use for the [`StandardMaterial::specular_transmission_texture`].
264 ///
265 /// Defaults to [`UvChannel::Uv0`].
266 #[cfg(feature = "pbr_transmission_textures")]
267 pub specular_transmission_channel: UvChannel,
268
269 /// A map that modulates specular transmission via its red channel. Multiplied by [`StandardMaterial::specular_transmission`]
270 /// to obtain the final result.
271 ///
272 /// **Important:** The [`StandardMaterial::specular_transmission`] property must be set to a value higher than 0.0,
273 /// or this texture won't have any effect.
274 #[cfg_attr(feature = "pbr_transmission_textures", texture(15))]
275 #[cfg_attr(feature = "pbr_transmission_textures", sampler(16))]
276 #[cfg(feature = "pbr_transmission_textures")]
277 pub specular_transmission_texture: Option<Handle<Image>>,
278
279 /// Thickness of the volume beneath the material surface.
280 ///
281 /// When set to `0.0` (the default) the material appears as an infinitely-thin film,
282 /// transmitting light without distorting it.
283 ///
284 /// When set to any other value, the material distorts light like a thick lens.
285 ///
286 /// **Note:** Typically used in conjunction with [`StandardMaterial::specular_transmission`] and [`StandardMaterial::ior`], or with
287 /// [`StandardMaterial::diffuse_transmission`].
288 #[doc(alias = "volume")]
289 #[doc(alias = "thin_walled")]
290 pub thickness: f32,
291
292 /// The UV channel to use for the [`StandardMaterial::thickness_texture`].
293 ///
294 /// Defaults to [`UvChannel::Uv0`].
295 #[cfg(feature = "pbr_transmission_textures")]
296 pub thickness_channel: UvChannel,
297
298 /// A map that modulates thickness via its green channel. Multiplied by [`StandardMaterial::thickness`]
299 /// to obtain the final result.
300 ///
301 /// **Important:** The [`StandardMaterial::thickness`] property must be set to a value higher than 0.0,
302 /// or this texture won't have any effect.
303 #[cfg_attr(feature = "pbr_transmission_textures", texture(17))]
304 #[cfg_attr(feature = "pbr_transmission_textures", sampler(18))]
305 #[cfg(feature = "pbr_transmission_textures")]
306 pub thickness_texture: Option<Handle<Image>>,
307
308 /// The [index of refraction](https://en.wikipedia.org/wiki/Refractive_index) of the material.
309 ///
310 /// Defaults to 1.5.
311 ///
312 /// | Material | Index of Refraction |
313 /// |:----------------|:---------------------|
314 /// | Vacuum | 1 |
315 /// | Air | 1.00 |
316 /// | Ice | 1.31 |
317 /// | Water | 1.33 |
318 /// | Eyes | 1.38 |
319 /// | Quartz | 1.46 |
320 /// | Olive Oil | 1.47 |
321 /// | Honey | 1.49 |
322 /// | Acrylic | 1.49 |
323 /// | Window Glass | 1.52 |
324 /// | Polycarbonate | 1.58 |
325 /// | Flint Glass | 1.69 |
326 /// | Ruby | 1.71 |
327 /// | Glycerine | 1.74 |
328 /// | Sapphire | 1.77 |
329 /// | Cubic Zirconia | 2.15 |
330 /// | Diamond | 2.42 |
331 /// | Moissanite | 2.65 |
332 ///
333 /// **Note:** Typically used in conjunction with [`StandardMaterial::specular_transmission`] and [`StandardMaterial::thickness`].
334 #[doc(alias = "index_of_refraction")]
335 #[doc(alias = "refraction_index")]
336 #[doc(alias = "refractive_index")]
337 pub ior: f32,
338
339 /// How far, on average, light travels through the volume beneath the material's
340 /// surface before being absorbed.
341 ///
342 /// Defaults to [`f32::INFINITY`], i.e. light is never absorbed.
343 ///
344 /// **Note:** To have any effect, must be used in conjunction with:
345 /// - [`StandardMaterial::attenuation_color`];
346 /// - [`StandardMaterial::thickness`];
347 /// - [`StandardMaterial::diffuse_transmission`] or [`StandardMaterial::specular_transmission`].
348 #[doc(alias = "absorption_distance")]
349 #[doc(alias = "extinction_distance")]
350 pub attenuation_distance: f32,
351
352 /// The resulting (non-absorbed) color after white light travels through the attenuation distance.
353 ///
354 /// Defaults to [`Color::WHITE`], i.e. no change.
355 ///
356 /// **Note:** To have any effect, must be used in conjunction with:
357 /// - [`StandardMaterial::attenuation_distance`];
358 /// - [`StandardMaterial::thickness`];
359 /// - [`StandardMaterial::diffuse_transmission`] or [`StandardMaterial::specular_transmission`].
360 #[doc(alias = "absorption_color")]
361 #[doc(alias = "extinction_color")]
362 pub attenuation_color: Color,
363
364 /// The UV channel to use for the [`StandardMaterial::normal_map_texture`].
365 ///
366 /// Defaults to [`UvChannel::Uv0`].
367 pub normal_map_channel: UvChannel,
368
369 /// Used to fake the lighting of bumps and dents on a material.
370 ///
371 /// A typical usage would be faking cobblestones on a flat plane mesh in 3D.
372 ///
373 /// # Notes
374 ///
375 /// Normal mapping with `StandardMaterial` and the core bevy PBR shaders requires:
376 /// - A normal map texture
377 /// - Vertex UVs
378 /// - Vertex tangents
379 /// - Vertex normals
380 ///
381 /// Tangents do not have to be stored in your model,
382 /// they can be generated using the [`Mesh::generate_tangents`] or
383 /// [`Mesh::with_generated_tangents`] methods.
384 /// If your material has a normal map, but still renders as a flat surface,
385 /// make sure your meshes have their tangents set.
386 ///
387 /// [`Mesh::generate_tangents`]: bevy_render::mesh::Mesh::generate_tangents
388 /// [`Mesh::with_generated_tangents`]: bevy_render::mesh::Mesh::with_generated_tangents
389 #[texture(9)]
390 #[sampler(10)]
391 #[dependency]
392 pub normal_map_texture: Option<Handle<Image>>,
393
394 /// Normal map textures authored for DirectX have their y-component flipped. Set this to flip
395 /// it to right-handed conventions.
396 pub flip_normal_map_y: bool,
397
398 /// The UV channel to use for the [`StandardMaterial::occlusion_texture`].
399 ///
400 /// Defaults to [`UvChannel::Uv0`].
401 pub occlusion_channel: UvChannel,
402
403 /// Specifies the level of exposure to ambient light.
404 ///
405 /// This is usually generated and stored automatically ("baked") by 3D-modeling software.
406 ///
407 /// Typically, steep concave parts of a model (such as the armpit of a shirt) are darker,
408 /// because they have little exposure to light.
409 /// An occlusion map specifies those parts of the model that light doesn't reach well.
410 ///
411 /// The material will be less lit in places where this texture is dark.
412 /// This is similar to ambient occlusion, but built into the model.
413 #[texture(7)]
414 #[sampler(8)]
415 #[dependency]
416 pub occlusion_texture: Option<Handle<Image>>,
417
418 /// The UV channel to use for the [`StandardMaterial::specular_texture`].
419 ///
420 /// Defaults to [`UvChannel::Uv0`].
421 #[cfg(feature = "pbr_specular_textures")]
422 pub specular_channel: UvChannel,
423
424 /// A map that specifies reflectance for non-metallic materials.
425 ///
426 /// Alpha values from [0.0, 1.0] in this texture are linearly mapped to
427 /// reflectance values of [0.0, 0.5] and multiplied by the constant
428 /// [`StandardMaterial::reflectance`] value. This follows the
429 /// `KHR_materials_specular` specification. The map will have no effect if
430 /// the material is fully metallic.
431 ///
432 /// When using this map, you may wish to set the
433 /// [`StandardMaterial::reflectance`] value to 2.0 so that this map can
434 /// express the full [0.0, 1.0] range of values.
435 ///
436 /// Note that, because the reflectance is stored in the alpha channel, and
437 /// the [`StandardMaterial::specular_tint_texture`] has no alpha value, it
438 /// may be desirable to pack the values together and supply the same
439 /// texture to both fields.
440 #[cfg_attr(feature = "pbr_specular_textures", texture(27))]
441 #[cfg_attr(feature = "pbr_specular_textures", sampler(28))]
442 #[cfg(feature = "pbr_specular_textures")]
443 pub specular_texture: Option<Handle<Image>>,
444
445 /// The UV channel to use for the
446 /// [`StandardMaterial::specular_tint_texture`].
447 ///
448 /// Defaults to [`UvChannel::Uv0`].
449 #[cfg(feature = "pbr_specular_textures")]
450 pub specular_tint_channel: UvChannel,
451
452 /// A map that specifies color adjustment to be applied to the specular
453 /// reflection for non-metallic materials.
454 ///
455 /// The RGB values of this texture modulate the
456 /// [`StandardMaterial::specular_tint`] value. See the documentation for
457 /// that field for more information.
458 ///
459 /// Like the fixed specular tint value, this texture map isn't supported in
460 /// the deferred renderer.
461 #[cfg_attr(feature = "pbr_specular_textures", texture(29))]
462 #[cfg_attr(feature = "pbr_specular_textures", sampler(30))]
463 #[cfg(feature = "pbr_specular_textures")]
464 pub specular_tint_texture: Option<Handle<Image>>,
465
466 /// An extra thin translucent layer on top of the main PBR layer. This is
467 /// typically used for painted surfaces.
468 ///
469 /// This value specifies the strength of the layer, which affects how
470 /// visible the clearcoat layer will be.
471 ///
472 /// Defaults to zero, specifying no clearcoat layer.
473 pub clearcoat: f32,
474
475 /// The UV channel to use for the [`StandardMaterial::clearcoat_texture`].
476 ///
477 /// Defaults to [`UvChannel::Uv0`].
478 #[cfg(feature = "pbr_multi_layer_material_textures")]
479 pub clearcoat_channel: UvChannel,
480
481 /// An image texture that specifies the strength of the clearcoat layer in
482 /// the red channel. Values sampled from this texture are multiplied by the
483 /// main [`StandardMaterial::clearcoat`] factor.
484 ///
485 /// As this is a non-color map, it must not be loaded as sRGB.
486 #[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(21))]
487 #[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(22))]
488 #[cfg(feature = "pbr_multi_layer_material_textures")]
489 pub clearcoat_texture: Option<Handle<Image>>,
490
491 /// The roughness of the clearcoat material. This is specified in exactly
492 /// the same way as the [`StandardMaterial::perceptual_roughness`].
493 ///
494 /// If the [`StandardMaterial::clearcoat`] value if zero, this has no
495 /// effect.
496 ///
497 /// Defaults to 0.5.
498 pub clearcoat_perceptual_roughness: f32,
499
500 /// The UV channel to use for the [`StandardMaterial::clearcoat_roughness_texture`].
501 ///
502 /// Defaults to [`UvChannel::Uv0`].
503 #[cfg(feature = "pbr_multi_layer_material_textures")]
504 pub clearcoat_roughness_channel: UvChannel,
505
506 /// An image texture that specifies the roughness of the clearcoat level in
507 /// the green channel. Values from this texture are multiplied by the main
508 /// [`StandardMaterial::clearcoat_perceptual_roughness`] factor.
509 ///
510 /// As this is a non-color map, it must not be loaded as sRGB.
511 #[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(23))]
512 #[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(24))]
513 #[cfg(feature = "pbr_multi_layer_material_textures")]
514 pub clearcoat_roughness_texture: Option<Handle<Image>>,
515
516 /// The UV channel to use for the [`StandardMaterial::clearcoat_normal_texture`].
517 ///
518 /// Defaults to [`UvChannel::Uv0`].
519 #[cfg(feature = "pbr_multi_layer_material_textures")]
520 pub clearcoat_normal_channel: UvChannel,
521
522 /// An image texture that specifies a normal map that is to be applied to
523 /// the clearcoat layer. This can be used to simulate, for example,
524 /// scratches on an outer layer of varnish. Normal maps are in the same
525 /// format as [`StandardMaterial::normal_map_texture`].
526 ///
527 /// Note that, if a clearcoat normal map isn't specified, the main normal
528 /// map, if any, won't be applied to the clearcoat. If you want a normal map
529 /// that applies to both the main material and to the clearcoat, specify it
530 /// in both [`StandardMaterial::normal_map_texture`] and this field.
531 ///
532 /// As this is a non-color map, it must not be loaded as sRGB.
533 #[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(25))]
534 #[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(26))]
535 #[cfg(feature = "pbr_multi_layer_material_textures")]
536 pub clearcoat_normal_texture: Option<Handle<Image>>,
537
538 /// Increases the roughness along a specific direction, so that the specular
539 /// highlight will be stretched instead of being a circular lobe.
540 ///
541 /// This value ranges from 0 (perfectly circular) to 1 (maximally
542 /// stretched). The default direction (corresponding to a
543 /// [`StandardMaterial::anisotropy_rotation`] of 0) aligns with the
544 /// *tangent* of the mesh; thus mesh tangents must be specified in order for
545 /// this parameter to have any meaning. The direction can be changed using
546 /// the [`StandardMaterial::anisotropy_rotation`] parameter.
547 ///
548 /// This is typically used for modeling surfaces such as brushed metal and
549 /// hair, in which one direction of the surface but not the other is smooth.
550 ///
551 /// See the [`KHR_materials_anisotropy` specification] for more details.
552 ///
553 /// [`KHR_materials_anisotropy` specification]:
554 /// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md
555 pub anisotropy_strength: f32,
556
557 /// The direction of increased roughness, in radians relative to the mesh
558 /// tangent.
559 ///
560 /// This parameter causes the roughness to vary according to the
561 /// [`StandardMaterial::anisotropy_strength`]. The rotation is applied in
562 /// tangent-bitangent space; thus, mesh tangents must be present for this
563 /// parameter to have any meaning.
564 ///
565 /// This parameter has no effect if
566 /// [`StandardMaterial::anisotropy_strength`] is zero. Its value can
567 /// optionally be adjusted across the mesh with the
568 /// [`StandardMaterial::anisotropy_texture`].
569 ///
570 /// See the [`KHR_materials_anisotropy` specification] for more details.
571 ///
572 /// [`KHR_materials_anisotropy` specification]:
573 /// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md
574 pub anisotropy_rotation: f32,
575
576 /// The UV channel to use for the [`StandardMaterial::anisotropy_texture`].
577 ///
578 /// Defaults to [`UvChannel::Uv0`].
579 #[cfg(feature = "pbr_anisotropy_texture")]
580 pub anisotropy_channel: UvChannel,
581
582 /// An image texture that allows the
583 /// [`StandardMaterial::anisotropy_strength`] and
584 /// [`StandardMaterial::anisotropy_rotation`] to vary across the mesh.
585 ///
586 /// The [`KHR_materials_anisotropy` specification] defines the format that
587 /// this texture must take. To summarize: the direction vector is encoded in
588 /// the red and green channels, while the strength is encoded in the blue
589 /// channels. For the direction vector, the red and green channels map the
590 /// color range [0, 1] to the vector range [-1, 1]. The direction vector
591 /// encoded in this texture modifies the default rotation direction in
592 /// tangent-bitangent space, before the
593 /// [`StandardMaterial::anisotropy_rotation`] parameter is applied. The
594 /// value in the blue channel is multiplied by the
595 /// [`StandardMaterial::anisotropy_strength`] value to produce the final
596 /// anisotropy strength.
597 ///
598 /// As the texel values don't represent colors, this texture must be in
599 /// linear color space, not sRGB.
600 ///
601 /// [`KHR_materials_anisotropy` specification]:
602 /// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md
603 #[cfg_attr(feature = "pbr_anisotropy_texture", texture(13))]
604 #[cfg_attr(feature = "pbr_anisotropy_texture", sampler(14))]
605 #[cfg(feature = "pbr_anisotropy_texture")]
606 pub anisotropy_texture: Option<Handle<Image>>,
607
608 /// Support two-sided lighting by automatically flipping the normals for "back" faces
609 /// within the PBR lighting shader.
610 ///
611 /// Defaults to `false`.
612 /// This does not automatically configure backface culling,
613 /// which can be done via `cull_mode`.
614 pub double_sided: bool,
615
616 /// Whether to cull the "front", "back" or neither side of a mesh.
617 /// If set to `None`, the two sides of the mesh are visible.
618 ///
619 /// Defaults to `Some(Face::Back)`.
620 /// In bevy, the order of declaration of a triangle's vertices
621 /// in [`Mesh`] defines the triangle's front face.
622 ///
623 /// When a triangle is in a viewport,
624 /// if its vertices appear counter-clockwise from the viewport's perspective,
625 /// then the viewport is seeing the triangle's front face.
626 /// Conversely, if the vertices appear clockwise, you are seeing the back face.
627 ///
628 /// In short, in bevy, front faces winds counter-clockwise.
629 ///
630 /// Your 3D editing software should manage all of that.
631 ///
632 /// [`Mesh`]: bevy_render::mesh::Mesh
633 // TODO: include this in reflection somehow (maybe via remote types like serde https://serde.rs/remote-derive.html)
634 #[reflect(ignore, clone)]
635 pub cull_mode: Option<Face>,
636
637 /// Whether to apply only the base color to this material.
638 ///
639 /// Normals, occlusion textures, roughness, metallic, reflectance, emissive,
640 /// shadows, alpha mode and ambient light are ignored if this is set to `true`.
641 pub unlit: bool,
642
643 /// Whether to enable fog for this material.
644 pub fog_enabled: bool,
645
646 /// How to apply the alpha channel of the `base_color_texture`.
647 ///
648 /// See [`AlphaMode`] for details. Defaults to [`AlphaMode::Opaque`].
649 pub alpha_mode: AlphaMode,
650
651 /// Adjust rendered depth.
652 ///
653 /// A material with a positive depth bias will render closer to the
654 /// camera while negative values cause the material to render behind
655 /// other objects. This is independent of the viewport.
656 ///
657 /// `depth_bias` affects render ordering and depth write operations
658 /// using the `wgpu::DepthBiasState::Constant` field.
659 ///
660 /// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting
661 pub depth_bias: f32,
662
663 /// The depth map used for [parallax mapping].
664 ///
665 /// It is a grayscale image where white represents bottom and black the top.
666 /// If this field is set, bevy will apply [parallax mapping].
667 /// Parallax mapping, unlike simple normal maps, will move the texture
668 /// coordinate according to the current perspective,
669 /// giving actual depth to the texture.
670 ///
671 /// The visual result is similar to a displacement map,
672 /// but does not require additional geometry.
673 ///
674 /// Use the [`parallax_depth_scale`] field to control the depth of the parallax.
675 ///
676 /// ## Limitations
677 ///
678 /// - It will look weird on bent/non-planar surfaces.
679 /// - The depth of the pixel does not reflect its visual position, resulting
680 /// in artifacts for depth-dependent features such as fog or SSAO.
681 /// - For the same reason, the geometry silhouette will always be
682 /// the one of the actual geometry, not the parallaxed version, resulting
683 /// in awkward looks on intersecting parallaxed surfaces.
684 ///
685 /// ## Performance
686 ///
687 /// Parallax mapping requires multiple texture lookups, proportional to
688 /// [`max_parallax_layer_count`], which might be costly.
689 ///
690 /// Use the [`parallax_mapping_method`] and [`max_parallax_layer_count`] fields
691 /// to tweak the shader, trading graphical quality for performance.
692 ///
693 /// To improve performance, set your `depth_map`'s [`Image::sampler`]
694 /// filter mode to `FilterMode::Nearest`, as [this paper] indicates, it improves
695 /// performance a bit.
696 ///
697 /// To reduce artifacts, avoid steep changes in depth, blurring the depth
698 /// map helps with this.
699 ///
700 /// Larger depth maps haves a disproportionate performance impact.
701 ///
702 /// [this paper]: https://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf
703 /// [parallax mapping]: https://en.wikipedia.org/wiki/Parallax_mapping
704 /// [`parallax_depth_scale`]: StandardMaterial::parallax_depth_scale
705 /// [`parallax_mapping_method`]: StandardMaterial::parallax_mapping_method
706 /// [`max_parallax_layer_count`]: StandardMaterial::max_parallax_layer_count
707 #[texture(11)]
708 #[sampler(12)]
709 #[dependency]
710 pub depth_map: Option<Handle<Image>>,
711
712 /// How deep the offset introduced by the depth map should be.
713 ///
714 /// Default is `0.1`, anything over that value may look distorted.
715 /// Lower values lessen the effect.
716 ///
717 /// The depth is relative to texture size. This means that if your texture
718 /// occupies a surface of `1` world unit, and `parallax_depth_scale` is `0.1`, then
719 /// the in-world depth will be of `0.1` world units.
720 /// If the texture stretches for `10` world units, then the final depth
721 /// will be of `1` world unit.
722 pub parallax_depth_scale: f32,
723
724 /// Which parallax mapping method to use.
725 ///
726 /// We recommend that all objects use the same [`ParallaxMappingMethod`], to avoid
727 /// duplicating and running two shaders.
728 pub parallax_mapping_method: ParallaxMappingMethod,
729
730 /// In how many layers to split the depth maps for parallax mapping.
731 ///
732 /// If you are seeing jaggy edges, increase this value.
733 /// However, this incurs a performance cost.
734 ///
735 /// Dependent on the situation, switching to [`ParallaxMappingMethod::Relief`]
736 /// and keeping this value low might have better performance than increasing the
737 /// layer count while using [`ParallaxMappingMethod::Occlusion`].
738 ///
739 /// Default is `16.0`.
740 pub max_parallax_layer_count: f32,
741
742 /// The exposure (brightness) level of the lightmap, if present.
743 pub lightmap_exposure: f32,
744
745 /// Render method used for opaque materials. (Where `alpha_mode` is [`AlphaMode::Opaque`] or [`AlphaMode::Mask`])
746 pub opaque_render_method: OpaqueRendererMethod,
747
748 /// Used for selecting the deferred lighting pass for deferred materials.
749 /// Default is [`DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID`] for default
750 /// PBR deferred lighting pass. Ignored in the case of forward materials.
751 pub deferred_lighting_pass_id: u8,
752
753 /// The transform applied to the UVs corresponding to `ATTRIBUTE_UV_0` on the mesh before sampling. Default is identity.
754 pub uv_transform: Affine2,
755}
756
757impl StandardMaterial {
758 /// Horizontal flipping transform
759 ///
760 /// Multiplying this with another Affine2 returns transformation with horizontally flipped texture coords
761 pub const FLIP_HORIZONTAL: Affine2 = Affine2 {
762 matrix2: Mat2::from_cols(Vec2::new(-1.0, 0.0), Vec2::Y),
763 translation: Vec2::X,
764 };
765
766 /// Vertical flipping transform
767 ///
768 /// Multiplying this with another Affine2 returns transformation with vertically flipped texture coords
769 pub const FLIP_VERTICAL: Affine2 = Affine2 {
770 matrix2: Mat2::from_cols(Vec2::X, Vec2::new(0.0, -1.0)),
771 translation: Vec2::Y,
772 };
773
774 /// Flipping X 3D transform
775 ///
776 /// Multiplying this with another Affine3 returns transformation with flipped X coords
777 pub const FLIP_X: Affine3 = Affine3 {
778 matrix3: Mat3::from_cols(Vec3::new(-1.0, 0.0, 0.0), Vec3::Y, Vec3::Z),
779 translation: Vec3::X,
780 };
781
782 /// Flipping Y 3D transform
783 ///
784 /// Multiplying this with another Affine3 returns transformation with flipped Y coords
785 pub const FLIP_Y: Affine3 = Affine3 {
786 matrix3: Mat3::from_cols(Vec3::X, Vec3::new(0.0, -1.0, 0.0), Vec3::Z),
787 translation: Vec3::Y,
788 };
789
790 /// Flipping Z 3D transform
791 ///
792 /// Multiplying this with another Affine3 returns transformation with flipped Z coords
793 pub const FLIP_Z: Affine3 = Affine3 {
794 matrix3: Mat3::from_cols(Vec3::X, Vec3::Y, Vec3::new(0.0, 0.0, -1.0)),
795 translation: Vec3::Z,
796 };
797
798 /// Flip the texture coordinates of the material.
799 pub fn flip(&mut self, horizontal: bool, vertical: bool) {
800 if horizontal {
801 // Multiplication of `Affine2` is order dependent, which is why
802 // we do not use the `*=` operator.
803 self.uv_transform = Self::FLIP_HORIZONTAL * self.uv_transform;
804 }
805 if vertical {
806 self.uv_transform = Self::FLIP_VERTICAL * self.uv_transform;
807 }
808 }
809
810 /// Consumes the material and returns a material with flipped texture coordinates
811 pub fn flipped(mut self, horizontal: bool, vertical: bool) -> Self {
812 self.flip(horizontal, vertical);
813 self
814 }
815
816 /// Creates a new material from a given color
817 pub fn from_color(color: impl Into<Color>) -> Self {
818 Self::from(color.into())
819 }
820}
821
822impl Default for StandardMaterial {
823 fn default() -> Self {
824 StandardMaterial {
825 // White because it gets multiplied with texture values if someone uses
826 // a texture.
827 base_color: Color::WHITE,
828 base_color_channel: UvChannel::Uv0,
829 base_color_texture: None,
830 emissive: LinearRgba::BLACK,
831 emissive_exposure_weight: 0.0,
832 emissive_channel: UvChannel::Uv0,
833 emissive_texture: None,
834 // Matches Blender's default roughness.
835 perceptual_roughness: 0.5,
836 // Metallic should generally be set to 0.0 or 1.0.
837 metallic: 0.0,
838 metallic_roughness_channel: UvChannel::Uv0,
839 metallic_roughness_texture: None,
840 // Minimum real-world reflectance is 2%, most materials between 2-5%
841 // Expressed in a linear scale and equivalent to 4% reflectance see
842 // <https://google.github.io/filament/Material%20Properties.pdf>
843 reflectance: 0.5,
844 diffuse_transmission: 0.0,
845 #[cfg(feature = "pbr_transmission_textures")]
846 diffuse_transmission_channel: UvChannel::Uv0,
847 #[cfg(feature = "pbr_transmission_textures")]
848 diffuse_transmission_texture: None,
849 specular_transmission: 0.0,
850 #[cfg(feature = "pbr_transmission_textures")]
851 specular_transmission_channel: UvChannel::Uv0,
852 #[cfg(feature = "pbr_transmission_textures")]
853 specular_transmission_texture: None,
854 thickness: 0.0,
855 #[cfg(feature = "pbr_transmission_textures")]
856 thickness_channel: UvChannel::Uv0,
857 #[cfg(feature = "pbr_transmission_textures")]
858 thickness_texture: None,
859 ior: 1.5,
860 attenuation_color: Color::WHITE,
861 attenuation_distance: f32::INFINITY,
862 occlusion_channel: UvChannel::Uv0,
863 occlusion_texture: None,
864 normal_map_channel: UvChannel::Uv0,
865 normal_map_texture: None,
866 #[cfg(feature = "pbr_specular_textures")]
867 specular_channel: UvChannel::Uv0,
868 #[cfg(feature = "pbr_specular_textures")]
869 specular_texture: None,
870 specular_tint: Color::WHITE,
871 #[cfg(feature = "pbr_specular_textures")]
872 specular_tint_channel: UvChannel::Uv0,
873 #[cfg(feature = "pbr_specular_textures")]
874 specular_tint_texture: None,
875 clearcoat: 0.0,
876 clearcoat_perceptual_roughness: 0.5,
877 #[cfg(feature = "pbr_multi_layer_material_textures")]
878 clearcoat_channel: UvChannel::Uv0,
879 #[cfg(feature = "pbr_multi_layer_material_textures")]
880 clearcoat_texture: None,
881 #[cfg(feature = "pbr_multi_layer_material_textures")]
882 clearcoat_roughness_channel: UvChannel::Uv0,
883 #[cfg(feature = "pbr_multi_layer_material_textures")]
884 clearcoat_roughness_texture: None,
885 #[cfg(feature = "pbr_multi_layer_material_textures")]
886 clearcoat_normal_channel: UvChannel::Uv0,
887 #[cfg(feature = "pbr_multi_layer_material_textures")]
888 clearcoat_normal_texture: None,
889 anisotropy_strength: 0.0,
890 anisotropy_rotation: 0.0,
891 #[cfg(feature = "pbr_anisotropy_texture")]
892 anisotropy_channel: UvChannel::Uv0,
893 #[cfg(feature = "pbr_anisotropy_texture")]
894 anisotropy_texture: None,
895 flip_normal_map_y: false,
896 double_sided: false,
897 cull_mode: Some(Face::Back),
898 unlit: false,
899 fog_enabled: true,
900 alpha_mode: AlphaMode::Opaque,
901 depth_bias: 0.0,
902 depth_map: None,
903 parallax_depth_scale: 0.1,
904 max_parallax_layer_count: 16.0,
905 lightmap_exposure: 1.0,
906 parallax_mapping_method: ParallaxMappingMethod::Occlusion,
907 opaque_render_method: OpaqueRendererMethod::Auto,
908 deferred_lighting_pass_id: DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID,
909 uv_transform: Affine2::IDENTITY,
910 }
911 }
912}
913
914impl From<Color> for StandardMaterial {
915 fn from(color: Color) -> Self {
916 StandardMaterial {
917 base_color: color,
918 alpha_mode: if color.alpha() < 1.0 {
919 AlphaMode::Blend
920 } else {
921 AlphaMode::Opaque
922 },
923 ..Default::default()
924 }
925 }
926}
927
928impl From<Handle<Image>> for StandardMaterial {
929 fn from(texture: Handle<Image>) -> Self {
930 StandardMaterial {
931 base_color_texture: Some(texture),
932 ..Default::default()
933 }
934 }
935}
936
937// NOTE: These must match the bit flags in bevy_pbr/src/render/pbr_types.wgsl!
938bitflags::bitflags! {
939 /// Bitflags info about the material a shader is currently rendering.
940 /// This is accessible in the shader in the [`StandardMaterialUniform`]
941 #[repr(transparent)]
942 pub struct StandardMaterialFlags: u32 {
943 const BASE_COLOR_TEXTURE = 1 << 0;
944 const EMISSIVE_TEXTURE = 1 << 1;
945 const METALLIC_ROUGHNESS_TEXTURE = 1 << 2;
946 const OCCLUSION_TEXTURE = 1 << 3;
947 const DOUBLE_SIDED = 1 << 4;
948 const UNLIT = 1 << 5;
949 const TWO_COMPONENT_NORMAL_MAP = 1 << 6;
950 const FLIP_NORMAL_MAP_Y = 1 << 7;
951 const FOG_ENABLED = 1 << 8;
952 const DEPTH_MAP = 1 << 9; // Used for parallax mapping
953 const SPECULAR_TRANSMISSION_TEXTURE = 1 << 10;
954 const THICKNESS_TEXTURE = 1 << 11;
955 const DIFFUSE_TRANSMISSION_TEXTURE = 1 << 12;
956 const ATTENUATION_ENABLED = 1 << 13;
957 const CLEARCOAT_TEXTURE = 1 << 14;
958 const CLEARCOAT_ROUGHNESS_TEXTURE = 1 << 15;
959 const CLEARCOAT_NORMAL_TEXTURE = 1 << 16;
960 const ANISOTROPY_TEXTURE = 1 << 17;
961 const SPECULAR_TEXTURE = 1 << 18;
962 const SPECULAR_TINT_TEXTURE = 1 << 19;
963 const ALPHA_MODE_RESERVED_BITS = Self::ALPHA_MODE_MASK_BITS << Self::ALPHA_MODE_SHIFT_BITS; // ← Bitmask reserving bits for the `AlphaMode`
964 const ALPHA_MODE_OPAQUE = 0 << Self::ALPHA_MODE_SHIFT_BITS; // ← Values are just sequential values bitshifted into
965 const ALPHA_MODE_MASK = 1 << Self::ALPHA_MODE_SHIFT_BITS; // the bitmask, and can range from 0 to 7.
966 const ALPHA_MODE_BLEND = 2 << Self::ALPHA_MODE_SHIFT_BITS; //
967 const ALPHA_MODE_PREMULTIPLIED = 3 << Self::ALPHA_MODE_SHIFT_BITS; //
968 const ALPHA_MODE_ADD = 4 << Self::ALPHA_MODE_SHIFT_BITS; // Right now only values 0–5 are used, which still gives
969 const ALPHA_MODE_MULTIPLY = 5 << Self::ALPHA_MODE_SHIFT_BITS; // ← us "room" for two more modes without adding more bits
970 const ALPHA_MODE_ALPHA_TO_COVERAGE = 6 << Self::ALPHA_MODE_SHIFT_BITS;
971 const NONE = 0;
972 const UNINITIALIZED = 0xFFFF;
973 }
974}
975
976impl StandardMaterialFlags {
977 const ALPHA_MODE_MASK_BITS: u32 = 0b111;
978 const ALPHA_MODE_SHIFT_BITS: u32 = 32 - Self::ALPHA_MODE_MASK_BITS.count_ones();
979}
980
981/// The GPU representation of the uniform data of a [`StandardMaterial`].
982#[derive(Clone, Default, ShaderType)]
983pub struct StandardMaterialUniform {
984 /// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything
985 /// in between.
986 pub base_color: Vec4,
987 // Use a color for user-friendliness even though we technically don't use the alpha channel
988 // Might be used in the future for exposure correction in HDR
989 pub emissive: Vec4,
990 /// Color white light takes after traveling through the attenuation distance underneath the material surface
991 pub attenuation_color: Vec4,
992 /// The transform applied to the UVs corresponding to `ATTRIBUTE_UV_0` on the mesh before sampling. Default is identity.
993 pub uv_transform: Mat3,
994 /// Specular intensity for non-metals on a linear scale of [0.0, 1.0]
995 /// defaults to 0.5 which is mapped to 4% reflectance in the shader
996 pub reflectance: Vec3,
997 /// Linear perceptual roughness, clamped to [0.089, 1.0] in the shader
998 /// Defaults to minimum of 0.089
999 pub roughness: f32,
1000 /// From [0.0, 1.0], dielectric to pure metallic
1001 pub metallic: f32,
1002 /// Amount of diffuse light transmitted through the material
1003 pub diffuse_transmission: f32,
1004 /// Amount of specular light transmitted through the material
1005 pub specular_transmission: f32,
1006 /// Thickness of the volume underneath the material surface
1007 pub thickness: f32,
1008 /// Index of Refraction
1009 pub ior: f32,
1010 /// How far light travels through the volume underneath the material surface before being absorbed
1011 pub attenuation_distance: f32,
1012 pub clearcoat: f32,
1013 pub clearcoat_perceptual_roughness: f32,
1014 pub anisotropy_strength: f32,
1015 pub anisotropy_rotation: Vec2,
1016 /// The [`StandardMaterialFlags`] accessible in the `wgsl` shader.
1017 pub flags: u32,
1018 /// When the alpha mode mask flag is set, any base color alpha above this cutoff means fully opaque,
1019 /// and any below means fully transparent.
1020 pub alpha_cutoff: f32,
1021 /// The depth of the [`StandardMaterial::depth_map`] to apply.
1022 pub parallax_depth_scale: f32,
1023 /// In how many layers to split the depth maps for Steep parallax mapping.
1024 ///
1025 /// If your `parallax_depth_scale` is >0.1 and you are seeing jaggy edges,
1026 /// increase this value. However, this incurs a performance cost.
1027 pub max_parallax_layer_count: f32,
1028 /// The exposure (brightness) level of the lightmap, if present.
1029 pub lightmap_exposure: f32,
1030 /// Using [`ParallaxMappingMethod::Relief`], how many additional
1031 /// steps to use at most to find the depth value.
1032 pub max_relief_mapping_search_steps: u32,
1033 /// ID for specifying which deferred lighting pass should be used for rendering this material, if any.
1034 pub deferred_lighting_pass_id: u32,
1035}
1036
1037impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
1038 fn as_bind_group_shader_type(
1039 &self,
1040 images: &RenderAssets<GpuImage>,
1041 ) -> StandardMaterialUniform {
1042 let mut flags = StandardMaterialFlags::NONE;
1043 if self.base_color_texture.is_some() {
1044 flags |= StandardMaterialFlags::BASE_COLOR_TEXTURE;
1045 }
1046 if self.emissive_texture.is_some() {
1047 flags |= StandardMaterialFlags::EMISSIVE_TEXTURE;
1048 }
1049 if self.metallic_roughness_texture.is_some() {
1050 flags |= StandardMaterialFlags::METALLIC_ROUGHNESS_TEXTURE;
1051 }
1052 if self.occlusion_texture.is_some() {
1053 flags |= StandardMaterialFlags::OCCLUSION_TEXTURE;
1054 }
1055 if self.double_sided {
1056 flags |= StandardMaterialFlags::DOUBLE_SIDED;
1057 }
1058 if self.unlit {
1059 flags |= StandardMaterialFlags::UNLIT;
1060 }
1061 if self.fog_enabled {
1062 flags |= StandardMaterialFlags::FOG_ENABLED;
1063 }
1064 if self.depth_map.is_some() {
1065 flags |= StandardMaterialFlags::DEPTH_MAP;
1066 }
1067 #[cfg(feature = "pbr_transmission_textures")]
1068 {
1069 if self.specular_transmission_texture.is_some() {
1070 flags |= StandardMaterialFlags::SPECULAR_TRANSMISSION_TEXTURE;
1071 }
1072 if self.thickness_texture.is_some() {
1073 flags |= StandardMaterialFlags::THICKNESS_TEXTURE;
1074 }
1075 if self.diffuse_transmission_texture.is_some() {
1076 flags |= StandardMaterialFlags::DIFFUSE_TRANSMISSION_TEXTURE;
1077 }
1078 }
1079
1080 #[cfg(feature = "pbr_anisotropy_texture")]
1081 {
1082 if self.anisotropy_texture.is_some() {
1083 flags |= StandardMaterialFlags::ANISOTROPY_TEXTURE;
1084 }
1085 }
1086
1087 #[cfg(feature = "pbr_specular_textures")]
1088 {
1089 if self.specular_texture.is_some() {
1090 flags |= StandardMaterialFlags::SPECULAR_TEXTURE;
1091 }
1092 if self.specular_tint_texture.is_some() {
1093 flags |= StandardMaterialFlags::SPECULAR_TINT_TEXTURE;
1094 }
1095 }
1096
1097 #[cfg(feature = "pbr_multi_layer_material_textures")]
1098 {
1099 if self.clearcoat_texture.is_some() {
1100 flags |= StandardMaterialFlags::CLEARCOAT_TEXTURE;
1101 }
1102 if self.clearcoat_roughness_texture.is_some() {
1103 flags |= StandardMaterialFlags::CLEARCOAT_ROUGHNESS_TEXTURE;
1104 }
1105 if self.clearcoat_normal_texture.is_some() {
1106 flags |= StandardMaterialFlags::CLEARCOAT_NORMAL_TEXTURE;
1107 }
1108 }
1109
1110 let has_normal_map = self.normal_map_texture.is_some();
1111 if has_normal_map {
1112 let normal_map_id = self.normal_map_texture.as_ref().map(Handle::id).unwrap();
1113 if let Some(texture) = images.get(normal_map_id) {
1114 match texture.texture_format {
1115 // All 2-component unorm formats
1116 TextureFormat::Rg8Unorm
1117 | TextureFormat::Rg16Unorm
1118 | TextureFormat::Bc5RgUnorm
1119 | TextureFormat::EacRg11Unorm => {
1120 flags |= StandardMaterialFlags::TWO_COMPONENT_NORMAL_MAP;
1121 }
1122 _ => {}
1123 }
1124 }
1125 if self.flip_normal_map_y {
1126 flags |= StandardMaterialFlags::FLIP_NORMAL_MAP_Y;
1127 }
1128 }
1129 // NOTE: 0.5 is from the glTF default - do we want this?
1130 let mut alpha_cutoff = 0.5;
1131 match self.alpha_mode {
1132 AlphaMode::Opaque => flags |= StandardMaterialFlags::ALPHA_MODE_OPAQUE,
1133 AlphaMode::Mask(c) => {
1134 alpha_cutoff = c;
1135 flags |= StandardMaterialFlags::ALPHA_MODE_MASK;
1136 }
1137 AlphaMode::Blend => flags |= StandardMaterialFlags::ALPHA_MODE_BLEND,
1138 AlphaMode::Premultiplied => flags |= StandardMaterialFlags::ALPHA_MODE_PREMULTIPLIED,
1139 AlphaMode::Add => flags |= StandardMaterialFlags::ALPHA_MODE_ADD,
1140 AlphaMode::Multiply => flags |= StandardMaterialFlags::ALPHA_MODE_MULTIPLY,
1141 AlphaMode::AlphaToCoverage => {
1142 flags |= StandardMaterialFlags::ALPHA_MODE_ALPHA_TO_COVERAGE;
1143 }
1144 };
1145
1146 if self.attenuation_distance.is_finite() {
1147 flags |= StandardMaterialFlags::ATTENUATION_ENABLED;
1148 }
1149
1150 let mut emissive = self.emissive.to_vec4();
1151 emissive[3] = self.emissive_exposure_weight;
1152
1153 // Doing this up front saves having to do this repeatedly in the fragment shader.
1154 let anisotropy_rotation = Vec2::from_angle(self.anisotropy_rotation);
1155
1156 StandardMaterialUniform {
1157 base_color: LinearRgba::from(self.base_color).to_vec4(),
1158 emissive,
1159 roughness: self.perceptual_roughness,
1160 metallic: self.metallic,
1161 reflectance: LinearRgba::from(self.specular_tint).to_vec3() * self.reflectance,
1162 clearcoat: self.clearcoat,
1163 clearcoat_perceptual_roughness: self.clearcoat_perceptual_roughness,
1164 anisotropy_strength: self.anisotropy_strength,
1165 anisotropy_rotation,
1166 diffuse_transmission: self.diffuse_transmission,
1167 specular_transmission: self.specular_transmission,
1168 thickness: self.thickness,
1169 ior: self.ior,
1170 attenuation_distance: self.attenuation_distance,
1171 attenuation_color: LinearRgba::from(self.attenuation_color)
1172 .to_f32_array()
1173 .into(),
1174 flags: flags.bits(),
1175 alpha_cutoff,
1176 parallax_depth_scale: self.parallax_depth_scale,
1177 max_parallax_layer_count: self.max_parallax_layer_count,
1178 lightmap_exposure: self.lightmap_exposure,
1179 max_relief_mapping_search_steps: self.parallax_mapping_method.max_steps(),
1180 deferred_lighting_pass_id: self.deferred_lighting_pass_id as u32,
1181 uv_transform: self.uv_transform.into(),
1182 }
1183 }
1184}
1185
1186bitflags! {
1187 /// The pipeline key for `StandardMaterial`, packed into 64 bits.
1188 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
1189 pub struct StandardMaterialKey: u64 {
1190 const CULL_FRONT = 0x000001;
1191 const CULL_BACK = 0x000002;
1192 const NORMAL_MAP = 0x000004;
1193 const RELIEF_MAPPING = 0x000008;
1194 const DIFFUSE_TRANSMISSION = 0x000010;
1195 const SPECULAR_TRANSMISSION = 0x000020;
1196 const CLEARCOAT = 0x000040;
1197 const CLEARCOAT_NORMAL_MAP = 0x000080;
1198 const ANISOTROPY = 0x000100;
1199 const BASE_COLOR_UV = 0x000200;
1200 const EMISSIVE_UV = 0x000400;
1201 const METALLIC_ROUGHNESS_UV = 0x000800;
1202 const OCCLUSION_UV = 0x001000;
1203 const SPECULAR_TRANSMISSION_UV = 0x002000;
1204 const THICKNESS_UV = 0x004000;
1205 const DIFFUSE_TRANSMISSION_UV = 0x008000;
1206 const NORMAL_MAP_UV = 0x010000;
1207 const ANISOTROPY_UV = 0x020000;
1208 const CLEARCOAT_UV = 0x040000;
1209 const CLEARCOAT_ROUGHNESS_UV = 0x080000;
1210 const CLEARCOAT_NORMAL_UV = 0x100000;
1211 const SPECULAR_UV = 0x200000;
1212 const SPECULAR_TINT_UV = 0x400000;
1213 const DEPTH_BIAS = 0xffffffff_00000000;
1214 }
1215}
1216
1217const STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT: u64 = 32;
1218
1219impl From<&StandardMaterial> for StandardMaterialKey {
1220 fn from(material: &StandardMaterial) -> Self {
1221 let mut key = StandardMaterialKey::empty();
1222 key.set(
1223 StandardMaterialKey::CULL_FRONT,
1224 material.cull_mode == Some(Face::Front),
1225 );
1226 key.set(
1227 StandardMaterialKey::CULL_BACK,
1228 material.cull_mode == Some(Face::Back),
1229 );
1230 key.set(
1231 StandardMaterialKey::NORMAL_MAP,
1232 material.normal_map_texture.is_some(),
1233 );
1234 key.set(
1235 StandardMaterialKey::RELIEF_MAPPING,
1236 matches!(
1237 material.parallax_mapping_method,
1238 ParallaxMappingMethod::Relief { .. }
1239 ),
1240 );
1241 key.set(
1242 StandardMaterialKey::DIFFUSE_TRANSMISSION,
1243 material.diffuse_transmission > 0.0,
1244 );
1245 key.set(
1246 StandardMaterialKey::SPECULAR_TRANSMISSION,
1247 material.specular_transmission > 0.0,
1248 );
1249
1250 key.set(StandardMaterialKey::CLEARCOAT, material.clearcoat > 0.0);
1251
1252 #[cfg(feature = "pbr_multi_layer_material_textures")]
1253 key.set(
1254 StandardMaterialKey::CLEARCOAT_NORMAL_MAP,
1255 material.clearcoat > 0.0 && material.clearcoat_normal_texture.is_some(),
1256 );
1257
1258 key.set(
1259 StandardMaterialKey::ANISOTROPY,
1260 material.anisotropy_strength > 0.0,
1261 );
1262
1263 key.set(
1264 StandardMaterialKey::BASE_COLOR_UV,
1265 material.base_color_channel != UvChannel::Uv0,
1266 );
1267
1268 key.set(
1269 StandardMaterialKey::EMISSIVE_UV,
1270 material.emissive_channel != UvChannel::Uv0,
1271 );
1272 key.set(
1273 StandardMaterialKey::METALLIC_ROUGHNESS_UV,
1274 material.metallic_roughness_channel != UvChannel::Uv0,
1275 );
1276 key.set(
1277 StandardMaterialKey::OCCLUSION_UV,
1278 material.occlusion_channel != UvChannel::Uv0,
1279 );
1280 #[cfg(feature = "pbr_transmission_textures")]
1281 {
1282 key.set(
1283 StandardMaterialKey::SPECULAR_TRANSMISSION_UV,
1284 material.specular_transmission_channel != UvChannel::Uv0,
1285 );
1286 key.set(
1287 StandardMaterialKey::THICKNESS_UV,
1288 material.thickness_channel != UvChannel::Uv0,
1289 );
1290 key.set(
1291 StandardMaterialKey::DIFFUSE_TRANSMISSION_UV,
1292 material.diffuse_transmission_channel != UvChannel::Uv0,
1293 );
1294 }
1295
1296 key.set(
1297 StandardMaterialKey::NORMAL_MAP_UV,
1298 material.normal_map_channel != UvChannel::Uv0,
1299 );
1300
1301 #[cfg(feature = "pbr_anisotropy_texture")]
1302 {
1303 key.set(
1304 StandardMaterialKey::ANISOTROPY_UV,
1305 material.anisotropy_channel != UvChannel::Uv0,
1306 );
1307 }
1308
1309 #[cfg(feature = "pbr_specular_textures")]
1310 {
1311 key.set(
1312 StandardMaterialKey::SPECULAR_UV,
1313 material.specular_channel != UvChannel::Uv0,
1314 );
1315 key.set(
1316 StandardMaterialKey::SPECULAR_TINT_UV,
1317 material.specular_tint_channel != UvChannel::Uv0,
1318 );
1319 }
1320
1321 #[cfg(feature = "pbr_multi_layer_material_textures")]
1322 {
1323 key.set(
1324 StandardMaterialKey::CLEARCOAT_UV,
1325 material.clearcoat_channel != UvChannel::Uv0,
1326 );
1327 key.set(
1328 StandardMaterialKey::CLEARCOAT_ROUGHNESS_UV,
1329 material.clearcoat_roughness_channel != UvChannel::Uv0,
1330 );
1331 key.set(
1332 StandardMaterialKey::CLEARCOAT_NORMAL_UV,
1333 material.clearcoat_normal_channel != UvChannel::Uv0,
1334 );
1335 }
1336
1337 key.insert(StandardMaterialKey::from_bits_retain(
1338 // Casting to i32 first to ensure the full i32 range is preserved.
1339 // (wgpu expects the depth_bias as an i32 when this is extracted in a later step)
1340 (material.depth_bias as i32 as u64) << STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT,
1341 ));
1342 key
1343 }
1344}
1345
1346impl Material for StandardMaterial {
1347 fn fragment_shader() -> ShaderRef {
1348 PBR_SHADER_HANDLE.into()
1349 }
1350
1351 #[inline]
1352 fn alpha_mode(&self) -> AlphaMode {
1353 self.alpha_mode
1354 }
1355
1356 #[inline]
1357 fn opaque_render_method(&self) -> OpaqueRendererMethod {
1358 match self.opaque_render_method {
1359 // For now, diffuse transmission doesn't work under deferred rendering as we don't pack
1360 // the required data into the GBuffer. If this material is set to `Auto`, we report it as
1361 // `Forward` so that it's rendered correctly, even when the `DefaultOpaqueRendererMethod`
1362 // is set to `Deferred`.
1363 //
1364 // If the developer explicitly sets the `OpaqueRendererMethod` to `Deferred`, we assume
1365 // they know what they're doing and don't override it.
1366 OpaqueRendererMethod::Auto if self.diffuse_transmission > 0.0 => {
1367 OpaqueRendererMethod::Forward
1368 }
1369 other => other,
1370 }
1371 }
1372
1373 #[inline]
1374 fn depth_bias(&self) -> f32 {
1375 self.depth_bias
1376 }
1377
1378 #[inline]
1379 fn reads_view_transmission_texture(&self) -> bool {
1380 self.specular_transmission > 0.0
1381 }
1382
1383 fn prepass_fragment_shader() -> ShaderRef {
1384 PBR_PREPASS_SHADER_HANDLE.into()
1385 }
1386
1387 fn deferred_fragment_shader() -> ShaderRef {
1388 PBR_SHADER_HANDLE.into()
1389 }
1390
1391 #[cfg(feature = "meshlet")]
1392 fn meshlet_mesh_fragment_shader() -> ShaderRef {
1393 Self::fragment_shader()
1394 }
1395
1396 #[cfg(feature = "meshlet")]
1397 fn meshlet_mesh_prepass_fragment_shader() -> ShaderRef {
1398 Self::prepass_fragment_shader()
1399 }
1400
1401 #[cfg(feature = "meshlet")]
1402 fn meshlet_mesh_deferred_fragment_shader() -> ShaderRef {
1403 Self::deferred_fragment_shader()
1404 }
1405
1406 fn specialize(
1407 _pipeline: &MaterialPipeline<Self>,
1408 descriptor: &mut RenderPipelineDescriptor,
1409 _layout: &MeshVertexBufferLayoutRef,
1410 key: MaterialPipelineKey<Self>,
1411 ) -> Result<(), SpecializedMeshPipelineError> {
1412 if let Some(fragment) = descriptor.fragment.as_mut() {
1413 let shader_defs = &mut fragment.shader_defs;
1414
1415 for (flags, shader_def) in [
1416 (
1417 StandardMaterialKey::NORMAL_MAP,
1418 "STANDARD_MATERIAL_NORMAL_MAP",
1419 ),
1420 (StandardMaterialKey::RELIEF_MAPPING, "RELIEF_MAPPING"),
1421 (
1422 StandardMaterialKey::DIFFUSE_TRANSMISSION,
1423 "STANDARD_MATERIAL_DIFFUSE_TRANSMISSION",
1424 ),
1425 (
1426 StandardMaterialKey::SPECULAR_TRANSMISSION,
1427 "STANDARD_MATERIAL_SPECULAR_TRANSMISSION",
1428 ),
1429 (
1430 StandardMaterialKey::DIFFUSE_TRANSMISSION
1431 | StandardMaterialKey::SPECULAR_TRANSMISSION,
1432 "STANDARD_MATERIAL_DIFFUSE_OR_SPECULAR_TRANSMISSION",
1433 ),
1434 (
1435 StandardMaterialKey::CLEARCOAT,
1436 "STANDARD_MATERIAL_CLEARCOAT",
1437 ),
1438 (
1439 StandardMaterialKey::CLEARCOAT_NORMAL_MAP,
1440 "STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP",
1441 ),
1442 (
1443 StandardMaterialKey::ANISOTROPY,
1444 "STANDARD_MATERIAL_ANISOTROPY",
1445 ),
1446 (
1447 StandardMaterialKey::BASE_COLOR_UV,
1448 "STANDARD_MATERIAL_BASE_COLOR_UV_B",
1449 ),
1450 (
1451 StandardMaterialKey::EMISSIVE_UV,
1452 "STANDARD_MATERIAL_EMISSIVE_UV_B",
1453 ),
1454 (
1455 StandardMaterialKey::METALLIC_ROUGHNESS_UV,
1456 "STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B",
1457 ),
1458 (
1459 StandardMaterialKey::OCCLUSION_UV,
1460 "STANDARD_MATERIAL_OCCLUSION_UV_B",
1461 ),
1462 (
1463 StandardMaterialKey::SPECULAR_TRANSMISSION_UV,
1464 "STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B",
1465 ),
1466 (
1467 StandardMaterialKey::THICKNESS_UV,
1468 "STANDARD_MATERIAL_THICKNESS_UV_B",
1469 ),
1470 (
1471 StandardMaterialKey::DIFFUSE_TRANSMISSION_UV,
1472 "STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B",
1473 ),
1474 (
1475 StandardMaterialKey::NORMAL_MAP_UV,
1476 "STANDARD_MATERIAL_NORMAL_MAP_UV_B",
1477 ),
1478 (
1479 StandardMaterialKey::CLEARCOAT_UV,
1480 "STANDARD_MATERIAL_CLEARCOAT_UV_B",
1481 ),
1482 (
1483 StandardMaterialKey::CLEARCOAT_ROUGHNESS_UV,
1484 "STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B",
1485 ),
1486 (
1487 StandardMaterialKey::CLEARCOAT_NORMAL_UV,
1488 "STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B",
1489 ),
1490 (
1491 StandardMaterialKey::ANISOTROPY_UV,
1492 "STANDARD_MATERIAL_ANISOTROPY_UV_B",
1493 ),
1494 (
1495 StandardMaterialKey::SPECULAR_UV,
1496 "STANDARD_MATERIAL_SPECULAR_UV_B",
1497 ),
1498 (
1499 StandardMaterialKey::SPECULAR_TINT_UV,
1500 "STANDARD_MATERIAL_SPECULAR_TINT_UV_B",
1501 ),
1502 ] {
1503 if key.bind_group_data.intersects(flags) {
1504 shader_defs.push(shader_def.into());
1505 }
1506 }
1507 }
1508
1509 descriptor.primitive.cull_mode = if key
1510 .bind_group_data
1511 .contains(StandardMaterialKey::CULL_FRONT)
1512 {
1513 Some(Face::Front)
1514 } else if key.bind_group_data.contains(StandardMaterialKey::CULL_BACK) {
1515 Some(Face::Back)
1516 } else {
1517 None
1518 };
1519
1520 if let Some(label) = &mut descriptor.label {
1521 *label = format!("pbr_{}", *label).into();
1522 }
1523 if let Some(depth_stencil) = descriptor.depth_stencil.as_mut() {
1524 depth_stencil.bias.constant =
1525 (key.bind_group_data.bits() >> STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT) as i32;
1526 }
1527 Ok(())
1528 }
1529}