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