bevy_pbr/
pbr_material.rs

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