use bevy_asset::Asset;1use bevy_color::{Alpha, ColorToComponents};2use bevy_material::OpaqueRendererMethod;3use bevy_math::{Affine2, Affine3, Mat2, Mat3, Vec2, Vec3, Vec4};4use bevy_mesh::{MeshVertexBufferLayoutRef, UvChannel};5use bevy_reflect::{std_traits::ReflectDefault, Reflect};6use bevy_render::{render_asset::RenderAssets, render_resource::*, texture::GpuImage};7use bitflags::bitflags;89use crate::{deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID, *};1011/// A material with "standard" properties used in PBR lighting.12/// Standard property values with pictures here:13/// <https://google.github.io/filament/notes/material_properties.html>.14///15/// May be created directly from a [`Color`] or an [`Image`].16#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]17#[bind_group_data(StandardMaterialKey)]18#[data(0, StandardMaterialUniform, binding_array(10))]19#[bindless(index_table(range(0..31)))]20#[reflect(Default, Debug, Clone)]21pub struct StandardMaterial {22/// The color of the surface of the material before lighting.23///24/// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything25/// in between. If used together with a `base_color_texture`, this is factored into the final26/// base color as `base_color * base_color_texture_value`.27///28/// Defaults to [`Color::WHITE`].29pub base_color: Color,3031/// The UV channel to use for the [`StandardMaterial::base_color_texture`].32///33/// Defaults to [`UvChannel::Uv0`].34pub base_color_channel: UvChannel,3536/// The texture component of the material's color before lighting.37/// The actual pre-lighting color is `base_color * this_texture`.38///39/// See [`base_color`] for details.40///41/// You should set `base_color` to [`Color::WHITE`] (the default)42/// if you want the texture to show as-is.43///44/// Setting `base_color` to something else than white will tint45/// the texture. For example, setting `base_color` to pure red will46/// tint the texture red.47///48/// [`base_color`]: StandardMaterial::base_color49#[texture(1)]50#[sampler(2)]51#[dependency]52pub base_color_texture: Option<Handle<Image>>,5354// Use a color for user friendliness even though we technically don't use the alpha channel55// Might be used in the future for exposure correction in HDR56/// Color the material "emits" to the camera.57///58/// This is typically used for monitor screens or LED lights.59/// Anything that can be visible even in darkness.60///61/// The emissive color is added to what would otherwise be the material's visible color.62/// This means that for a light emissive value, in darkness,63/// you will mostly see the emissive component.64///65/// The default emissive color is [`LinearRgba::BLACK`], which doesn't add anything to the material color.66///67/// Emissive strength is controlled by the value of the color channels,68/// while the hue is controlled by their relative values.69///70/// As a result, channel values for `emissive`71/// colors can exceed `1.0`. For instance, a `base_color` of72/// `LinearRgba::rgb(1.0, 0.0, 0.0)` represents the brightest73/// red for objects that reflect light, but an emissive color74/// like `LinearRgba::rgb(1000.0, 0.0, 0.0)` can be used to create75/// intensely bright red emissive effects.76///77/// This results in a final luminance value when multiplied78/// by the value of the greyscale emissive texture (which ranges from 0 for black to 1 for white).79/// Luminance is a measure of the amount of light emitted per unit area,80/// and can be thought of as the "brightness" of the effect.81/// In Bevy, we treat these luminance values as the physical units of cd/m², aka nits.82///83/// Increasing the emissive strength of the color will impact visual effects84/// like bloom, but it's important to note that **an emissive material won't85/// typically light up surrounding areas like a light source**,86/// it just adds a value to the color seen on screen.87pub emissive: LinearRgba,8889/// The weight in which the camera exposure influences the emissive color.90/// A value of `0.0` means the emissive color is not affected by the camera exposure.91/// In opposition, a value of `1.0` means the emissive color is multiplied by the camera exposure.92///93/// Defaults to `0.0`94pub emissive_exposure_weight: f32,9596/// The UV channel to use for the [`StandardMaterial::emissive_texture`].97///98/// Defaults to [`UvChannel::Uv0`].99pub emissive_channel: UvChannel,100101/// The emissive map, multiplies pixels with [`emissive`]102/// to get the final "emitting" color of a surface.103///104/// This color is multiplied by [`emissive`] to get the final emitted color.105/// Meaning that you should set [`emissive`] to [`Color::WHITE`]106/// if you want to use the full range of color of the emissive texture.107///108/// [`emissive`]: StandardMaterial::emissive109#[texture(3)]110#[sampler(4)]111#[dependency]112pub emissive_texture: Option<Handle<Image>>,113114/// Linear perceptual roughness, clamped to `[0.089, 1.0]` in the shader.115///116/// Defaults to `0.5`.117///118/// Low values result in a "glossy" material with specular highlights,119/// while values close to `1` result in rough materials.120///121/// If used together with a roughness/metallic texture, this is factored into the final base122/// color as `roughness * roughness_texture_value`.123///124/// 0.089 is the minimum floating point value that won't be rounded down to 0 in the125/// calculations used.126// Technically for 32-bit floats, 0.045 could be used.127// See <https://google.github.io/filament/Filament.html#materialsystem/parameterization/>128pub perceptual_roughness: f32,129130/// How "metallic" the material appears, within `[0.0, 1.0]`.131///132/// This should be set to 0.0 for dielectric materials or 1.0 for metallic materials.133/// For a hybrid surface such as corroded metal, you may need to use in-between values.134///135/// Defaults to `0.00`, for dielectric.136///137/// If used together with a roughness/metallic texture, this is factored into the final base138/// color as `metallic * metallic_texture_value`.139pub metallic: f32,140141/// The UV channel to use for the [`StandardMaterial::metallic_roughness_texture`].142///143/// Defaults to [`UvChannel::Uv0`].144pub metallic_roughness_channel: UvChannel,145146/// Metallic and roughness maps, stored as a single texture.147///148/// The blue channel contains metallic values,149/// and the green channel contains the roughness values.150/// Other channels are unused.151///152/// Those values are multiplied by the scalar ones of the material,153/// see [`metallic`] and [`perceptual_roughness`] for details.154///155/// Note that with the default values of [`metallic`] and [`perceptual_roughness`],156/// setting this texture has no effect. If you want to exclusively use the157/// `metallic_roughness_texture` values for your material, make sure to set [`metallic`]158/// and [`perceptual_roughness`] to `1.0`.159///160/// [`metallic`]: StandardMaterial::metallic161/// [`perceptual_roughness`]: StandardMaterial::perceptual_roughness162#[texture(5)]163#[sampler(6)]164#[dependency]165pub metallic_roughness_texture: Option<Handle<Image>>,166167/// Specular intensity for non-metals on a linear scale of `[0.0, 1.0]`.168///169/// Use the value as a way to control the intensity of the170/// specular highlight of the material, i.e. how reflective is the material,171/// rather than the physical property "reflectance."172///173/// Set to `0.0`, no specular highlight is visible, the highlight is strongest174/// when `reflectance` is set to `1.0`.175///176/// Defaults to `0.5` which is mapped to 4% reflectance in the shader.177#[doc(alias = "specular_intensity")]178pub reflectance: f32,179180/// A color with which to modulate the [`StandardMaterial::reflectance`] for181/// non-metals.182///183/// The specular highlights and reflection are tinted with this color. Note184/// that it has no effect for non-metals.185///186/// This feature is currently unsupported in the deferred rendering path, in187/// order to reduce the size of the geometry buffers.188///189/// Defaults to [`Color::WHITE`].190#[doc(alias = "specular_color")]191pub specular_tint: Color,192193/// The amount of light transmitted _diffusely_ through the material (i.e. “translucency”).194///195/// Implemented as a second, flipped [Lambertian diffuse](https://en.wikipedia.org/wiki/Lambertian_reflectance) lobe,196/// which provides an inexpensive but plausible approximation of translucency for thin dielectric objects (e.g. paper,197/// leaves, some fabrics) or thicker volumetric materials with short scattering distances (e.g. porcelain, wax).198///199/// For specular transmission usecases with refraction (e.g. glass) use the [`StandardMaterial::specular_transmission`] and200/// [`StandardMaterial::ior`] properties instead.201///202/// - When set to `0.0` (the default) no diffuse light is transmitted;203/// - When set to `1.0` all diffuse light is transmitted through the material;204/// - Values higher than `0.5` will cause more diffuse light to be transmitted than reflected, resulting in a “darker”205/// appearance on the side facing the light than the opposite side. (e.g. plant leaves)206///207/// ## Notes208///209/// - The material's [`StandardMaterial::base_color`] also modulates the transmitted light;210/// - To receive transmitted shadows on the diffuse transmission lobe (i.e. the “backside”) of the material,211/// use the [`TransmittedShadowReceiver`](bevy_light::TransmittedShadowReceiver) component.212#[doc(alias = "translucency")]213pub diffuse_transmission: f32,214215/// The UV channel to use for the [`StandardMaterial::diffuse_transmission_texture`].216///217/// Defaults to [`UvChannel::Uv0`].218#[cfg(feature = "pbr_transmission_textures")]219pub diffuse_transmission_channel: UvChannel,220221/// A map that modulates diffuse transmission via its alpha channel. Multiplied by [`StandardMaterial::diffuse_transmission`]222/// to obtain the final result.223///224/// **Important:** The [`StandardMaterial::diffuse_transmission`] property must be set to a value higher than 0.0,225/// or this texture won't have any effect.226#[cfg_attr(feature = "pbr_transmission_textures", texture(19))]227#[cfg_attr(feature = "pbr_transmission_textures", sampler(20))]228#[cfg(feature = "pbr_transmission_textures")]229#[dependency]230pub diffuse_transmission_texture: Option<Handle<Image>>,231232/// The amount of light transmitted _specularly_ through the material (i.e. via refraction).233///234/// - When set to `0.0` (the default) no light is transmitted.235/// - When set to `1.0` all light is transmitted through the material.236///237/// The material's [`StandardMaterial::base_color`] also modulates the transmitted light.238///239/// **Note:** Typically used in conjunction with [`StandardMaterial::thickness`], [`StandardMaterial::ior`] and [`StandardMaterial::perceptual_roughness`].240///241/// ## Performance242///243/// Specular transmission is implemented as a relatively expensive screen-space effect that allows occluded objects to be seen through the material,244/// with distortion and blur effects.245///246/// - [`crate::ScreenSpaceTransmission::steps`] can be used to enable transmissive objects247/// to be seen through other transmissive objects, at the cost of additional draw calls and texture copies; (Use with caution!)248/// - If a simplified approximation of specular transmission using only environment map lighting is sufficient, consider setting249/// [`crate::ScreenSpaceTransmission::steps`] to `0`.250/// - If purely diffuse light transmission is needed, (i.e. “translucency”) consider using [`StandardMaterial::diffuse_transmission`] instead,251/// for a much less expensive effect.252/// - Specular transmission is rendered before alpha blending, so any material with [`AlphaMode::Blend`], [`AlphaMode::Premultiplied`], [`AlphaMode::Add`] or [`AlphaMode::Multiply`]253/// won't be visible through specular transmissive materials.254#[doc(alias = "refraction")]255pub specular_transmission: f32,256257/// The UV channel to use for the [`StandardMaterial::specular_transmission_texture`].258///259/// Defaults to [`UvChannel::Uv0`].260#[cfg(feature = "pbr_transmission_textures")]261pub specular_transmission_channel: UvChannel,262263/// A map that modulates specular transmission via its red channel. Multiplied by [`StandardMaterial::specular_transmission`]264/// to obtain the final result.265///266/// **Important:** The [`StandardMaterial::specular_transmission`] property must be set to a value higher than 0.0,267/// or this texture won't have any effect.268#[cfg_attr(feature = "pbr_transmission_textures", texture(15))]269#[cfg_attr(feature = "pbr_transmission_textures", sampler(16))]270#[cfg(feature = "pbr_transmission_textures")]271#[dependency]272pub specular_transmission_texture: Option<Handle<Image>>,273274/// Thickness of the volume beneath the material surface.275///276/// When set to `0.0` (the default) the material appears as an infinitely-thin film,277/// transmitting light without distorting it.278///279/// When set to any other value, the material distorts light like a thick lens.280///281/// **Note:** Typically used in conjunction with [`StandardMaterial::specular_transmission`] and [`StandardMaterial::ior`], or with282/// [`StandardMaterial::diffuse_transmission`].283#[doc(alias = "volume")]284#[doc(alias = "thin_walled")]285pub thickness: f32,286287/// The UV channel to use for the [`StandardMaterial::thickness_texture`].288///289/// Defaults to [`UvChannel::Uv0`].290#[cfg(feature = "pbr_transmission_textures")]291pub thickness_channel: UvChannel,292293/// A map that modulates thickness via its green channel. Multiplied by [`StandardMaterial::thickness`]294/// to obtain the final result.295///296/// **Important:** The [`StandardMaterial::thickness`] property must be set to a value higher than 0.0,297/// or this texture won't have any effect.298#[cfg_attr(feature = "pbr_transmission_textures", texture(17))]299#[cfg_attr(feature = "pbr_transmission_textures", sampler(18))]300#[cfg(feature = "pbr_transmission_textures")]301#[dependency]302pub thickness_texture: Option<Handle<Image>>,303304/// The [index of refraction](https://en.wikipedia.org/wiki/Refractive_index) of the material.305///306/// Defaults to 1.5.307///308/// | Material | Index of Refraction |309/// |:----------------|:---------------------|310/// | Vacuum | 1 |311/// | Air | 1.00 |312/// | Ice | 1.31 |313/// | Water | 1.33 |314/// | Eyes | 1.38 |315/// | Quartz | 1.46 |316/// | Olive Oil | 1.47 |317/// | Honey | 1.49 |318/// | Acrylic | 1.49 |319/// | Window Glass | 1.52 |320/// | Polycarbonate | 1.58 |321/// | Flint Glass | 1.69 |322/// | Ruby | 1.71 |323/// | Glycerine | 1.74 |324/// | Sapphire | 1.77 |325/// | Cubic Zirconia | 2.15 |326/// | Diamond | 2.42 |327/// | Moissanite | 2.65 |328///329/// **Note:** Typically used in conjunction with [`StandardMaterial::specular_transmission`] and [`StandardMaterial::thickness`].330#[doc(alias = "index_of_refraction")]331#[doc(alias = "refraction_index")]332#[doc(alias = "refractive_index")]333pub ior: f32,334335/// How far, on average, light travels through the volume beneath the material's336/// surface before being absorbed.337///338/// Defaults to [`f32::INFINITY`], i.e. light is never absorbed.339///340/// **Note:** To have any effect, must be used in conjunction with:341/// - [`StandardMaterial::attenuation_color`];342/// - [`StandardMaterial::thickness`];343/// - [`StandardMaterial::diffuse_transmission`] or [`StandardMaterial::specular_transmission`].344#[doc(alias = "absorption_distance")]345#[doc(alias = "extinction_distance")]346pub attenuation_distance: f32,347348/// The resulting (non-absorbed) color after white light travels through the attenuation distance.349///350/// Defaults to [`Color::WHITE`], i.e. no change.351///352/// **Note:** To have any effect, must be used in conjunction with:353/// - [`StandardMaterial::attenuation_distance`];354/// - [`StandardMaterial::thickness`];355/// - [`StandardMaterial::diffuse_transmission`] or [`StandardMaterial::specular_transmission`].356#[doc(alias = "absorption_color")]357#[doc(alias = "extinction_color")]358pub attenuation_color: Color,359360/// The UV channel to use for the [`StandardMaterial::normal_map_texture`].361///362/// Defaults to [`UvChannel::Uv0`].363pub normal_map_channel: UvChannel,364365/// Used to fake the lighting of bumps and dents on a material.366///367/// A typical usage would be faking cobblestones on a flat plane mesh in 3D.368///369/// # Notes370///371/// Normal mapping with `StandardMaterial` and the core bevy PBR shaders requires:372/// - A normal map texture373/// - Vertex UVs374/// - Vertex tangents375/// - Vertex normals376///377/// Tangents do not have to be stored in your model,378/// they can be generated using the [`Mesh::generate_tangents`] or379/// [`Mesh::with_generated_tangents`] methods.380/// If your material has a normal map, but still renders as a flat surface,381/// make sure your meshes have their tangents set.382///383/// [`Mesh::generate_tangents`]: bevy_mesh::Mesh::generate_tangents384/// [`Mesh::with_generated_tangents`]: bevy_mesh::Mesh::with_generated_tangents385///386/// # Usage387///388/// ```389/// # use bevy_asset::{AssetServer, Handle};390/// # use bevy_ecs::change_detection::Res;391/// # use bevy_image::{Image, ImageLoaderSettings};392/// #393/// fn load_normal_map(asset_server: Res<AssetServer>) {394/// let normal_handle: Handle<Image> = asset_server.load_with_settings(395/// "textures/parallax_example/cube_normal.png",396/// // The normal map texture is in linear color space. Lighting won't look correct397/// // if `is_srgb` is `true`, which is the default.398/// |settings: &mut ImageLoaderSettings| settings.is_srgb = false,399/// );400/// }401/// ```402#[texture(9)]403#[sampler(10)]404#[dependency]405pub normal_map_texture: Option<Handle<Image>>,406407/// Normal map textures authored for DirectX have their y-component flipped. Set this to flip408/// it to right-handed conventions.409pub flip_normal_map_y: bool,410411/// The UV channel to use for the [`StandardMaterial::occlusion_texture`].412///413/// Defaults to [`UvChannel::Uv0`].414pub occlusion_channel: UvChannel,415416/// Specifies the level of exposure to ambient light.417///418/// This is usually generated and stored automatically ("baked") by 3D-modeling software.419///420/// Typically, steep concave parts of a model (such as the armpit of a shirt) are darker,421/// because they have little exposure to light.422/// An occlusion map specifies those parts of the model that light doesn't reach well.423///424/// The material will be less lit in places where this texture is dark.425/// This is similar to ambient occlusion, but built into the model.426#[texture(7)]427#[sampler(8)]428#[dependency]429pub occlusion_texture: Option<Handle<Image>>,430431/// The UV channel to use for the [`StandardMaterial::specular_texture`].432///433/// Defaults to [`UvChannel::Uv0`].434#[cfg(feature = "pbr_specular_textures")]435pub specular_channel: UvChannel,436437/// A map that specifies reflectance for non-metallic materials.438///439/// Alpha values from [0.0, 1.0] in this texture are linearly mapped to440/// reflectance values of [0.0, 0.5] and multiplied by the constant441/// [`StandardMaterial::reflectance`] value. This follows the442/// `KHR_materials_specular` specification. The map will have no effect if443/// the material is fully metallic.444///445/// When using this map, you may wish to set the446/// [`StandardMaterial::reflectance`] value to 2.0 so that this map can447/// express the full [0.0, 1.0] range of values.448///449/// Note that, because the reflectance is stored in the alpha channel, and450/// the [`StandardMaterial::specular_tint_texture`] has no alpha value, it451/// may be desirable to pack the values together and supply the same452/// texture to both fields.453#[cfg_attr(feature = "pbr_specular_textures", texture(27))]454#[cfg_attr(feature = "pbr_specular_textures", sampler(28))]455#[cfg(feature = "pbr_specular_textures")]456#[dependency]457pub specular_texture: Option<Handle<Image>>,458459/// The UV channel to use for the460/// [`StandardMaterial::specular_tint_texture`].461///462/// Defaults to [`UvChannel::Uv0`].463#[cfg(feature = "pbr_specular_textures")]464pub specular_tint_channel: UvChannel,465466/// A map that specifies color adjustment to be applied to the specular467/// reflection for non-metallic materials.468///469/// The RGB values of this texture modulate the470/// [`StandardMaterial::specular_tint`] value. See the documentation for471/// that field for more information.472///473/// Like the fixed specular tint value, this texture map isn't supported in474/// the deferred renderer.475#[cfg_attr(feature = "pbr_specular_textures", texture(29))]476#[cfg_attr(feature = "pbr_specular_textures", sampler(30))]477#[cfg(feature = "pbr_specular_textures")]478#[dependency]479pub specular_tint_texture: Option<Handle<Image>>,480481/// An extra thin translucent layer on top of the main PBR layer. This is482/// typically used for painted surfaces.483///484/// This value specifies the strength of the layer, which affects how485/// visible the clearcoat layer will be.486///487/// Defaults to zero, specifying no clearcoat layer.488pub clearcoat: f32,489490/// The UV channel to use for the [`StandardMaterial::clearcoat_texture`].491///492/// Defaults to [`UvChannel::Uv0`].493#[cfg(feature = "pbr_multi_layer_material_textures")]494pub clearcoat_channel: UvChannel,495496/// An image texture that specifies the strength of the clearcoat layer in497/// the red channel. Values sampled from this texture are multiplied by the498/// main [`StandardMaterial::clearcoat`] factor.499///500/// As this is a non-color map, it must not be loaded as sRGB.501#[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(21))]502#[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(22))]503#[cfg(feature = "pbr_multi_layer_material_textures")]504#[dependency]505pub clearcoat_texture: Option<Handle<Image>>,506507/// The roughness of the clearcoat material. This is specified in exactly508/// the same way as the [`StandardMaterial::perceptual_roughness`].509///510/// If the [`StandardMaterial::clearcoat`] value if zero, this has no511/// effect.512///513/// Defaults to 0.5.514pub clearcoat_perceptual_roughness: f32,515516/// The UV channel to use for the [`StandardMaterial::clearcoat_roughness_texture`].517///518/// Defaults to [`UvChannel::Uv0`].519#[cfg(feature = "pbr_multi_layer_material_textures")]520pub clearcoat_roughness_channel: UvChannel,521522/// An image texture that specifies the roughness of the clearcoat level in523/// the green channel. Values from this texture are multiplied by the main524/// [`StandardMaterial::clearcoat_perceptual_roughness`] factor.525///526/// As this is a non-color map, it must not be loaded as sRGB.527#[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(23))]528#[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(24))]529#[cfg(feature = "pbr_multi_layer_material_textures")]530#[dependency]531pub clearcoat_roughness_texture: Option<Handle<Image>>,532533/// The UV channel to use for the [`StandardMaterial::clearcoat_normal_texture`].534///535/// Defaults to [`UvChannel::Uv0`].536#[cfg(feature = "pbr_multi_layer_material_textures")]537pub clearcoat_normal_channel: UvChannel,538539/// An image texture that specifies a normal map that is to be applied to540/// the clearcoat layer. This can be used to simulate, for example,541/// scratches on an outer layer of varnish. Normal maps are in the same542/// format as [`StandardMaterial::normal_map_texture`].543///544/// Note that, if a clearcoat normal map isn't specified, the main normal545/// map, if any, won't be applied to the clearcoat. If you want a normal map546/// that applies to both the main material and to the clearcoat, specify it547/// in both [`StandardMaterial::normal_map_texture`] and this field.548///549/// As this is a non-color map, it must not be loaded as sRGB.550#[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(25))]551#[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(26))]552#[cfg(feature = "pbr_multi_layer_material_textures")]553#[dependency]554pub clearcoat_normal_texture: Option<Handle<Image>>,555556/// Increases the roughness along a specific direction, so that the specular557/// highlight will be stretched instead of being a circular lobe.558///559/// This value ranges from 0 (perfectly circular) to 1 (maximally560/// stretched). The default direction (corresponding to a561/// [`StandardMaterial::anisotropy_rotation`] of 0) aligns with the562/// *tangent* of the mesh; thus mesh tangents must be specified in order for563/// this parameter to have any meaning. The direction can be changed using564/// the [`StandardMaterial::anisotropy_rotation`] parameter.565///566/// This is typically used for modeling surfaces such as brushed metal and567/// hair, in which one direction of the surface but not the other is smooth.568///569/// See the [`KHR_materials_anisotropy` specification] for more details.570///571/// [`KHR_materials_anisotropy` specification]:572/// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md573pub anisotropy_strength: f32,574575/// The direction of increased roughness, in radians relative to the mesh576/// tangent.577///578/// This parameter causes the roughness to vary according to the579/// [`StandardMaterial::anisotropy_strength`]. The rotation is applied in580/// tangent-bitangent space; thus, mesh tangents must be present for this581/// parameter to have any meaning.582///583/// This parameter has no effect if584/// [`StandardMaterial::anisotropy_strength`] is zero. Its value can585/// optionally be adjusted across the mesh with the586/// [`StandardMaterial::anisotropy_texture`].587///588/// See the [`KHR_materials_anisotropy` specification] for more details.589///590/// [`KHR_materials_anisotropy` specification]:591/// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md592pub anisotropy_rotation: f32,593594/// The UV channel to use for the [`StandardMaterial::anisotropy_texture`].595///596/// Defaults to [`UvChannel::Uv0`].597#[cfg(feature = "pbr_anisotropy_texture")]598pub anisotropy_channel: UvChannel,599600/// An image texture that allows the601/// [`StandardMaterial::anisotropy_strength`] and602/// [`StandardMaterial::anisotropy_rotation`] to vary across the mesh.603///604/// The [`KHR_materials_anisotropy` specification] defines the format that605/// this texture must take. To summarize: the direction vector is encoded in606/// the red and green channels, while the strength is encoded in the blue607/// channels. For the direction vector, the red and green channels map the608/// color range [0, 1] to the vector range [-1, 1]. The direction vector609/// encoded in this texture modifies the default rotation direction in610/// tangent-bitangent space, before the611/// [`StandardMaterial::anisotropy_rotation`] parameter is applied. The612/// value in the blue channel is multiplied by the613/// [`StandardMaterial::anisotropy_strength`] value to produce the final614/// anisotropy strength.615///616/// As the texel values don't represent colors, this texture must be in617/// linear color space, not sRGB.618///619/// [`KHR_materials_anisotropy` specification]:620/// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md621#[cfg_attr(feature = "pbr_anisotropy_texture", texture(13))]622#[cfg_attr(feature = "pbr_anisotropy_texture", sampler(14))]623#[cfg(feature = "pbr_anisotropy_texture")]624#[dependency]625pub anisotropy_texture: Option<Handle<Image>>,626627/// Support two-sided lighting by automatically flipping the normals for "back" faces628/// within the PBR lighting shader.629///630/// Defaults to `false`.631/// This does not automatically configure backface culling,632/// which can be done via `cull_mode`.633pub double_sided: bool,634635/// Whether to cull the "front", "back" or neither side of a mesh.636/// If set to `None`, the two sides of the mesh are visible.637///638/// Defaults to `Some(Face::Back)`.639/// In bevy, the order of declaration of a triangle's vertices640/// in [`Mesh`] defines the triangle's front face.641///642/// When a triangle is in a viewport,643/// if its vertices appear counter-clockwise from the viewport's perspective,644/// then the viewport is seeing the triangle's front face.645/// Conversely, if the vertices appear clockwise, you are seeing the back face.646///647/// In short, in bevy, front faces winds counter-clockwise.648///649/// Your 3D editing software should manage all of that.650///651/// [`Mesh`]: bevy_mesh::Mesh652// TODO: include this in reflection somehow (maybe via remote types like serde https://serde.rs/remote-derive.html)653#[reflect(ignore, clone)]654pub cull_mode: Option<Face>,655656/// Whether to apply only the base color to this material.657///658/// Normals, occlusion textures, roughness, metallic, reflectance, emissive,659/// shadows, alpha mode and ambient light are ignored if this is set to `true`.660pub unlit: bool,661662/// Whether to enable fog for this material.663pub fog_enabled: bool,664665/// How to apply the alpha channel of the `base_color_texture`.666///667/// See [`AlphaMode`] for details. Defaults to [`AlphaMode::Opaque`].668pub alpha_mode: AlphaMode,669670/// Adjust rendered depth.671///672/// A material with a positive depth bias will render closer to the673/// camera while negative values cause the material to render behind674/// other objects. This is independent of the viewport.675///676/// `depth_bias` affects render ordering and depth write operations677/// using the `wgpu::DepthBiasState::Constant` field.678///679/// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting680pub depth_bias: f32,681682/// The depth map used for [parallax mapping].683///684/// It is a grayscale image where white represents bottom and black the top.685/// If this field is set, bevy will apply [parallax mapping].686/// Parallax mapping, unlike simple normal maps, will move the texture687/// coordinate according to the current perspective,688/// giving actual depth to the texture.689///690/// The visual result is similar to a displacement map,691/// but does not require additional geometry.692///693/// Use the [`parallax_depth_scale`] field to control the depth of the parallax.694///695/// ## Limitations696///697/// - It will look weird on bent/non-planar surfaces.698/// - The depth of the pixel does not reflect its visual position, resulting699/// in artifacts for depth-dependent features such as fog or SSAO.700/// - For the same reason, the geometry silhouette will always be701/// the one of the actual geometry, not the parallaxed version, resulting702/// in awkward looks on intersecting parallaxed surfaces.703///704/// ## Performance705///706/// Parallax mapping requires multiple texture lookups, proportional to707/// [`max_parallax_layer_count`], which might be costly.708///709/// Use the [`parallax_mapping_method`] and [`max_parallax_layer_count`] fields710/// to tweak the shader, trading graphical quality for performance.711///712/// To improve performance, set your `depth_map`'s [`Image::sampler`]713/// filter mode to `FilterMode::Nearest`, as [this paper] indicates, it improves714/// performance a bit.715///716/// To reduce artifacts, avoid steep changes in depth, blurring the depth717/// map helps with this.718///719/// Larger depth maps haves a disproportionate performance impact.720///721/// [this paper]: https://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf722/// [parallax mapping]: https://en.wikipedia.org/wiki/Parallax_mapping723/// [`parallax_depth_scale`]: StandardMaterial::parallax_depth_scale724/// [`parallax_mapping_method`]: StandardMaterial::parallax_mapping_method725/// [`max_parallax_layer_count`]: StandardMaterial::max_parallax_layer_count726#[texture(11)]727#[sampler(12)]728#[dependency]729pub depth_map: Option<Handle<Image>>,730731/// How deep the offset introduced by the depth map should be.732///733/// Default is `0.1`, anything over that value may look distorted.734/// Lower values lessen the effect.735///736/// The depth is relative to texture size. This means that if your texture737/// occupies a surface of `1` world unit, and `parallax_depth_scale` is `0.1`, then738/// the in-world depth will be of `0.1` world units.739/// If the texture stretches for `10` world units, then the final depth740/// will be of `1` world unit.741pub parallax_depth_scale: f32,742743/// Which parallax mapping method to use.744///745/// We recommend that all objects use the same [`ParallaxMappingMethod`], to avoid746/// duplicating and running two shaders.747pub parallax_mapping_method: ParallaxMappingMethod,748749/// In how many layers to split the depth maps for parallax mapping.750///751/// If you are seeing jaggy edges, increase this value.752/// However, this incurs a performance cost.753///754/// Dependent on the situation, switching to [`ParallaxMappingMethod::Relief`]755/// and keeping this value low might have better performance than increasing the756/// layer count while using [`ParallaxMappingMethod::Occlusion`].757///758/// Default is `16.0`.759pub max_parallax_layer_count: f32,760761/// The exposure (brightness) level of the lightmap, if present.762pub lightmap_exposure: f32,763764/// Render method used for opaque materials. (Where `alpha_mode` is [`AlphaMode::Opaque`] or [`AlphaMode::Mask`])765pub opaque_render_method: OpaqueRendererMethod,766767/// Used for selecting the deferred lighting pass for deferred materials.768/// Default is [`DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID`] for default769/// PBR deferred lighting pass. Ignored in the case of forward materials.770pub deferred_lighting_pass_id: u8,771772/// The transform applied to the UVs corresponding to `ATTRIBUTE_UV_0` on the mesh before sampling. Default is identity.773pub uv_transform: Affine2,774}775776impl StandardMaterial {777/// Horizontal flipping transform778///779/// Multiplying this with another Affine2 returns transformation with horizontally flipped texture coords780pub const FLIP_HORIZONTAL: Affine2 = Affine2 {781matrix2: Mat2::from_cols(Vec2::new(-1.0, 0.0), Vec2::Y),782translation: Vec2::X,783};784785/// Vertical flipping transform786///787/// Multiplying this with another Affine2 returns transformation with vertically flipped texture coords788pub const FLIP_VERTICAL: Affine2 = Affine2 {789matrix2: Mat2::from_cols(Vec2::X, Vec2::new(0.0, -1.0)),790translation: Vec2::Y,791};792793/// Flipping X 3D transform794///795/// Multiplying this with another Affine3 returns transformation with flipped X coords796pub const FLIP_X: Affine3 = Affine3 {797matrix3: Mat3::from_cols(Vec3::new(-1.0, 0.0, 0.0), Vec3::Y, Vec3::Z),798translation: Vec3::X,799};800801/// Flipping Y 3D transform802///803/// Multiplying this with another Affine3 returns transformation with flipped Y coords804pub const FLIP_Y: Affine3 = Affine3 {805matrix3: Mat3::from_cols(Vec3::X, Vec3::new(0.0, -1.0, 0.0), Vec3::Z),806translation: Vec3::Y,807};808809/// Flipping Z 3D transform810///811/// Multiplying this with another Affine3 returns transformation with flipped Z coords812pub const FLIP_Z: Affine3 = Affine3 {813matrix3: Mat3::from_cols(Vec3::X, Vec3::Y, Vec3::new(0.0, 0.0, -1.0)),814translation: Vec3::Z,815};816817/// Flip the texture coordinates of the material.818pub fn flip(&mut self, horizontal: bool, vertical: bool) {819if horizontal {820// Multiplication of `Affine2` is order dependent, which is why821// we do not use the `*=` operator.822self.uv_transform = Self::FLIP_HORIZONTAL * self.uv_transform;823}824if vertical {825self.uv_transform = Self::FLIP_VERTICAL * self.uv_transform;826}827}828829/// Consumes the material and returns a material with flipped texture coordinates830pub fn flipped(mut self, horizontal: bool, vertical: bool) -> Self {831self.flip(horizontal, vertical);832self833}834835/// Creates a new material from a given color836pub fn from_color(color: impl Into<Color>) -> Self {837Self::from(color.into())838}839}840841impl Default for StandardMaterial {842fn default() -> Self {843StandardMaterial {844// White because it gets multiplied with texture values if someone uses845// a texture.846base_color: Color::WHITE,847base_color_channel: UvChannel::Uv0,848base_color_texture: None,849emissive: LinearRgba::BLACK,850emissive_exposure_weight: 0.0,851emissive_channel: UvChannel::Uv0,852emissive_texture: None,853// Matches Blender's default roughness.854perceptual_roughness: 0.5,855// Metallic should generally be set to 0.0 or 1.0.856metallic: 0.0,857metallic_roughness_channel: UvChannel::Uv0,858metallic_roughness_texture: None,859// Minimum real-world reflectance is 2%, most materials between 2-5%860// Expressed in a linear scale and equivalent to 4% reflectance see861// <https://google.github.io/filament/Material%20Properties.pdf>862reflectance: 0.5,863diffuse_transmission: 0.0,864#[cfg(feature = "pbr_transmission_textures")]865diffuse_transmission_channel: UvChannel::Uv0,866#[cfg(feature = "pbr_transmission_textures")]867diffuse_transmission_texture: None,868specular_transmission: 0.0,869#[cfg(feature = "pbr_transmission_textures")]870specular_transmission_channel: UvChannel::Uv0,871#[cfg(feature = "pbr_transmission_textures")]872specular_transmission_texture: None,873thickness: 0.0,874#[cfg(feature = "pbr_transmission_textures")]875thickness_channel: UvChannel::Uv0,876#[cfg(feature = "pbr_transmission_textures")]877thickness_texture: None,878ior: 1.5,879attenuation_color: Color::WHITE,880attenuation_distance: f32::INFINITY,881occlusion_channel: UvChannel::Uv0,882occlusion_texture: None,883normal_map_channel: UvChannel::Uv0,884normal_map_texture: None,885#[cfg(feature = "pbr_specular_textures")]886specular_channel: UvChannel::Uv0,887#[cfg(feature = "pbr_specular_textures")]888specular_texture: None,889specular_tint: Color::WHITE,890#[cfg(feature = "pbr_specular_textures")]891specular_tint_channel: UvChannel::Uv0,892#[cfg(feature = "pbr_specular_textures")]893specular_tint_texture: None,894clearcoat: 0.0,895clearcoat_perceptual_roughness: 0.5,896#[cfg(feature = "pbr_multi_layer_material_textures")]897clearcoat_channel: UvChannel::Uv0,898#[cfg(feature = "pbr_multi_layer_material_textures")]899clearcoat_texture: None,900#[cfg(feature = "pbr_multi_layer_material_textures")]901clearcoat_roughness_channel: UvChannel::Uv0,902#[cfg(feature = "pbr_multi_layer_material_textures")]903clearcoat_roughness_texture: None,904#[cfg(feature = "pbr_multi_layer_material_textures")]905clearcoat_normal_channel: UvChannel::Uv0,906#[cfg(feature = "pbr_multi_layer_material_textures")]907clearcoat_normal_texture: None,908anisotropy_strength: 0.0,909anisotropy_rotation: 0.0,910#[cfg(feature = "pbr_anisotropy_texture")]911anisotropy_channel: UvChannel::Uv0,912#[cfg(feature = "pbr_anisotropy_texture")]913anisotropy_texture: None,914flip_normal_map_y: false,915double_sided: false,916cull_mode: Some(Face::Back),917unlit: false,918fog_enabled: true,919alpha_mode: AlphaMode::Opaque,920depth_bias: 0.0,921depth_map: None,922parallax_depth_scale: 0.1,923max_parallax_layer_count: 16.0,924lightmap_exposure: 1.0,925parallax_mapping_method: ParallaxMappingMethod::Occlusion,926opaque_render_method: OpaqueRendererMethod::Auto,927deferred_lighting_pass_id: DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID,928uv_transform: Affine2::IDENTITY,929}930}931}932933impl From<Color> for StandardMaterial {934fn from(color: Color) -> Self {935StandardMaterial {936base_color: color,937alpha_mode: if color.alpha() < 1.0 {938AlphaMode::Blend939} else {940AlphaMode::Opaque941},942..Default::default()943}944}945}946947impl From<Handle<Image>> for StandardMaterial {948fn from(texture: Handle<Image>) -> Self {949StandardMaterial {950base_color_texture: Some(texture),951..Default::default()952}953}954}955956// NOTE: These must match the bit flags in bevy_pbr/src/render/pbr_types.wgsl!957bitflags::bitflags! {958/// Bitflags info about the material a shader is currently rendering.959/// This is accessible in the shader in the [`StandardMaterialUniform`]960#[repr(transparent)]961pub struct StandardMaterialFlags: u32 {962const BASE_COLOR_TEXTURE = 1 << 0;963const EMISSIVE_TEXTURE = 1 << 1;964const METALLIC_ROUGHNESS_TEXTURE = 1 << 2;965const OCCLUSION_TEXTURE = 1 << 3;966const DOUBLE_SIDED = 1 << 4;967const UNLIT = 1 << 5;968const TWO_COMPONENT_NORMAL_MAP = 1 << 6;969const FLIP_NORMAL_MAP_Y = 1 << 7;970const FOG_ENABLED = 1 << 8;971const DEPTH_MAP = 1 << 9; // Used for parallax mapping972const SPECULAR_TRANSMISSION_TEXTURE = 1 << 10;973const THICKNESS_TEXTURE = 1 << 11;974const DIFFUSE_TRANSMISSION_TEXTURE = 1 << 12;975const ATTENUATION_ENABLED = 1 << 13;976const CLEARCOAT_TEXTURE = 1 << 14;977const CLEARCOAT_ROUGHNESS_TEXTURE = 1 << 15;978const CLEARCOAT_NORMAL_TEXTURE = 1 << 16;979const ANISOTROPY_TEXTURE = 1 << 17;980const SPECULAR_TEXTURE = 1 << 18;981const SPECULAR_TINT_TEXTURE = 1 << 19;982const ALPHA_MODE_RESERVED_BITS = Self::ALPHA_MODE_MASK_BITS << Self::ALPHA_MODE_SHIFT_BITS; // ← Bitmask reserving bits for the `AlphaMode`983const ALPHA_MODE_OPAQUE = 0 << Self::ALPHA_MODE_SHIFT_BITS; // ← Values are just sequential values bitshifted into984const ALPHA_MODE_MASK = 1 << Self::ALPHA_MODE_SHIFT_BITS; // the bitmask, and can range from 0 to 7.985const ALPHA_MODE_BLEND = 2 << Self::ALPHA_MODE_SHIFT_BITS; //986const ALPHA_MODE_PREMULTIPLIED = 3 << Self::ALPHA_MODE_SHIFT_BITS; //987const ALPHA_MODE_ADD = 4 << Self::ALPHA_MODE_SHIFT_BITS; // Right now only values 0–5 are used, which still gives988const ALPHA_MODE_MULTIPLY = 5 << Self::ALPHA_MODE_SHIFT_BITS; // ← us "room" for two more modes without adding more bits989const ALPHA_MODE_ALPHA_TO_COVERAGE = 6 << Self::ALPHA_MODE_SHIFT_BITS;990const NONE = 0;991const UNINITIALIZED = 0xFFFF;992}993}994995impl StandardMaterialFlags {996const ALPHA_MODE_MASK_BITS: u32 = 0b111;997const ALPHA_MODE_SHIFT_BITS: u32 = 32 - Self::ALPHA_MODE_MASK_BITS.count_ones();998}9991000/// The GPU representation of the uniform data of a [`StandardMaterial`].1001#[derive(Clone, Default, ShaderType)]1002pub struct StandardMaterialUniform {1003/// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything1004/// in between.1005pub base_color: Vec4,1006// Use a color for user-friendliness even though we technically don't use the alpha channel1007// Might be used in the future for exposure correction in HDR1008pub emissive: Vec4,1009/// Color white light takes after traveling through the attenuation distance underneath the material surface1010pub attenuation_color: Vec4,1011/// The transform applied to the UVs corresponding to `ATTRIBUTE_UV_0` on the mesh before sampling. Default is identity.1012pub uv_transform: Mat3,1013/// Specular intensity for non-metals on a linear scale of [0.0, 1.0]1014/// defaults to 0.5 which is mapped to 4% reflectance in the shader1015pub reflectance: Vec3,1016/// Linear perceptual roughness, clamped to [0.089, 1.0] in the shader1017/// Defaults to minimum of 0.0891018pub roughness: f32,1019/// From [0.0, 1.0], dielectric to pure metallic1020pub metallic: f32,1021/// Amount of diffuse light transmitted through the material1022pub diffuse_transmission: f32,1023/// Amount of specular light transmitted through the material1024pub specular_transmission: f32,1025/// Thickness of the volume underneath the material surface1026pub thickness: f32,1027/// Index of Refraction1028pub ior: f32,1029/// How far light travels through the volume underneath the material surface before being absorbed1030pub attenuation_distance: f32,1031pub clearcoat: f32,1032pub clearcoat_perceptual_roughness: f32,1033pub anisotropy_strength: f32,1034pub anisotropy_rotation: Vec2,1035/// The [`StandardMaterialFlags`] accessible in the `wgsl` shader.1036pub flags: u32,1037/// When the alpha mode mask flag is set, any base color alpha above this cutoff means fully opaque,1038/// and any below means fully transparent.1039pub alpha_cutoff: f32,1040/// The depth of the [`StandardMaterial::depth_map`] to apply.1041pub parallax_depth_scale: f32,1042/// In how many layers to split the depth maps for Steep parallax mapping.1043///1044/// If your `parallax_depth_scale` is >0.1 and you are seeing jaggy edges,1045/// increase this value. However, this incurs a performance cost.1046pub max_parallax_layer_count: f32,1047/// The exposure (brightness) level of the lightmap, if present.1048pub lightmap_exposure: f32,1049/// Using [`ParallaxMappingMethod::Relief`], how many additional1050/// steps to use at most to find the depth value.1051pub max_relief_mapping_search_steps: u32,1052/// ID for specifying which deferred lighting pass should be used for rendering this material, if any.1053pub deferred_lighting_pass_id: u32,1054}10551056impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {1057fn as_bind_group_shader_type(1058&self,1059images: &RenderAssets<GpuImage>,1060) -> StandardMaterialUniform {1061let mut flags = StandardMaterialFlags::NONE;1062if self.base_color_texture.is_some() {1063flags |= StandardMaterialFlags::BASE_COLOR_TEXTURE;1064}1065if self.emissive_texture.is_some() {1066flags |= StandardMaterialFlags::EMISSIVE_TEXTURE;1067}1068if self.metallic_roughness_texture.is_some() {1069flags |= StandardMaterialFlags::METALLIC_ROUGHNESS_TEXTURE;1070}1071if self.occlusion_texture.is_some() {1072flags |= StandardMaterialFlags::OCCLUSION_TEXTURE;1073}1074if self.double_sided {1075flags |= StandardMaterialFlags::DOUBLE_SIDED;1076}1077if self.unlit {1078flags |= StandardMaterialFlags::UNLIT;1079}1080if self.fog_enabled {1081flags |= StandardMaterialFlags::FOG_ENABLED;1082}1083if self.depth_map.is_some() {1084flags |= StandardMaterialFlags::DEPTH_MAP;1085}1086#[cfg(feature = "pbr_transmission_textures")]1087{1088if self.specular_transmission_texture.is_some() {1089flags |= StandardMaterialFlags::SPECULAR_TRANSMISSION_TEXTURE;1090}1091if self.thickness_texture.is_some() {1092flags |= StandardMaterialFlags::THICKNESS_TEXTURE;1093}1094if self.diffuse_transmission_texture.is_some() {1095flags |= StandardMaterialFlags::DIFFUSE_TRANSMISSION_TEXTURE;1096}1097}10981099#[cfg(feature = "pbr_anisotropy_texture")]1100{1101if self.anisotropy_texture.is_some() {1102flags |= StandardMaterialFlags::ANISOTROPY_TEXTURE;1103}1104}11051106#[cfg(feature = "pbr_specular_textures")]1107{1108if self.specular_texture.is_some() {1109flags |= StandardMaterialFlags::SPECULAR_TEXTURE;1110}1111if self.specular_tint_texture.is_some() {1112flags |= StandardMaterialFlags::SPECULAR_TINT_TEXTURE;1113}1114}11151116#[cfg(feature = "pbr_multi_layer_material_textures")]1117{1118if self.clearcoat_texture.is_some() {1119flags |= StandardMaterialFlags::CLEARCOAT_TEXTURE;1120}1121if self.clearcoat_roughness_texture.is_some() {1122flags |= StandardMaterialFlags::CLEARCOAT_ROUGHNESS_TEXTURE;1123}1124if self.clearcoat_normal_texture.is_some() {1125flags |= StandardMaterialFlags::CLEARCOAT_NORMAL_TEXTURE;1126}1127}11281129let has_normal_map = self.normal_map_texture.is_some();1130if has_normal_map {1131let normal_map_id = self.normal_map_texture.as_ref().map(Handle::id).unwrap();1132if let Some(texture) = images.get(normal_map_id) {1133match texture.texture_descriptor.format {1134// All 2-component unorm formats1135TextureFormat::Rg8Unorm1136| TextureFormat::Rg16Unorm1137| TextureFormat::Bc5RgUnorm1138| TextureFormat::EacRg11Unorm => {1139flags |= StandardMaterialFlags::TWO_COMPONENT_NORMAL_MAP;1140}1141_ => {}1142}1143}1144if self.flip_normal_map_y {1145flags |= StandardMaterialFlags::FLIP_NORMAL_MAP_Y;1146}1147}1148// NOTE: 0.5 is from the glTF default - do we want this?1149let mut alpha_cutoff = 0.5;1150match self.alpha_mode {1151AlphaMode::Opaque => flags |= StandardMaterialFlags::ALPHA_MODE_OPAQUE,1152AlphaMode::Mask(c) => {1153alpha_cutoff = c;1154flags |= StandardMaterialFlags::ALPHA_MODE_MASK;1155}1156AlphaMode::Blend => flags |= StandardMaterialFlags::ALPHA_MODE_BLEND,1157AlphaMode::Premultiplied => flags |= StandardMaterialFlags::ALPHA_MODE_PREMULTIPLIED,1158AlphaMode::Add => flags |= StandardMaterialFlags::ALPHA_MODE_ADD,1159AlphaMode::Multiply => flags |= StandardMaterialFlags::ALPHA_MODE_MULTIPLY,1160AlphaMode::AlphaToCoverage => {1161flags |= StandardMaterialFlags::ALPHA_MODE_ALPHA_TO_COVERAGE;1162}1163};11641165if self.attenuation_distance.is_finite() {1166flags |= StandardMaterialFlags::ATTENUATION_ENABLED;1167}11681169let mut emissive = self.emissive.to_vec4();1170emissive[3] = self.emissive_exposure_weight;11711172// Doing this up front saves having to do this repeatedly in the fragment shader.1173let anisotropy_rotation = Vec2::from_angle(self.anisotropy_rotation);11741175StandardMaterialUniform {1176base_color: LinearRgba::from(self.base_color).to_vec4(),1177emissive,1178roughness: self.perceptual_roughness,1179metallic: self.metallic,1180reflectance: LinearRgba::from(self.specular_tint).to_vec3() * self.reflectance,1181clearcoat: self.clearcoat,1182clearcoat_perceptual_roughness: self.clearcoat_perceptual_roughness,1183anisotropy_strength: self.anisotropy_strength,1184anisotropy_rotation,1185diffuse_transmission: self.diffuse_transmission,1186specular_transmission: self.specular_transmission,1187thickness: self.thickness,1188ior: self.ior,1189attenuation_distance: self.attenuation_distance,1190attenuation_color: LinearRgba::from(self.attenuation_color)1191.to_f32_array()1192.into(),1193flags: flags.bits(),1194alpha_cutoff,1195parallax_depth_scale: self.parallax_depth_scale,1196max_parallax_layer_count: self.max_parallax_layer_count,1197lightmap_exposure: self.lightmap_exposure,1198max_relief_mapping_search_steps: self.parallax_mapping_method.max_steps(),1199deferred_lighting_pass_id: self.deferred_lighting_pass_id as u32,1200uv_transform: self.uv_transform.into(),1201}1202}1203}12041205bitflags! {1206/// The pipeline key for `StandardMaterial`, packed into 64 bits.1207#[repr(C)]1208#[derive(Clone, Copy, PartialEq, Eq, Hash)]1209pub struct StandardMaterialKey: u64 {1210const CULL_FRONT = 0x000001;1211const CULL_BACK = 0x000002;1212const NORMAL_MAP = 0x000004;1213const RELIEF_MAPPING = 0x000008;1214const DIFFUSE_TRANSMISSION = 0x000010;1215const SPECULAR_TRANSMISSION = 0x000020;1216const CLEARCOAT = 0x000040;1217const CLEARCOAT_NORMAL_MAP = 0x000080;1218const ANISOTROPY = 0x000100;1219const BASE_COLOR_UV = 0x000200;1220const EMISSIVE_UV = 0x000400;1221const METALLIC_ROUGHNESS_UV = 0x000800;1222const OCCLUSION_UV = 0x001000;1223const SPECULAR_TRANSMISSION_UV = 0x002000;1224const THICKNESS_UV = 0x004000;1225const DIFFUSE_TRANSMISSION_UV = 0x008000;1226const NORMAL_MAP_UV = 0x010000;1227const ANISOTROPY_UV = 0x020000;1228const CLEARCOAT_UV = 0x040000;1229const CLEARCOAT_ROUGHNESS_UV = 0x080000;1230const CLEARCOAT_NORMAL_UV = 0x100000;1231const SPECULAR_UV = 0x200000;1232const SPECULAR_TINT_UV = 0x400000;1233const DEPTH_BIAS = 0xffffffff_00000000;1234}1235}12361237const STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT: u64 = 32;12381239impl From<&StandardMaterial> for StandardMaterialKey {1240fn from(material: &StandardMaterial) -> Self {1241let mut key = StandardMaterialKey::empty();1242key.set(1243StandardMaterialKey::CULL_FRONT,1244material.cull_mode == Some(Face::Front),1245);1246key.set(1247StandardMaterialKey::CULL_BACK,1248material.cull_mode == Some(Face::Back),1249);1250key.set(1251StandardMaterialKey::NORMAL_MAP,1252material.normal_map_texture.is_some(),1253);1254key.set(1255StandardMaterialKey::RELIEF_MAPPING,1256matches!(1257material.parallax_mapping_method,1258ParallaxMappingMethod::Relief { .. }1259),1260);1261key.set(1262StandardMaterialKey::DIFFUSE_TRANSMISSION,1263material.diffuse_transmission > 0.0,1264);1265key.set(1266StandardMaterialKey::SPECULAR_TRANSMISSION,1267material.specular_transmission > 0.0,1268);12691270key.set(StandardMaterialKey::CLEARCOAT, material.clearcoat > 0.0);12711272#[cfg(feature = "pbr_multi_layer_material_textures")]1273key.set(1274StandardMaterialKey::CLEARCOAT_NORMAL_MAP,1275material.clearcoat > 0.0 && material.clearcoat_normal_texture.is_some(),1276);12771278key.set(1279StandardMaterialKey::ANISOTROPY,1280material.anisotropy_strength > 0.0,1281);12821283key.set(1284StandardMaterialKey::BASE_COLOR_UV,1285material.base_color_channel != UvChannel::Uv0,1286);12871288key.set(1289StandardMaterialKey::EMISSIVE_UV,1290material.emissive_channel != UvChannel::Uv0,1291);1292key.set(1293StandardMaterialKey::METALLIC_ROUGHNESS_UV,1294material.metallic_roughness_channel != UvChannel::Uv0,1295);1296key.set(1297StandardMaterialKey::OCCLUSION_UV,1298material.occlusion_channel != UvChannel::Uv0,1299);1300#[cfg(feature = "pbr_transmission_textures")]1301{1302key.set(1303StandardMaterialKey::SPECULAR_TRANSMISSION_UV,1304material.specular_transmission_channel != UvChannel::Uv0,1305);1306key.set(1307StandardMaterialKey::THICKNESS_UV,1308material.thickness_channel != UvChannel::Uv0,1309);1310key.set(1311StandardMaterialKey::DIFFUSE_TRANSMISSION_UV,1312material.diffuse_transmission_channel != UvChannel::Uv0,1313);1314}13151316key.set(1317StandardMaterialKey::NORMAL_MAP_UV,1318material.normal_map_channel != UvChannel::Uv0,1319);13201321#[cfg(feature = "pbr_anisotropy_texture")]1322{1323key.set(1324StandardMaterialKey::ANISOTROPY_UV,1325material.anisotropy_channel != UvChannel::Uv0,1326);1327}13281329#[cfg(feature = "pbr_specular_textures")]1330{1331key.set(1332StandardMaterialKey::SPECULAR_UV,1333material.specular_channel != UvChannel::Uv0,1334);1335key.set(1336StandardMaterialKey::SPECULAR_TINT_UV,1337material.specular_tint_channel != UvChannel::Uv0,1338);1339}13401341#[cfg(feature = "pbr_multi_layer_material_textures")]1342{1343key.set(1344StandardMaterialKey::CLEARCOAT_UV,1345material.clearcoat_channel != UvChannel::Uv0,1346);1347key.set(1348StandardMaterialKey::CLEARCOAT_ROUGHNESS_UV,1349material.clearcoat_roughness_channel != UvChannel::Uv0,1350);1351key.set(1352StandardMaterialKey::CLEARCOAT_NORMAL_UV,1353material.clearcoat_normal_channel != UvChannel::Uv0,1354);1355}13561357key.insert(StandardMaterialKey::from_bits_retain(1358// Casting to i32 first to ensure the full i32 range is preserved.1359// (wgpu expects the depth_bias as an i32 when this is extracted in a later step)1360(material.depth_bias as i32 as u64) << STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT,1361));1362key1363}1364}13651366impl Material for StandardMaterial {1367fn fragment_shader() -> ShaderRef {1368shader_ref(bevy_asset::embedded_path!("render/pbr.wgsl"))1369}13701371#[inline]1372fn alpha_mode(&self) -> AlphaMode {1373self.alpha_mode1374}13751376#[inline]1377fn opaque_render_method(&self) -> OpaqueRendererMethod {1378match self.opaque_render_method {1379// For now, diffuse transmission doesn't work under deferred rendering as we don't pack1380// the required data into the GBuffer. If this material is set to `Auto`, we report it as1381// `Forward` so that it's rendered correctly, even when the `DefaultOpaqueRendererMethod`1382// is set to `Deferred`.1383//1384// If the developer explicitly sets the `OpaqueRendererMethod` to `Deferred`, we assume1385// they know what they're doing and don't override it.1386OpaqueRendererMethod::Auto if self.diffuse_transmission > 0.0 => {1387OpaqueRendererMethod::Forward1388}1389other => other,1390}1391}13921393#[inline]1394fn depth_bias(&self) -> f32 {1395self.depth_bias1396}13971398#[inline]1399fn reads_view_transmission_texture(&self) -> bool {1400self.specular_transmission > 0.01401}14021403fn prepass_fragment_shader() -> ShaderRef {1404shader_ref(bevy_asset::embedded_path!("render/pbr_prepass.wgsl"))1405}14061407fn deferred_fragment_shader() -> ShaderRef {1408shader_ref(bevy_asset::embedded_path!("render/pbr.wgsl"))1409}14101411#[cfg(feature = "meshlet")]1412fn meshlet_mesh_fragment_shader() -> ShaderRef {1413Self::fragment_shader()1414}14151416#[cfg(feature = "meshlet")]1417fn meshlet_mesh_prepass_fragment_shader() -> ShaderRef {1418Self::prepass_fragment_shader()1419}14201421#[cfg(feature = "meshlet")]1422fn meshlet_mesh_deferred_fragment_shader() -> ShaderRef {1423Self::deferred_fragment_shader()1424}14251426fn specialize(1427_pipeline: &MaterialPipeline,1428descriptor: &mut RenderPipelineDescriptor,1429_layout: &MeshVertexBufferLayoutRef,1430key: MaterialPipelineKey<Self>,1431) -> Result<(), SpecializedMeshPipelineError> {1432if let Some(fragment) = descriptor.fragment.as_mut() {1433let shader_defs = &mut fragment.shader_defs;14341435for (flags, shader_def) in [1436(1437StandardMaterialKey::NORMAL_MAP,1438"STANDARD_MATERIAL_NORMAL_MAP",1439),1440(StandardMaterialKey::RELIEF_MAPPING, "RELIEF_MAPPING"),1441(1442StandardMaterialKey::DIFFUSE_TRANSMISSION,1443"STANDARD_MATERIAL_DIFFUSE_TRANSMISSION",1444),1445(1446StandardMaterialKey::SPECULAR_TRANSMISSION,1447"STANDARD_MATERIAL_SPECULAR_TRANSMISSION",1448),1449(1450StandardMaterialKey::DIFFUSE_TRANSMISSION1451| StandardMaterialKey::SPECULAR_TRANSMISSION,1452"STANDARD_MATERIAL_DIFFUSE_OR_SPECULAR_TRANSMISSION",1453),1454(1455StandardMaterialKey::CLEARCOAT,1456"STANDARD_MATERIAL_CLEARCOAT",1457),1458(1459StandardMaterialKey::CLEARCOAT_NORMAL_MAP,1460"STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP",1461),1462(1463StandardMaterialKey::ANISOTROPY,1464"STANDARD_MATERIAL_ANISOTROPY",1465),1466(1467StandardMaterialKey::BASE_COLOR_UV,1468"STANDARD_MATERIAL_BASE_COLOR_UV_B",1469),1470(1471StandardMaterialKey::EMISSIVE_UV,1472"STANDARD_MATERIAL_EMISSIVE_UV_B",1473),1474(1475StandardMaterialKey::METALLIC_ROUGHNESS_UV,1476"STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B",1477),1478(1479StandardMaterialKey::OCCLUSION_UV,1480"STANDARD_MATERIAL_OCCLUSION_UV_B",1481),1482(1483StandardMaterialKey::SPECULAR_TRANSMISSION_UV,1484"STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B",1485),1486(1487StandardMaterialKey::THICKNESS_UV,1488"STANDARD_MATERIAL_THICKNESS_UV_B",1489),1490(1491StandardMaterialKey::DIFFUSE_TRANSMISSION_UV,1492"STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B",1493),1494(1495StandardMaterialKey::NORMAL_MAP_UV,1496"STANDARD_MATERIAL_NORMAL_MAP_UV_B",1497),1498(1499StandardMaterialKey::CLEARCOAT_UV,1500"STANDARD_MATERIAL_CLEARCOAT_UV_B",1501),1502(1503StandardMaterialKey::CLEARCOAT_ROUGHNESS_UV,1504"STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B",1505),1506(1507StandardMaterialKey::CLEARCOAT_NORMAL_UV,1508"STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B",1509),1510(1511StandardMaterialKey::ANISOTROPY_UV,1512"STANDARD_MATERIAL_ANISOTROPY_UV_B",1513),1514(1515StandardMaterialKey::SPECULAR_UV,1516"STANDARD_MATERIAL_SPECULAR_UV_B",1517),1518(1519StandardMaterialKey::SPECULAR_TINT_UV,1520"STANDARD_MATERIAL_SPECULAR_TINT_UV_B",1521),1522] {1523if key.bind_group_data.intersects(flags) {1524shader_defs.push(shader_def.into());1525}1526}1527}15281529// Generally, we want to cull front faces if `CULL_FRONT` is present and1530// backfaces if `CULL_BACK` is present. However, if the view has1531// `INVERT_CULLING` on (usually used for mirrors and the like), we do1532// the opposite.1533descriptor.primitive.cull_mode = match (1534key.bind_group_data1535.contains(StandardMaterialKey::CULL_FRONT),1536key.bind_group_data.contains(StandardMaterialKey::CULL_BACK),1537key.mesh_key.contains(MeshPipelineKey::INVERT_CULLING),1538) {1539(true, false, false) | (false, true, true) => Some(Face::Front),1540(false, true, false) | (true, false, true) => Some(Face::Back),1541_ => None,1542};15431544if let Some(label) = &mut descriptor.label {1545*label = format!("pbr_{}", *label).into();1546}1547if let Some(depth_stencil) = descriptor.depth_stencil.as_mut() {1548depth_stencil.bias.constant =1549(key.bind_group_data.bits() >> STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT) as i32;1550}1551Ok(())1552}1553}155415551556