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