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