Skip to main content

bevy_pbr/
pbr_material.rs

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