use bevy_asset::Asset;1use bevy_color::{Alpha, ColorToComponents};2use bevy_math::{Affine2, Affine3, Mat2, Mat3, Vec2, Vec3, Vec4};3use bevy_mesh::MeshVertexBufferLayoutRef;4use bevy_reflect::{std_traits::ReflectDefault, Reflect};5use bevy_render::{render_asset::RenderAssets, render_resource::*, texture::GpuImage};6use bitflags::bitflags;78use crate::{deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID, *};910/// An enum to define which UV attribute to use for a texture.11///12/// It is used for every texture in the [`StandardMaterial`].13/// It only supports two UV attributes, [`bevy_mesh::Mesh::ATTRIBUTE_UV_0`] and14/// [`bevy_mesh::Mesh::ATTRIBUTE_UV_1`].15/// The default is [`UvChannel::Uv0`].16#[derive(Reflect, Default, Debug, Clone, PartialEq, Eq)]17#[reflect(Default, Debug, Clone, PartialEq)]18pub enum UvChannel {19#[default]20Uv0,21Uv1,22}2324/// A material with "standard" properties used in PBR lighting.25/// Standard property values with pictures here:26/// <https://google.github.io/filament/notes/material_properties.html>.27///28/// May be created directly from a [`Color`] or an [`Image`].29#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]30#[bind_group_data(StandardMaterialKey)]31#[data(0, StandardMaterialUniform, binding_array(10))]32#[bindless(index_table(range(0..31)))]33#[reflect(Default, Debug, Clone)]34pub struct StandardMaterial {35/// The color of the surface of the material before lighting.36///37/// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything38/// in between. If used together with a `base_color_texture`, this is factored into the final39/// base color as `base_color * base_color_texture_value`.40///41/// Defaults to [`Color::WHITE`].42pub base_color: Color,4344/// The UV channel to use for the [`StandardMaterial::base_color_texture`].45///46/// Defaults to [`UvChannel::Uv0`].47pub base_color_channel: UvChannel,4849/// The texture component of the material's color before lighting.50/// The actual pre-lighting color is `base_color * this_texture`.51///52/// See [`base_color`] for details.53///54/// You should set `base_color` to [`Color::WHITE`] (the default)55/// if you want the texture to show as-is.56///57/// Setting `base_color` to something else than white will tint58/// the texture. For example, setting `base_color` to pure red will59/// tint the texture red.60///61/// [`base_color`]: StandardMaterial::base_color62#[texture(1)]63#[sampler(2)]64#[dependency]65pub base_color_texture: Option<Handle<Image>>,6667// Use a color for user friendliness even though we technically don't use the alpha channel68// Might be used in the future for exposure correction in HDR69/// Color the material "emits" to the camera.70///71/// This is typically used for monitor screens or LED lights.72/// Anything that can be visible even in darkness.73///74/// The emissive color is added to what would otherwise be the material's visible color.75/// This means that for a light emissive value, in darkness,76/// you will mostly see the emissive component.77///78/// The default emissive color is [`LinearRgba::BLACK`], which doesn't add anything to the material color.79///80/// Emissive strength is controlled by the value of the color channels,81/// while the hue is controlled by their relative values.82///83/// As a result, channel values for `emissive`84/// colors can exceed `1.0`. For instance, a `base_color` of85/// `LinearRgba::rgb(1.0, 0.0, 0.0)` represents the brightest86/// red for objects that reflect light, but an emissive color87/// like `LinearRgba::rgb(1000.0, 0.0, 0.0)` can be used to create88/// intensely bright red emissive effects.89///90/// This results in a final luminance value when multiplied91/// by the value of the greyscale emissive texture (which ranges from 0 for black to 1 for white).92/// Luminance is a measure of the amount of light emitted per unit area,93/// and can be thought of as the "brightness" of the effect.94/// In Bevy, we treat these luminance values as the physical units of cd/m², aka nits.95///96/// Increasing the emissive strength of the color will impact visual effects97/// like bloom, but it's important to note that **an emissive material won't98/// typically light up surrounding areas like a light source**,99/// it just adds a value to the color seen on screen.100pub emissive: LinearRgba,101102/// The weight in which the camera exposure influences the emissive color.103/// A value of `0.0` means the emissive color is not affected by the camera exposure.104/// In opposition, a value of `1.0` means the emissive color is multiplied by the camera exposure.105///106/// Defaults to `0.0`107pub emissive_exposure_weight: f32,108109/// The UV channel to use for the [`StandardMaterial::emissive_texture`].110///111/// Defaults to [`UvChannel::Uv0`].112pub emissive_channel: UvChannel,113114/// The emissive map, multiplies pixels with [`emissive`]115/// to get the final "emitting" color of a surface.116///117/// This color is multiplied by [`emissive`] to get the final emitted color.118/// Meaning that you should set [`emissive`] to [`Color::WHITE`]119/// if you want to use the full range of color of the emissive texture.120///121/// [`emissive`]: StandardMaterial::emissive122#[texture(3)]123#[sampler(4)]124#[dependency]125pub emissive_texture: Option<Handle<Image>>,126127/// Linear perceptual roughness, clamped to `[0.089, 1.0]` in the shader.128///129/// Defaults to `0.5`.130///131/// Low values result in a "glossy" material with specular highlights,132/// while values close to `1` result in rough materials.133///134/// If used together with a roughness/metallic texture, this is factored into the final base135/// color as `roughness * roughness_texture_value`.136///137/// 0.089 is the minimum floating point value that won't be rounded down to 0 in the138/// calculations used.139// Technically for 32-bit floats, 0.045 could be used.140// See <https://google.github.io/filament/Filament.html#materialsystem/parameterization/>141pub perceptual_roughness: f32,142143/// How "metallic" the material appears, within `[0.0, 1.0]`.144///145/// This should be set to 0.0 for dielectric materials or 1.0 for metallic materials.146/// For a hybrid surface such as corroded metal, you may need to use in-between values.147///148/// Defaults to `0.00`, for dielectric.149///150/// If used together with a roughness/metallic texture, this is factored into the final base151/// color as `metallic * metallic_texture_value`.152pub metallic: f32,153154/// The UV channel to use for the [`StandardMaterial::metallic_roughness_texture`].155///156/// Defaults to [`UvChannel::Uv0`].157pub metallic_roughness_channel: UvChannel,158159/// Metallic and roughness maps, stored as a single texture.160///161/// The blue channel contains metallic values,162/// and the green channel contains the roughness values.163/// Other channels are unused.164///165/// Those values are multiplied by the scalar ones of the material,166/// see [`metallic`] and [`perceptual_roughness`] for details.167///168/// Note that with the default values of [`metallic`] and [`perceptual_roughness`],169/// setting this texture has no effect. If you want to exclusively use the170/// `metallic_roughness_texture` values for your material, make sure to set [`metallic`]171/// and [`perceptual_roughness`] to `1.0`.172///173/// [`metallic`]: StandardMaterial::metallic174/// [`perceptual_roughness`]: StandardMaterial::perceptual_roughness175#[texture(5)]176#[sampler(6)]177#[dependency]178pub metallic_roughness_texture: Option<Handle<Image>>,179180/// Specular intensity for non-metals on a linear scale of `[0.0, 1.0]`.181///182/// Use the value as a way to control the intensity of the183/// specular highlight of the material, i.e. how reflective is the material,184/// rather than the physical property "reflectance."185///186/// Set to `0.0`, no specular highlight is visible, the highlight is strongest187/// when `reflectance` is set to `1.0`.188///189/// Defaults to `0.5` which is mapped to 4% reflectance in the shader.190#[doc(alias = "specular_intensity")]191pub reflectance: f32,192193/// A color with which to modulate the [`StandardMaterial::reflectance`] for194/// non-metals.195///196/// The specular highlights and reflection are tinted with this color. Note197/// that it has no effect for non-metals.198///199/// This feature is currently unsupported in the deferred rendering path, in200/// order to reduce the size of the geometry buffers.201///202/// Defaults to [`Color::WHITE`].203#[doc(alias = "specular_color")]204pub specular_tint: Color,205206/// The amount of light transmitted _diffusely_ through the material (i.e. “translucency”).207///208/// Implemented as a second, flipped [Lambertian diffuse](https://en.wikipedia.org/wiki/Lambertian_reflectance) lobe,209/// which provides an inexpensive but plausible approximation of translucency for thin dielectric objects (e.g. paper,210/// leaves, some fabrics) or thicker volumetric materials with short scattering distances (e.g. porcelain, wax).211///212/// For specular transmission usecases with refraction (e.g. glass) use the [`StandardMaterial::specular_transmission`] and213/// [`StandardMaterial::ior`] properties instead.214///215/// - When set to `0.0` (the default) no diffuse light is transmitted;216/// - When set to `1.0` all diffuse light is transmitted through the material;217/// - Values higher than `0.5` will cause more diffuse light to be transmitted than reflected, resulting in a “darker”218/// appearance on the side facing the light than the opposite side. (e.g. plant leaves)219///220/// ## Notes221///222/// - The material's [`StandardMaterial::base_color`] also modulates the transmitted light;223/// - To receive transmitted shadows on the diffuse transmission lobe (i.e. the “backside”) of the material,224/// use the [`TransmittedShadowReceiver`](bevy_light::TransmittedShadowReceiver) component.225#[doc(alias = "translucency")]226pub diffuse_transmission: f32,227228/// The UV channel to use for the [`StandardMaterial::diffuse_transmission_texture`].229///230/// Defaults to [`UvChannel::Uv0`].231#[cfg(feature = "pbr_transmission_textures")]232pub diffuse_transmission_channel: UvChannel,233234/// A map that modulates diffuse transmission via its alpha channel. Multiplied by [`StandardMaterial::diffuse_transmission`]235/// to obtain the final result.236///237/// **Important:** The [`StandardMaterial::diffuse_transmission`] property must be set to a value higher than 0.0,238/// or this texture won't have any effect.239#[cfg_attr(feature = "pbr_transmission_textures", texture(19))]240#[cfg_attr(feature = "pbr_transmission_textures", sampler(20))]241#[cfg(feature = "pbr_transmission_textures")]242pub diffuse_transmission_texture: Option<Handle<Image>>,243244/// The amount of light transmitted _specularly_ through the material (i.e. via refraction).245///246/// - When set to `0.0` (the default) no light is transmitted.247/// - When set to `1.0` all light is transmitted through the material.248///249/// The material's [`StandardMaterial::base_color`] also modulates the transmitted light.250///251/// **Note:** Typically used in conjunction with [`StandardMaterial::thickness`], [`StandardMaterial::ior`] and [`StandardMaterial::perceptual_roughness`].252///253/// ## Performance254///255/// Specular transmission is implemented as a relatively expensive screen-space effect that allows occluded objects to be seen through the material,256/// with distortion and blur effects.257///258/// - [`Camera3d::screen_space_specular_transmission_steps`](bevy_camera::Camera3d::screen_space_specular_transmission_steps) can be used to enable transmissive objects259/// to be seen through other transmissive objects, at the cost of additional draw calls and texture copies; (Use with caution!)260/// - If a simplified approximation of specular transmission using only environment map lighting is sufficient, consider setting261/// [`Camera3d::screen_space_specular_transmission_steps`](bevy_camera::Camera3d::screen_space_specular_transmission_steps) to `0`.262/// - If purely diffuse light transmission is needed, (i.e. “translucency”) consider using [`StandardMaterial::diffuse_transmission`] instead,263/// for a much less expensive effect.264/// - Specular transmission is rendered before alpha blending, so any material with [`AlphaMode::Blend`], [`AlphaMode::Premultiplied`], [`AlphaMode::Add`] or [`AlphaMode::Multiply`]265/// won't be visible through specular transmissive materials.266#[doc(alias = "refraction")]267pub specular_transmission: f32,268269/// The UV channel to use for the [`StandardMaterial::specular_transmission_texture`].270///271/// Defaults to [`UvChannel::Uv0`].272#[cfg(feature = "pbr_transmission_textures")]273pub specular_transmission_channel: UvChannel,274275/// A map that modulates specular transmission via its red channel. Multiplied by [`StandardMaterial::specular_transmission`]276/// to obtain the final result.277///278/// **Important:** The [`StandardMaterial::specular_transmission`] property must be set to a value higher than 0.0,279/// or this texture won't have any effect.280#[cfg_attr(feature = "pbr_transmission_textures", texture(15))]281#[cfg_attr(feature = "pbr_transmission_textures", sampler(16))]282#[cfg(feature = "pbr_transmission_textures")]283pub specular_transmission_texture: Option<Handle<Image>>,284285/// Thickness of the volume beneath the material surface.286///287/// When set to `0.0` (the default) the material appears as an infinitely-thin film,288/// transmitting light without distorting it.289///290/// When set to any other value, the material distorts light like a thick lens.291///292/// **Note:** Typically used in conjunction with [`StandardMaterial::specular_transmission`] and [`StandardMaterial::ior`], or with293/// [`StandardMaterial::diffuse_transmission`].294#[doc(alias = "volume")]295#[doc(alias = "thin_walled")]296pub thickness: f32,297298/// The UV channel to use for the [`StandardMaterial::thickness_texture`].299///300/// Defaults to [`UvChannel::Uv0`].301#[cfg(feature = "pbr_transmission_textures")]302pub thickness_channel: UvChannel,303304/// A map that modulates thickness via its green channel. Multiplied by [`StandardMaterial::thickness`]305/// to obtain the final result.306///307/// **Important:** The [`StandardMaterial::thickness`] property must be set to a value higher than 0.0,308/// or this texture won't have any effect.309#[cfg_attr(feature = "pbr_transmission_textures", texture(17))]310#[cfg_attr(feature = "pbr_transmission_textures", sampler(18))]311#[cfg(feature = "pbr_transmission_textures")]312pub thickness_texture: Option<Handle<Image>>,313314/// The [index of refraction](https://en.wikipedia.org/wiki/Refractive_index) of the material.315///316/// Defaults to 1.5.317///318/// | Material | Index of Refraction |319/// |:----------------|:---------------------|320/// | Vacuum | 1 |321/// | Air | 1.00 |322/// | Ice | 1.31 |323/// | Water | 1.33 |324/// | Eyes | 1.38 |325/// | Quartz | 1.46 |326/// | Olive Oil | 1.47 |327/// | Honey | 1.49 |328/// | Acrylic | 1.49 |329/// | Window Glass | 1.52 |330/// | Polycarbonate | 1.58 |331/// | Flint Glass | 1.69 |332/// | Ruby | 1.71 |333/// | Glycerine | 1.74 |334/// | Sapphire | 1.77 |335/// | Cubic Zirconia | 2.15 |336/// | Diamond | 2.42 |337/// | Moissanite | 2.65 |338///339/// **Note:** Typically used in conjunction with [`StandardMaterial::specular_transmission`] and [`StandardMaterial::thickness`].340#[doc(alias = "index_of_refraction")]341#[doc(alias = "refraction_index")]342#[doc(alias = "refractive_index")]343pub ior: f32,344345/// How far, on average, light travels through the volume beneath the material's346/// surface before being absorbed.347///348/// Defaults to [`f32::INFINITY`], i.e. light is never absorbed.349///350/// **Note:** To have any effect, must be used in conjunction with:351/// - [`StandardMaterial::attenuation_color`];352/// - [`StandardMaterial::thickness`];353/// - [`StandardMaterial::diffuse_transmission`] or [`StandardMaterial::specular_transmission`].354#[doc(alias = "absorption_distance")]355#[doc(alias = "extinction_distance")]356pub attenuation_distance: f32,357358/// The resulting (non-absorbed) color after white light travels through the attenuation distance.359///360/// Defaults to [`Color::WHITE`], i.e. no change.361///362/// **Note:** To have any effect, must be used in conjunction with:363/// - [`StandardMaterial::attenuation_distance`];364/// - [`StandardMaterial::thickness`];365/// - [`StandardMaterial::diffuse_transmission`] or [`StandardMaterial::specular_transmission`].366#[doc(alias = "absorption_color")]367#[doc(alias = "extinction_color")]368pub attenuation_color: Color,369370/// The UV channel to use for the [`StandardMaterial::normal_map_texture`].371///372/// Defaults to [`UvChannel::Uv0`].373pub normal_map_channel: UvChannel,374375/// Used to fake the lighting of bumps and dents on a material.376///377/// A typical usage would be faking cobblestones on a flat plane mesh in 3D.378///379/// # Notes380///381/// Normal mapping with `StandardMaterial` and the core bevy PBR shaders requires:382/// - A normal map texture383/// - Vertex UVs384/// - Vertex tangents385/// - Vertex normals386///387/// Tangents do not have to be stored in your model,388/// they can be generated using the [`Mesh::generate_tangents`] or389/// [`Mesh::with_generated_tangents`] methods.390/// If your material has a normal map, but still renders as a flat surface,391/// make sure your meshes have their tangents set.392///393/// [`Mesh::generate_tangents`]: bevy_mesh::Mesh::generate_tangents394/// [`Mesh::with_generated_tangents`]: bevy_mesh::Mesh::with_generated_tangents395///396/// # Usage397///398/// ```399/// # use bevy_asset::{AssetServer, Handle};400/// # use bevy_ecs::change_detection::Res;401/// # use bevy_image::{Image, ImageLoaderSettings};402/// #403/// fn load_normal_map(asset_server: Res<AssetServer>) {404/// let normal_handle: Handle<Image> = asset_server.load_with_settings(405/// "textures/parallax_example/cube_normal.png",406/// // The normal map texture is in linear color space. Lighting won't look correct407/// // if `is_srgb` is `true`, which is the default.408/// |settings: &mut ImageLoaderSettings| settings.is_srgb = false,409/// );410/// }411/// ```412#[texture(9)]413#[sampler(10)]414#[dependency]415pub normal_map_texture: Option<Handle<Image>>,416417/// Normal map textures authored for DirectX have their y-component flipped. Set this to flip418/// it to right-handed conventions.419pub flip_normal_map_y: bool,420421/// The UV channel to use for the [`StandardMaterial::occlusion_texture`].422///423/// Defaults to [`UvChannel::Uv0`].424pub occlusion_channel: UvChannel,425426/// Specifies the level of exposure to ambient light.427///428/// This is usually generated and stored automatically ("baked") by 3D-modeling software.429///430/// Typically, steep concave parts of a model (such as the armpit of a shirt) are darker,431/// because they have little exposure to light.432/// An occlusion map specifies those parts of the model that light doesn't reach well.433///434/// The material will be less lit in places where this texture is dark.435/// This is similar to ambient occlusion, but built into the model.436#[texture(7)]437#[sampler(8)]438#[dependency]439pub occlusion_texture: Option<Handle<Image>>,440441/// The UV channel to use for the [`StandardMaterial::specular_texture`].442///443/// Defaults to [`UvChannel::Uv0`].444#[cfg(feature = "pbr_specular_textures")]445pub specular_channel: UvChannel,446447/// A map that specifies reflectance for non-metallic materials.448///449/// Alpha values from [0.0, 1.0] in this texture are linearly mapped to450/// reflectance values of [0.0, 0.5] and multiplied by the constant451/// [`StandardMaterial::reflectance`] value. This follows the452/// `KHR_materials_specular` specification. The map will have no effect if453/// the material is fully metallic.454///455/// When using this map, you may wish to set the456/// [`StandardMaterial::reflectance`] value to 2.0 so that this map can457/// express the full [0.0, 1.0] range of values.458///459/// Note that, because the reflectance is stored in the alpha channel, and460/// the [`StandardMaterial::specular_tint_texture`] has no alpha value, it461/// may be desirable to pack the values together and supply the same462/// texture to both fields.463#[cfg_attr(feature = "pbr_specular_textures", texture(27))]464#[cfg_attr(feature = "pbr_specular_textures", sampler(28))]465#[cfg(feature = "pbr_specular_textures")]466pub specular_texture: Option<Handle<Image>>,467468/// The UV channel to use for the469/// [`StandardMaterial::specular_tint_texture`].470///471/// Defaults to [`UvChannel::Uv0`].472#[cfg(feature = "pbr_specular_textures")]473pub specular_tint_channel: UvChannel,474475/// A map that specifies color adjustment to be applied to the specular476/// reflection for non-metallic materials.477///478/// The RGB values of this texture modulate the479/// [`StandardMaterial::specular_tint`] value. See the documentation for480/// that field for more information.481///482/// Like the fixed specular tint value, this texture map isn't supported in483/// the deferred renderer.484#[cfg_attr(feature = "pbr_specular_textures", texture(29))]485#[cfg_attr(feature = "pbr_specular_textures", sampler(30))]486#[cfg(feature = "pbr_specular_textures")]487pub specular_tint_texture: Option<Handle<Image>>,488489/// An extra thin translucent layer on top of the main PBR layer. This is490/// typically used for painted surfaces.491///492/// This value specifies the strength of the layer, which affects how493/// visible the clearcoat layer will be.494///495/// Defaults to zero, specifying no clearcoat layer.496pub clearcoat: f32,497498/// The UV channel to use for the [`StandardMaterial::clearcoat_texture`].499///500/// Defaults to [`UvChannel::Uv0`].501#[cfg(feature = "pbr_multi_layer_material_textures")]502pub clearcoat_channel: UvChannel,503504/// An image texture that specifies the strength of the clearcoat layer in505/// the red channel. Values sampled from this texture are multiplied by the506/// main [`StandardMaterial::clearcoat`] factor.507///508/// As this is a non-color map, it must not be loaded as sRGB.509#[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(21))]510#[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(22))]511#[cfg(feature = "pbr_multi_layer_material_textures")]512pub clearcoat_texture: Option<Handle<Image>>,513514/// The roughness of the clearcoat material. This is specified in exactly515/// the same way as the [`StandardMaterial::perceptual_roughness`].516///517/// If the [`StandardMaterial::clearcoat`] value if zero, this has no518/// effect.519///520/// Defaults to 0.5.521pub clearcoat_perceptual_roughness: f32,522523/// The UV channel to use for the [`StandardMaterial::clearcoat_roughness_texture`].524///525/// Defaults to [`UvChannel::Uv0`].526#[cfg(feature = "pbr_multi_layer_material_textures")]527pub clearcoat_roughness_channel: UvChannel,528529/// An image texture that specifies the roughness of the clearcoat level in530/// the green channel. Values from this texture are multiplied by the main531/// [`StandardMaterial::clearcoat_perceptual_roughness`] factor.532///533/// As this is a non-color map, it must not be loaded as sRGB.534#[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(23))]535#[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(24))]536#[cfg(feature = "pbr_multi_layer_material_textures")]537pub clearcoat_roughness_texture: Option<Handle<Image>>,538539/// The UV channel to use for the [`StandardMaterial::clearcoat_normal_texture`].540///541/// Defaults to [`UvChannel::Uv0`].542#[cfg(feature = "pbr_multi_layer_material_textures")]543pub clearcoat_normal_channel: UvChannel,544545/// An image texture that specifies a normal map that is to be applied to546/// the clearcoat layer. This can be used to simulate, for example,547/// scratches on an outer layer of varnish. Normal maps are in the same548/// format as [`StandardMaterial::normal_map_texture`].549///550/// Note that, if a clearcoat normal map isn't specified, the main normal551/// map, if any, won't be applied to the clearcoat. If you want a normal map552/// that applies to both the main material and to the clearcoat, specify it553/// in both [`StandardMaterial::normal_map_texture`] and this field.554///555/// As this is a non-color map, it must not be loaded as sRGB.556#[cfg_attr(feature = "pbr_multi_layer_material_textures", texture(25))]557#[cfg_attr(feature = "pbr_multi_layer_material_textures", sampler(26))]558#[cfg(feature = "pbr_multi_layer_material_textures")]559pub clearcoat_normal_texture: Option<Handle<Image>>,560561/// Increases the roughness along a specific direction, so that the specular562/// highlight will be stretched instead of being a circular lobe.563///564/// This value ranges from 0 (perfectly circular) to 1 (maximally565/// stretched). The default direction (corresponding to a566/// [`StandardMaterial::anisotropy_rotation`] of 0) aligns with the567/// *tangent* of the mesh; thus mesh tangents must be specified in order for568/// this parameter to have any meaning. The direction can be changed using569/// the [`StandardMaterial::anisotropy_rotation`] parameter.570///571/// This is typically used for modeling surfaces such as brushed metal and572/// hair, in which one direction of the surface but not the other is smooth.573///574/// See the [`KHR_materials_anisotropy` specification] for more details.575///576/// [`KHR_materials_anisotropy` specification]:577/// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md578pub anisotropy_strength: f32,579580/// The direction of increased roughness, in radians relative to the mesh581/// tangent.582///583/// This parameter causes the roughness to vary according to the584/// [`StandardMaterial::anisotropy_strength`]. The rotation is applied in585/// tangent-bitangent space; thus, mesh tangents must be present for this586/// parameter to have any meaning.587///588/// This parameter has no effect if589/// [`StandardMaterial::anisotropy_strength`] is zero. Its value can590/// optionally be adjusted across the mesh with the591/// [`StandardMaterial::anisotropy_texture`].592///593/// See the [`KHR_materials_anisotropy` specification] for more details.594///595/// [`KHR_materials_anisotropy` specification]:596/// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md597pub anisotropy_rotation: f32,598599/// The UV channel to use for the [`StandardMaterial::anisotropy_texture`].600///601/// Defaults to [`UvChannel::Uv0`].602#[cfg(feature = "pbr_anisotropy_texture")]603pub anisotropy_channel: UvChannel,604605/// An image texture that allows the606/// [`StandardMaterial::anisotropy_strength`] and607/// [`StandardMaterial::anisotropy_rotation`] to vary across the mesh.608///609/// The [`KHR_materials_anisotropy` specification] defines the format that610/// this texture must take. To summarize: the direction vector is encoded in611/// the red and green channels, while the strength is encoded in the blue612/// channels. For the direction vector, the red and green channels map the613/// color range [0, 1] to the vector range [-1, 1]. The direction vector614/// encoded in this texture modifies the default rotation direction in615/// tangent-bitangent space, before the616/// [`StandardMaterial::anisotropy_rotation`] parameter is applied. The617/// value in the blue channel is multiplied by the618/// [`StandardMaterial::anisotropy_strength`] value to produce the final619/// anisotropy strength.620///621/// As the texel values don't represent colors, this texture must be in622/// linear color space, not sRGB.623///624/// [`KHR_materials_anisotropy` specification]:625/// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md626#[cfg_attr(feature = "pbr_anisotropy_texture", texture(13))]627#[cfg_attr(feature = "pbr_anisotropy_texture", sampler(14))]628#[cfg(feature = "pbr_anisotropy_texture")]629pub anisotropy_texture: Option<Handle<Image>>,630631/// Support two-sided lighting by automatically flipping the normals for "back" faces632/// within the PBR lighting shader.633///634/// Defaults to `false`.635/// This does not automatically configure backface culling,636/// which can be done via `cull_mode`.637pub double_sided: bool,638639/// Whether to cull the "front", "back" or neither side of a mesh.640/// If set to `None`, the two sides of the mesh are visible.641///642/// Defaults to `Some(Face::Back)`.643/// In bevy, the order of declaration of a triangle's vertices644/// in [`Mesh`] defines the triangle's front face.645///646/// When a triangle is in a viewport,647/// if its vertices appear counter-clockwise from the viewport's perspective,648/// then the viewport is seeing the triangle's front face.649/// Conversely, if the vertices appear clockwise, you are seeing the back face.650///651/// In short, in bevy, front faces winds counter-clockwise.652///653/// Your 3D editing software should manage all of that.654///655/// [`Mesh`]: bevy_mesh::Mesh656// TODO: include this in reflection somehow (maybe via remote types like serde https://serde.rs/remote-derive.html)657#[reflect(ignore, clone)]658pub cull_mode: Option<Face>,659660/// Whether to apply only the base color to this material.661///662/// Normals, occlusion textures, roughness, metallic, reflectance, emissive,663/// shadows, alpha mode and ambient light are ignored if this is set to `true`.664pub unlit: bool,665666/// Whether to enable fog for this material.667pub fog_enabled: bool,668669/// How to apply the alpha channel of the `base_color_texture`.670///671/// See [`AlphaMode`] for details. Defaults to [`AlphaMode::Opaque`].672pub alpha_mode: AlphaMode,673674/// Adjust rendered depth.675///676/// A material with a positive depth bias will render closer to the677/// camera while negative values cause the material to render behind678/// other objects. This is independent of the viewport.679///680/// `depth_bias` affects render ordering and depth write operations681/// using the `wgpu::DepthBiasState::Constant` field.682///683/// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting684pub depth_bias: f32,685686/// The depth map used for [parallax mapping].687///688/// It is a grayscale image where white represents bottom and black the top.689/// If this field is set, bevy will apply [parallax mapping].690/// Parallax mapping, unlike simple normal maps, will move the texture691/// coordinate according to the current perspective,692/// giving actual depth to the texture.693///694/// The visual result is similar to a displacement map,695/// but does not require additional geometry.696///697/// Use the [`parallax_depth_scale`] field to control the depth of the parallax.698///699/// ## Limitations700///701/// - It will look weird on bent/non-planar surfaces.702/// - The depth of the pixel does not reflect its visual position, resulting703/// in artifacts for depth-dependent features such as fog or SSAO.704/// - For the same reason, the geometry silhouette will always be705/// the one of the actual geometry, not the parallaxed version, resulting706/// in awkward looks on intersecting parallaxed surfaces.707///708/// ## Performance709///710/// Parallax mapping requires multiple texture lookups, proportional to711/// [`max_parallax_layer_count`], which might be costly.712///713/// Use the [`parallax_mapping_method`] and [`max_parallax_layer_count`] fields714/// to tweak the shader, trading graphical quality for performance.715///716/// To improve performance, set your `depth_map`'s [`Image::sampler`]717/// filter mode to `FilterMode::Nearest`, as [this paper] indicates, it improves718/// performance a bit.719///720/// To reduce artifacts, avoid steep changes in depth, blurring the depth721/// map helps with this.722///723/// Larger depth maps haves a disproportionate performance impact.724///725/// [this paper]: https://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf726/// [parallax mapping]: https://en.wikipedia.org/wiki/Parallax_mapping727/// [`parallax_depth_scale`]: StandardMaterial::parallax_depth_scale728/// [`parallax_mapping_method`]: StandardMaterial::parallax_mapping_method729/// [`max_parallax_layer_count`]: StandardMaterial::max_parallax_layer_count730#[texture(11)]731#[sampler(12)]732#[dependency]733pub depth_map: Option<Handle<Image>>,734735/// How deep the offset introduced by the depth map should be.736///737/// Default is `0.1`, anything over that value may look distorted.738/// Lower values lessen the effect.739///740/// The depth is relative to texture size. This means that if your texture741/// occupies a surface of `1` world unit, and `parallax_depth_scale` is `0.1`, then742/// the in-world depth will be of `0.1` world units.743/// If the texture stretches for `10` world units, then the final depth744/// will be of `1` world unit.745pub parallax_depth_scale: f32,746747/// Which parallax mapping method to use.748///749/// We recommend that all objects use the same [`ParallaxMappingMethod`], to avoid750/// duplicating and running two shaders.751pub parallax_mapping_method: ParallaxMappingMethod,752753/// In how many layers to split the depth maps for parallax mapping.754///755/// If you are seeing jaggy edges, increase this value.756/// However, this incurs a performance cost.757///758/// Dependent on the situation, switching to [`ParallaxMappingMethod::Relief`]759/// and keeping this value low might have better performance than increasing the760/// layer count while using [`ParallaxMappingMethod::Occlusion`].761///762/// Default is `16.0`.763pub max_parallax_layer_count: f32,764765/// The exposure (brightness) level of the lightmap, if present.766pub lightmap_exposure: f32,767768/// Render method used for opaque materials. (Where `alpha_mode` is [`AlphaMode::Opaque`] or [`AlphaMode::Mask`])769pub opaque_render_method: OpaqueRendererMethod,770771/// Used for selecting the deferred lighting pass for deferred materials.772/// Default is [`DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID`] for default773/// PBR deferred lighting pass. Ignored in the case of forward materials.774pub deferred_lighting_pass_id: u8,775776/// The transform applied to the UVs corresponding to `ATTRIBUTE_UV_0` on the mesh before sampling. Default is identity.777pub uv_transform: Affine2,778}779780impl StandardMaterial {781/// Horizontal flipping transform782///783/// Multiplying this with another Affine2 returns transformation with horizontally flipped texture coords784pub const FLIP_HORIZONTAL: Affine2 = Affine2 {785matrix2: Mat2::from_cols(Vec2::new(-1.0, 0.0), Vec2::Y),786translation: Vec2::X,787};788789/// Vertical flipping transform790///791/// Multiplying this with another Affine2 returns transformation with vertically flipped texture coords792pub const FLIP_VERTICAL: Affine2 = Affine2 {793matrix2: Mat2::from_cols(Vec2::X, Vec2::new(0.0, -1.0)),794translation: Vec2::Y,795};796797/// Flipping X 3D transform798///799/// Multiplying this with another Affine3 returns transformation with flipped X coords800pub const FLIP_X: Affine3 = Affine3 {801matrix3: Mat3::from_cols(Vec3::new(-1.0, 0.0, 0.0), Vec3::Y, Vec3::Z),802translation: Vec3::X,803};804805/// Flipping Y 3D transform806///807/// Multiplying this with another Affine3 returns transformation with flipped Y coords808pub const FLIP_Y: Affine3 = Affine3 {809matrix3: Mat3::from_cols(Vec3::X, Vec3::new(0.0, -1.0, 0.0), Vec3::Z),810translation: Vec3::Y,811};812813/// Flipping Z 3D transform814///815/// Multiplying this with another Affine3 returns transformation with flipped Z coords816pub const FLIP_Z: Affine3 = Affine3 {817matrix3: Mat3::from_cols(Vec3::X, Vec3::Y, Vec3::new(0.0, 0.0, -1.0)),818translation: Vec3::Z,819};820821/// Flip the texture coordinates of the material.822pub fn flip(&mut self, horizontal: bool, vertical: bool) {823if horizontal {824// Multiplication of `Affine2` is order dependent, which is why825// we do not use the `*=` operator.826self.uv_transform = Self::FLIP_HORIZONTAL * self.uv_transform;827}828if vertical {829self.uv_transform = Self::FLIP_VERTICAL * self.uv_transform;830}831}832833/// Consumes the material and returns a material with flipped texture coordinates834pub fn flipped(mut self, horizontal: bool, vertical: bool) -> Self {835self.flip(horizontal, vertical);836self837}838839/// Creates a new material from a given color840pub fn from_color(color: impl Into<Color>) -> Self {841Self::from(color.into())842}843}844845impl Default for StandardMaterial {846fn default() -> Self {847StandardMaterial {848// White because it gets multiplied with texture values if someone uses849// a texture.850base_color: Color::WHITE,851base_color_channel: UvChannel::Uv0,852base_color_texture: None,853emissive: LinearRgba::BLACK,854emissive_exposure_weight: 0.0,855emissive_channel: UvChannel::Uv0,856emissive_texture: None,857// Matches Blender's default roughness.858perceptual_roughness: 0.5,859// Metallic should generally be set to 0.0 or 1.0.860metallic: 0.0,861metallic_roughness_channel: UvChannel::Uv0,862metallic_roughness_texture: None,863// Minimum real-world reflectance is 2%, most materials between 2-5%864// Expressed in a linear scale and equivalent to 4% reflectance see865// <https://google.github.io/filament/Material%20Properties.pdf>866reflectance: 0.5,867diffuse_transmission: 0.0,868#[cfg(feature = "pbr_transmission_textures")]869diffuse_transmission_channel: UvChannel::Uv0,870#[cfg(feature = "pbr_transmission_textures")]871diffuse_transmission_texture: None,872specular_transmission: 0.0,873#[cfg(feature = "pbr_transmission_textures")]874specular_transmission_channel: UvChannel::Uv0,875#[cfg(feature = "pbr_transmission_textures")]876specular_transmission_texture: None,877thickness: 0.0,878#[cfg(feature = "pbr_transmission_textures")]879thickness_channel: UvChannel::Uv0,880#[cfg(feature = "pbr_transmission_textures")]881thickness_texture: None,882ior: 1.5,883attenuation_color: Color::WHITE,884attenuation_distance: f32::INFINITY,885occlusion_channel: UvChannel::Uv0,886occlusion_texture: None,887normal_map_channel: UvChannel::Uv0,888normal_map_texture: None,889#[cfg(feature = "pbr_specular_textures")]890specular_channel: UvChannel::Uv0,891#[cfg(feature = "pbr_specular_textures")]892specular_texture: None,893specular_tint: Color::WHITE,894#[cfg(feature = "pbr_specular_textures")]895specular_tint_channel: UvChannel::Uv0,896#[cfg(feature = "pbr_specular_textures")]897specular_tint_texture: None,898clearcoat: 0.0,899clearcoat_perceptual_roughness: 0.5,900#[cfg(feature = "pbr_multi_layer_material_textures")]901clearcoat_channel: UvChannel::Uv0,902#[cfg(feature = "pbr_multi_layer_material_textures")]903clearcoat_texture: None,904#[cfg(feature = "pbr_multi_layer_material_textures")]905clearcoat_roughness_channel: UvChannel::Uv0,906#[cfg(feature = "pbr_multi_layer_material_textures")]907clearcoat_roughness_texture: None,908#[cfg(feature = "pbr_multi_layer_material_textures")]909clearcoat_normal_channel: UvChannel::Uv0,910#[cfg(feature = "pbr_multi_layer_material_textures")]911clearcoat_normal_texture: None,912anisotropy_strength: 0.0,913anisotropy_rotation: 0.0,914#[cfg(feature = "pbr_anisotropy_texture")]915anisotropy_channel: UvChannel::Uv0,916#[cfg(feature = "pbr_anisotropy_texture")]917anisotropy_texture: None,918flip_normal_map_y: false,919double_sided: false,920cull_mode: Some(Face::Back),921unlit: false,922fog_enabled: true,923alpha_mode: AlphaMode::Opaque,924depth_bias: 0.0,925depth_map: None,926parallax_depth_scale: 0.1,927max_parallax_layer_count: 16.0,928lightmap_exposure: 1.0,929parallax_mapping_method: ParallaxMappingMethod::Occlusion,930opaque_render_method: OpaqueRendererMethod::Auto,931deferred_lighting_pass_id: DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID,932uv_transform: Affine2::IDENTITY,933}934}935}936937impl From<Color> for StandardMaterial {938fn from(color: Color) -> Self {939StandardMaterial {940base_color: color,941alpha_mode: if color.alpha() < 1.0 {942AlphaMode::Blend943} else {944AlphaMode::Opaque945},946..Default::default()947}948}949}950951impl From<Handle<Image>> for StandardMaterial {952fn from(texture: Handle<Image>) -> Self {953StandardMaterial {954base_color_texture: Some(texture),955..Default::default()956}957}958}959960// NOTE: These must match the bit flags in bevy_pbr/src/render/pbr_types.wgsl!961bitflags::bitflags! {962/// Bitflags info about the material a shader is currently rendering.963/// This is accessible in the shader in the [`StandardMaterialUniform`]964#[repr(transparent)]965pub struct StandardMaterialFlags: u32 {966const BASE_COLOR_TEXTURE = 1 << 0;967const EMISSIVE_TEXTURE = 1 << 1;968const METALLIC_ROUGHNESS_TEXTURE = 1 << 2;969const OCCLUSION_TEXTURE = 1 << 3;970const DOUBLE_SIDED = 1 << 4;971const UNLIT = 1 << 5;972const TWO_COMPONENT_NORMAL_MAP = 1 << 6;973const FLIP_NORMAL_MAP_Y = 1 << 7;974const FOG_ENABLED = 1 << 8;975const DEPTH_MAP = 1 << 9; // Used for parallax mapping976const SPECULAR_TRANSMISSION_TEXTURE = 1 << 10;977const THICKNESS_TEXTURE = 1 << 11;978const DIFFUSE_TRANSMISSION_TEXTURE = 1 << 12;979const ATTENUATION_ENABLED = 1 << 13;980const CLEARCOAT_TEXTURE = 1 << 14;981const CLEARCOAT_ROUGHNESS_TEXTURE = 1 << 15;982const CLEARCOAT_NORMAL_TEXTURE = 1 << 16;983const ANISOTROPY_TEXTURE = 1 << 17;984const SPECULAR_TEXTURE = 1 << 18;985const SPECULAR_TINT_TEXTURE = 1 << 19;986const ALPHA_MODE_RESERVED_BITS = Self::ALPHA_MODE_MASK_BITS << Self::ALPHA_MODE_SHIFT_BITS; // ← Bitmask reserving bits for the `AlphaMode`987const ALPHA_MODE_OPAQUE = 0 << Self::ALPHA_MODE_SHIFT_BITS; // ← Values are just sequential values bitshifted into988const ALPHA_MODE_MASK = 1 << Self::ALPHA_MODE_SHIFT_BITS; // the bitmask, and can range from 0 to 7.989const ALPHA_MODE_BLEND = 2 << Self::ALPHA_MODE_SHIFT_BITS; //990const ALPHA_MODE_PREMULTIPLIED = 3 << Self::ALPHA_MODE_SHIFT_BITS; //991const ALPHA_MODE_ADD = 4 << Self::ALPHA_MODE_SHIFT_BITS; // Right now only values 0–5 are used, which still gives992const ALPHA_MODE_MULTIPLY = 5 << Self::ALPHA_MODE_SHIFT_BITS; // ← us "room" for two more modes without adding more bits993const ALPHA_MODE_ALPHA_TO_COVERAGE = 6 << Self::ALPHA_MODE_SHIFT_BITS;994const NONE = 0;995const UNINITIALIZED = 0xFFFF;996}997}998999impl StandardMaterialFlags {1000const ALPHA_MODE_MASK_BITS: u32 = 0b111;1001const ALPHA_MODE_SHIFT_BITS: u32 = 32 - Self::ALPHA_MODE_MASK_BITS.count_ones();1002}10031004/// The GPU representation of the uniform data of a [`StandardMaterial`].1005#[derive(Clone, Default, ShaderType)]1006pub struct StandardMaterialUniform {1007/// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything1008/// in between.1009pub base_color: Vec4,1010// Use a color for user-friendliness even though we technically don't use the alpha channel1011// Might be used in the future for exposure correction in HDR1012pub emissive: Vec4,1013/// Color white light takes after traveling through the attenuation distance underneath the material surface1014pub attenuation_color: Vec4,1015/// The transform applied to the UVs corresponding to `ATTRIBUTE_UV_0` on the mesh before sampling. Default is identity.1016pub uv_transform: Mat3,1017/// Specular intensity for non-metals on a linear scale of [0.0, 1.0]1018/// defaults to 0.5 which is mapped to 4% reflectance in the shader1019pub reflectance: Vec3,1020/// Linear perceptual roughness, clamped to [0.089, 1.0] in the shader1021/// Defaults to minimum of 0.0891022pub roughness: f32,1023/// From [0.0, 1.0], dielectric to pure metallic1024pub metallic: f32,1025/// Amount of diffuse light transmitted through the material1026pub diffuse_transmission: f32,1027/// Amount of specular light transmitted through the material1028pub specular_transmission: f32,1029/// Thickness of the volume underneath the material surface1030pub thickness: f32,1031/// Index of Refraction1032pub ior: f32,1033/// How far light travels through the volume underneath the material surface before being absorbed1034pub attenuation_distance: f32,1035pub clearcoat: f32,1036pub clearcoat_perceptual_roughness: f32,1037pub anisotropy_strength: f32,1038pub anisotropy_rotation: Vec2,1039/// The [`StandardMaterialFlags`] accessible in the `wgsl` shader.1040pub flags: u32,1041/// When the alpha mode mask flag is set, any base color alpha above this cutoff means fully opaque,1042/// and any below means fully transparent.1043pub alpha_cutoff: f32,1044/// The depth of the [`StandardMaterial::depth_map`] to apply.1045pub parallax_depth_scale: f32,1046/// In how many layers to split the depth maps for Steep parallax mapping.1047///1048/// If your `parallax_depth_scale` is >0.1 and you are seeing jaggy edges,1049/// increase this value. However, this incurs a performance cost.1050pub max_parallax_layer_count: f32,1051/// The exposure (brightness) level of the lightmap, if present.1052pub lightmap_exposure: f32,1053/// Using [`ParallaxMappingMethod::Relief`], how many additional1054/// steps to use at most to find the depth value.1055pub max_relief_mapping_search_steps: u32,1056/// ID for specifying which deferred lighting pass should be used for rendering this material, if any.1057pub deferred_lighting_pass_id: u32,1058}10591060impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {1061fn as_bind_group_shader_type(1062&self,1063images: &RenderAssets<GpuImage>,1064) -> StandardMaterialUniform {1065let mut flags = StandardMaterialFlags::NONE;1066if self.base_color_texture.is_some() {1067flags |= StandardMaterialFlags::BASE_COLOR_TEXTURE;1068}1069if self.emissive_texture.is_some() {1070flags |= StandardMaterialFlags::EMISSIVE_TEXTURE;1071}1072if self.metallic_roughness_texture.is_some() {1073flags |= StandardMaterialFlags::METALLIC_ROUGHNESS_TEXTURE;1074}1075if self.occlusion_texture.is_some() {1076flags |= StandardMaterialFlags::OCCLUSION_TEXTURE;1077}1078if self.double_sided {1079flags |= StandardMaterialFlags::DOUBLE_SIDED;1080}1081if self.unlit {1082flags |= StandardMaterialFlags::UNLIT;1083}1084if self.fog_enabled {1085flags |= StandardMaterialFlags::FOG_ENABLED;1086}1087if self.depth_map.is_some() {1088flags |= StandardMaterialFlags::DEPTH_MAP;1089}1090#[cfg(feature = "pbr_transmission_textures")]1091{1092if self.specular_transmission_texture.is_some() {1093flags |= StandardMaterialFlags::SPECULAR_TRANSMISSION_TEXTURE;1094}1095if self.thickness_texture.is_some() {1096flags |= StandardMaterialFlags::THICKNESS_TEXTURE;1097}1098if self.diffuse_transmission_texture.is_some() {1099flags |= StandardMaterialFlags::DIFFUSE_TRANSMISSION_TEXTURE;1100}1101}11021103#[cfg(feature = "pbr_anisotropy_texture")]1104{1105if self.anisotropy_texture.is_some() {1106flags |= StandardMaterialFlags::ANISOTROPY_TEXTURE;1107}1108}11091110#[cfg(feature = "pbr_specular_textures")]1111{1112if self.specular_texture.is_some() {1113flags |= StandardMaterialFlags::SPECULAR_TEXTURE;1114}1115if self.specular_tint_texture.is_some() {1116flags |= StandardMaterialFlags::SPECULAR_TINT_TEXTURE;1117}1118}11191120#[cfg(feature = "pbr_multi_layer_material_textures")]1121{1122if self.clearcoat_texture.is_some() {1123flags |= StandardMaterialFlags::CLEARCOAT_TEXTURE;1124}1125if self.clearcoat_roughness_texture.is_some() {1126flags |= StandardMaterialFlags::CLEARCOAT_ROUGHNESS_TEXTURE;1127}1128if self.clearcoat_normal_texture.is_some() {1129flags |= StandardMaterialFlags::CLEARCOAT_NORMAL_TEXTURE;1130}1131}11321133let has_normal_map = self.normal_map_texture.is_some();1134if has_normal_map {1135let normal_map_id = self.normal_map_texture.as_ref().map(Handle::id).unwrap();1136if let Some(texture) = images.get(normal_map_id) {1137match texture.texture_format {1138// All 2-component unorm formats1139TextureFormat::Rg8Unorm1140| TextureFormat::Rg16Unorm1141| TextureFormat::Bc5RgUnorm1142| TextureFormat::EacRg11Unorm => {1143flags |= StandardMaterialFlags::TWO_COMPONENT_NORMAL_MAP;1144}1145_ => {}1146}1147}1148if self.flip_normal_map_y {1149flags |= StandardMaterialFlags::FLIP_NORMAL_MAP_Y;1150}1151}1152// NOTE: 0.5 is from the glTF default - do we want this?1153let mut alpha_cutoff = 0.5;1154match self.alpha_mode {1155AlphaMode::Opaque => flags |= StandardMaterialFlags::ALPHA_MODE_OPAQUE,1156AlphaMode::Mask(c) => {1157alpha_cutoff = c;1158flags |= StandardMaterialFlags::ALPHA_MODE_MASK;1159}1160AlphaMode::Blend => flags |= StandardMaterialFlags::ALPHA_MODE_BLEND,1161AlphaMode::Premultiplied => flags |= StandardMaterialFlags::ALPHA_MODE_PREMULTIPLIED,1162AlphaMode::Add => flags |= StandardMaterialFlags::ALPHA_MODE_ADD,1163AlphaMode::Multiply => flags |= StandardMaterialFlags::ALPHA_MODE_MULTIPLY,1164AlphaMode::AlphaToCoverage => {1165flags |= StandardMaterialFlags::ALPHA_MODE_ALPHA_TO_COVERAGE;1166}1167};11681169if self.attenuation_distance.is_finite() {1170flags |= StandardMaterialFlags::ATTENUATION_ENABLED;1171}11721173let mut emissive = self.emissive.to_vec4();1174emissive[3] = self.emissive_exposure_weight;11751176// Doing this up front saves having to do this repeatedly in the fragment shader.1177let anisotropy_rotation = Vec2::from_angle(self.anisotropy_rotation);11781179StandardMaterialUniform {1180base_color: LinearRgba::from(self.base_color).to_vec4(),1181emissive,1182roughness: self.perceptual_roughness,1183metallic: self.metallic,1184reflectance: LinearRgba::from(self.specular_tint).to_vec3() * self.reflectance,1185clearcoat: self.clearcoat,1186clearcoat_perceptual_roughness: self.clearcoat_perceptual_roughness,1187anisotropy_strength: self.anisotropy_strength,1188anisotropy_rotation,1189diffuse_transmission: self.diffuse_transmission,1190specular_transmission: self.specular_transmission,1191thickness: self.thickness,1192ior: self.ior,1193attenuation_distance: self.attenuation_distance,1194attenuation_color: LinearRgba::from(self.attenuation_color)1195.to_f32_array()1196.into(),1197flags: flags.bits(),1198alpha_cutoff,1199parallax_depth_scale: self.parallax_depth_scale,1200max_parallax_layer_count: self.max_parallax_layer_count,1201lightmap_exposure: self.lightmap_exposure,1202max_relief_mapping_search_steps: self.parallax_mapping_method.max_steps(),1203deferred_lighting_pass_id: self.deferred_lighting_pass_id as u32,1204uv_transform: self.uv_transform.into(),1205}1206}1207}12081209bitflags! {1210/// The pipeline key for `StandardMaterial`, packed into 64 bits.1211#[repr(C)]1212#[derive(Clone, Copy, PartialEq, Eq, Hash)]1213pub struct StandardMaterialKey: u64 {1214const CULL_FRONT = 0x000001;1215const CULL_BACK = 0x000002;1216const NORMAL_MAP = 0x000004;1217const RELIEF_MAPPING = 0x000008;1218const DIFFUSE_TRANSMISSION = 0x000010;1219const SPECULAR_TRANSMISSION = 0x000020;1220const CLEARCOAT = 0x000040;1221const CLEARCOAT_NORMAL_MAP = 0x000080;1222const ANISOTROPY = 0x000100;1223const BASE_COLOR_UV = 0x000200;1224const EMISSIVE_UV = 0x000400;1225const METALLIC_ROUGHNESS_UV = 0x000800;1226const OCCLUSION_UV = 0x001000;1227const SPECULAR_TRANSMISSION_UV = 0x002000;1228const THICKNESS_UV = 0x004000;1229const DIFFUSE_TRANSMISSION_UV = 0x008000;1230const NORMAL_MAP_UV = 0x010000;1231const ANISOTROPY_UV = 0x020000;1232const CLEARCOAT_UV = 0x040000;1233const CLEARCOAT_ROUGHNESS_UV = 0x080000;1234const CLEARCOAT_NORMAL_UV = 0x100000;1235const SPECULAR_UV = 0x200000;1236const SPECULAR_TINT_UV = 0x400000;1237const DEPTH_BIAS = 0xffffffff_00000000;1238}1239}12401241const STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT: u64 = 32;12421243impl From<&StandardMaterial> for StandardMaterialKey {1244fn from(material: &StandardMaterial) -> Self {1245let mut key = StandardMaterialKey::empty();1246key.set(1247StandardMaterialKey::CULL_FRONT,1248material.cull_mode == Some(Face::Front),1249);1250key.set(1251StandardMaterialKey::CULL_BACK,1252material.cull_mode == Some(Face::Back),1253);1254key.set(1255StandardMaterialKey::NORMAL_MAP,1256material.normal_map_texture.is_some(),1257);1258key.set(1259StandardMaterialKey::RELIEF_MAPPING,1260matches!(1261material.parallax_mapping_method,1262ParallaxMappingMethod::Relief { .. }1263),1264);1265key.set(1266StandardMaterialKey::DIFFUSE_TRANSMISSION,1267material.diffuse_transmission > 0.0,1268);1269key.set(1270StandardMaterialKey::SPECULAR_TRANSMISSION,1271material.specular_transmission > 0.0,1272);12731274key.set(StandardMaterialKey::CLEARCOAT, material.clearcoat > 0.0);12751276#[cfg(feature = "pbr_multi_layer_material_textures")]1277key.set(1278StandardMaterialKey::CLEARCOAT_NORMAL_MAP,1279material.clearcoat > 0.0 && material.clearcoat_normal_texture.is_some(),1280);12811282key.set(1283StandardMaterialKey::ANISOTROPY,1284material.anisotropy_strength > 0.0,1285);12861287key.set(1288StandardMaterialKey::BASE_COLOR_UV,1289material.base_color_channel != UvChannel::Uv0,1290);12911292key.set(1293StandardMaterialKey::EMISSIVE_UV,1294material.emissive_channel != UvChannel::Uv0,1295);1296key.set(1297StandardMaterialKey::METALLIC_ROUGHNESS_UV,1298material.metallic_roughness_channel != UvChannel::Uv0,1299);1300key.set(1301StandardMaterialKey::OCCLUSION_UV,1302material.occlusion_channel != UvChannel::Uv0,1303);1304#[cfg(feature = "pbr_transmission_textures")]1305{1306key.set(1307StandardMaterialKey::SPECULAR_TRANSMISSION_UV,1308material.specular_transmission_channel != UvChannel::Uv0,1309);1310key.set(1311StandardMaterialKey::THICKNESS_UV,1312material.thickness_channel != UvChannel::Uv0,1313);1314key.set(1315StandardMaterialKey::DIFFUSE_TRANSMISSION_UV,1316material.diffuse_transmission_channel != UvChannel::Uv0,1317);1318}13191320key.set(1321StandardMaterialKey::NORMAL_MAP_UV,1322material.normal_map_channel != UvChannel::Uv0,1323);13241325#[cfg(feature = "pbr_anisotropy_texture")]1326{1327key.set(1328StandardMaterialKey::ANISOTROPY_UV,1329material.anisotropy_channel != UvChannel::Uv0,1330);1331}13321333#[cfg(feature = "pbr_specular_textures")]1334{1335key.set(1336StandardMaterialKey::SPECULAR_UV,1337material.specular_channel != UvChannel::Uv0,1338);1339key.set(1340StandardMaterialKey::SPECULAR_TINT_UV,1341material.specular_tint_channel != UvChannel::Uv0,1342);1343}13441345#[cfg(feature = "pbr_multi_layer_material_textures")]1346{1347key.set(1348StandardMaterialKey::CLEARCOAT_UV,1349material.clearcoat_channel != UvChannel::Uv0,1350);1351key.set(1352StandardMaterialKey::CLEARCOAT_ROUGHNESS_UV,1353material.clearcoat_roughness_channel != UvChannel::Uv0,1354);1355key.set(1356StandardMaterialKey::CLEARCOAT_NORMAL_UV,1357material.clearcoat_normal_channel != UvChannel::Uv0,1358);1359}13601361key.insert(StandardMaterialKey::from_bits_retain(1362// Casting to i32 first to ensure the full i32 range is preserved.1363// (wgpu expects the depth_bias as an i32 when this is extracted in a later step)1364(material.depth_bias as i32 as u64) << STANDARD_MATERIAL_KEY_DEPTH_BIAS_SHIFT,1365));1366key1367}1368}13691370impl Material for StandardMaterial {1371fn fragment_shader() -> ShaderRef {1372shader_ref(bevy_asset::embedded_path!("render/pbr.wgsl"))1373}13741375#[inline]1376fn alpha_mode(&self) -> AlphaMode {1377self.alpha_mode1378}13791380#[inline]1381fn opaque_render_method(&self) -> OpaqueRendererMethod {1382match self.opaque_render_method {1383// For now, diffuse transmission doesn't work under deferred rendering as we don't pack1384// the required data into the GBuffer. If this material is set to `Auto`, we report it as1385// `Forward` so that it's rendered correctly, even when the `DefaultOpaqueRendererMethod`1386// is set to `Deferred`.1387//1388// If the developer explicitly sets the `OpaqueRendererMethod` to `Deferred`, we assume1389// they know what they're doing and don't override it.1390OpaqueRendererMethod::Auto if self.diffuse_transmission > 0.0 => {1391OpaqueRendererMethod::Forward1392}1393other => other,1394}1395}13961397#[inline]1398fn depth_bias(&self) -> f32 {1399self.depth_bias1400}14011402#[inline]1403fn reads_view_transmission_texture(&self) -> bool {1404self.specular_transmission > 0.01405}14061407fn prepass_fragment_shader() -> ShaderRef {1408shader_ref(bevy_asset::embedded_path!("render/pbr_prepass.wgsl"))1409}14101411fn deferred_fragment_shader() -> ShaderRef {1412shader_ref(bevy_asset::embedded_path!("render/pbr.wgsl"))1413}14141415#[cfg(feature = "meshlet")]1416fn meshlet_mesh_fragment_shader() -> ShaderRef {1417Self::fragment_shader()1418}14191420#[cfg(feature = "meshlet")]1421fn meshlet_mesh_prepass_fragment_shader() -> ShaderRef {1422Self::prepass_fragment_shader()1423}14241425#[cfg(feature = "meshlet")]1426fn meshlet_mesh_deferred_fragment_shader() -> ShaderRef {1427Self::deferred_fragment_shader()1428}14291430fn specialize(1431_pipeline: &MaterialPipeline,1432descriptor: &mut RenderPipelineDescriptor,1433_layout: &MeshVertexBufferLayoutRef,1434key: MaterialPipelineKey<Self>,1435) -> Result<(), SpecializedMeshPipelineError> {1436if let Some(fragment) = descriptor.fragment.as_mut() {1437let shader_defs = &mut fragment.shader_defs;14381439for (flags, shader_def) in [1440(1441StandardMaterialKey::NORMAL_MAP,1442"STANDARD_MATERIAL_NORMAL_MAP",1443),1444(StandardMaterialKey::RELIEF_MAPPING, "RELIEF_MAPPING"),1445(1446StandardMaterialKey::DIFFUSE_TRANSMISSION,1447"STANDARD_MATERIAL_DIFFUSE_TRANSMISSION",1448),1449(1450StandardMaterialKey::SPECULAR_TRANSMISSION,1451"STANDARD_MATERIAL_SPECULAR_TRANSMISSION",1452),1453(1454StandardMaterialKey::DIFFUSE_TRANSMISSION1455| StandardMaterialKey::SPECULAR_TRANSMISSION,1456"STANDARD_MATERIAL_DIFFUSE_OR_SPECULAR_TRANSMISSION",1457),1458(1459StandardMaterialKey::CLEARCOAT,1460"STANDARD_MATERIAL_CLEARCOAT",1461),1462(1463StandardMaterialKey::CLEARCOAT_NORMAL_MAP,1464"STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP",1465),1466(1467StandardMaterialKey::ANISOTROPY,1468"STANDARD_MATERIAL_ANISOTROPY",1469),1470(1471StandardMaterialKey::BASE_COLOR_UV,1472"STANDARD_MATERIAL_BASE_COLOR_UV_B",1473),1474(1475StandardMaterialKey::EMISSIVE_UV,1476"STANDARD_MATERIAL_EMISSIVE_UV_B",1477),1478(1479StandardMaterialKey::METALLIC_ROUGHNESS_UV,1480"STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B",1481),1482(1483StandardMaterialKey::OCCLUSION_UV,1484"STANDARD_MATERIAL_OCCLUSION_UV_B",1485),1486(1487StandardMaterialKey::SPECULAR_TRANSMISSION_UV,1488"STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B",1489),1490(1491StandardMaterialKey::THICKNESS_UV,1492"STANDARD_MATERIAL_THICKNESS_UV_B",1493),1494(1495StandardMaterialKey::DIFFUSE_TRANSMISSION_UV,1496"STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B",1497),1498(1499StandardMaterialKey::NORMAL_MAP_UV,1500"STANDARD_MATERIAL_NORMAL_MAP_UV_B",1501),1502(1503StandardMaterialKey::CLEARCOAT_UV,1504"STANDARD_MATERIAL_CLEARCOAT_UV_B",1505),1506(1507StandardMaterialKey::CLEARCOAT_ROUGHNESS_UV,1508"STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B",1509),1510(1511StandardMaterialKey::CLEARCOAT_NORMAL_UV,1512"STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B",1513),1514(1515StandardMaterialKey::ANISOTROPY_UV,1516"STANDARD_MATERIAL_ANISOTROPY_UV_B",1517),1518(1519StandardMaterialKey::SPECULAR_UV,1520"STANDARD_MATERIAL_SPECULAR_UV_B",1521),1522(1523StandardMaterialKey::SPECULAR_TINT_UV,1524"STANDARD_MATERIAL_SPECULAR_TINT_UV_B",1525),1526] {1527if key.bind_group_data.intersects(flags) {1528shader_defs.push(shader_def.into());1529}1530}1531}15321533descriptor.primitive.cull_mode = if key1534.bind_group_data1535.contains(StandardMaterialKey::CULL_FRONT)1536{1537Some(Face::Front)1538} else if key.bind_group_data.contains(StandardMaterialKey::CULL_BACK) {1539Some(Face::Back)1540} else {1541None1542};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