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