1
1
use crate :: {
2
- AlphaMode , Material , MaterialPipeline , MaterialPipelineKey , PBR_PREPASS_SHADER_HANDLE ,
3
- PBR_SHADER_HANDLE ,
2
+ AlphaMode , Material , MaterialPipeline , MaterialPipelineKey , ParallaxMappingMethod ,
3
+ PBR_PREPASS_SHADER_HANDLE , PBR_SHADER_HANDLE ,
4
4
} ;
5
5
use bevy_asset:: Handle ;
6
6
use bevy_math:: Vec4 ;
@@ -231,6 +231,84 @@ pub struct StandardMaterial {
231
231
///
232
232
/// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting
233
233
pub depth_bias : f32 ,
234
+
235
+ /// The depth map used for [parallax mapping].
236
+ ///
237
+ /// It is a greyscale image where white represents bottom and black the top.
238
+ /// If this field is set, bevy will apply [parallax mapping].
239
+ /// Parallax mapping, unlike simple normal maps, will move the texture
240
+ /// coordinate according to the current perspective,
241
+ /// giving actual depth to the texture.
242
+ ///
243
+ /// The visual result is similar to a displacement map,
244
+ /// but does not require additional geometry.
245
+ ///
246
+ /// Use the [`parallax_depth`] field to control the depth of the parallax.
247
+ ///
248
+ /// ## Limitations
249
+ ///
250
+ /// - It will look weird on bent/non-planar surfaces.
251
+ /// - The depth of the pixel does not reflect its visual position, resulting
252
+ /// in artifacts for depth-dependent features such as fog or SSAO.
253
+ /// - For the same reason, the the geometry silhouette will always be
254
+ /// the one of the actual geometry, not the parallaxed version, resulting
255
+ /// in awkward looks on intersecting parallaxed surfaces.
256
+ ///
257
+ /// ## Performance
258
+ ///
259
+ /// Parallax mapping requires multiple texture lookups, proportional to
260
+ /// [`max_parallax_layer_count`], which might be costly.
261
+ ///
262
+ /// Use the [`parallax_mapping_method`] and [`max_parallax_layer_count`] fields
263
+ /// to tweak the shader, trading graphical quality for performance.
264
+ ///
265
+ /// To improve performance, set your `depth_map`'s [`Image::sampler_descriptor`]
266
+ /// filter mode to `FilterMode::Nearest`, as [this paper] indicates, it improves
267
+ /// performance a bit.
268
+ ///
269
+ /// To reduce artifacts, avoid steep changes in depth, blurring the depth
270
+ /// map helps with this.
271
+ ///
272
+ /// Larger depth maps haves a disproportionate performance impact.
273
+ ///
274
+ /// [this paper]: https://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf
275
+ /// [parallax mapping]: https://en.wikipedia.org/wiki/Parallax_mapping
276
+ /// [`parallax_depth`]: StandardMaterial::parallax_depth
277
+ /// [`parallax_mapping_method`]: StandardMaterial::parallax_mapping_method
278
+ /// [`max_parallax_layer_count`]: StandardMaterial::max_parallax_layer_count
279
+ #[ texture( 11 ) ]
280
+ #[ sampler( 12 ) ]
281
+ pub depth_map : Option < Handle < Image > > ,
282
+
283
+ /// How deep the offset introduced by the depth map should be.
284
+ ///
285
+ /// Default is `0.1`, anything over that value may look distorted.
286
+ /// Lower values lessen the effect.
287
+ ///
288
+ /// The depth is relative to texture size. This means that if your texture
289
+ /// occupies a surface of `1` world unit, and `parallax_depth` is `0.1`, then
290
+ /// the in-world depth will be of `0.1` world units.
291
+ /// If the texture stretches for `10` world units, then the final depth
292
+ /// will be of `1` world unit.
293
+ pub parallax_depth : f32 ,
294
+
295
+ /// Which parallax mapping method to use.
296
+ ///
297
+ /// We recommend that all objects use the same [`ParallaxMappingMethod`], to avoid
298
+ /// duplicating and running two shaders.
299
+ pub parallax_mapping_method : ParallaxMappingMethod ,
300
+
301
+ /// In how many layers to split the depth maps for parallax mapping.
302
+ ///
303
+ /// If you are seeing jaggy edges, increase this value.
304
+ /// However, this incurs a performance cost.
305
+ ///
306
+ /// Dependent on the situation, switching to [`ParallaxMappingMethod::ReliefMapping`]
307
+ /// and keeping this value low might have better performance than increasing the
308
+ /// layer count while using [`ParallaxMappingMethod::ParallaxOcclusionMapping`].
309
+ ///
310
+ /// Default is `16.0`.
311
+ pub max_parallax_layer_count : f32 ,
234
312
}
235
313
236
314
impl Default for StandardMaterial {
@@ -260,6 +338,10 @@ impl Default for StandardMaterial {
260
338
fog_enabled : true ,
261
339
alpha_mode : AlphaMode :: Opaque ,
262
340
depth_bias : 0.0 ,
341
+ depth_map : None ,
342
+ parallax_depth : 0.1 ,
343
+ max_parallax_layer_count : 16.0 ,
344
+ parallax_mapping_method : ParallaxMappingMethod :: ParallaxOcclusionMapping ,
263
345
}
264
346
}
265
347
}
@@ -302,6 +384,7 @@ bitflags::bitflags! {
302
384
const TWO_COMPONENT_NORMAL_MAP = ( 1 << 6 ) ;
303
385
const FLIP_NORMAL_MAP_Y = ( 1 << 7 ) ;
304
386
const FOG_ENABLED = ( 1 << 8 ) ;
387
+ const DEPTH_MAP = ( 1 << 9 ) ; // Used for parallax mapping
305
388
const ALPHA_MODE_RESERVED_BITS = ( Self :: ALPHA_MODE_MASK_BITS << Self :: ALPHA_MODE_SHIFT_BITS ) ; // ← Bitmask reserving bits for the `AlphaMode`
306
389
const ALPHA_MODE_OPAQUE = ( 0 << Self :: ALPHA_MODE_SHIFT_BITS ) ; // ← Values are just sequential values bitshifted into
307
390
const ALPHA_MODE_MASK = ( 1 << Self :: ALPHA_MODE_SHIFT_BITS ) ; // the bitmask, and can range from 0 to 7.
@@ -341,6 +424,13 @@ pub struct StandardMaterialUniform {
341
424
/// When the alpha mode mask flag is set, any base color alpha above this cutoff means fully opaque,
342
425
/// and any below means fully transparent.
343
426
pub alpha_cutoff : f32 ,
427
+ /// The depth of the [`StandardMaterial::depth_map`] to apply.
428
+ pub parallax_depth : f32 ,
429
+ /// In how many layers to split the depth maps for Steep parallax mapping.
430
+ ///
431
+ /// If your `parallax_depth` is >0.1 and you are seeing jaggy edges,
432
+ /// increase this value. However, this incurs a performance cost.
433
+ pub max_parallax_layer_count : f32 ,
344
434
}
345
435
346
436
impl AsBindGroupShaderType < StandardMaterialUniform > for StandardMaterial {
@@ -367,6 +457,9 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
367
457
if self . fog_enabled {
368
458
flags |= StandardMaterialFlags :: FOG_ENABLED ;
369
459
}
460
+ if self . depth_map . is_some ( ) {
461
+ flags |= StandardMaterialFlags :: DEPTH_MAP ;
462
+ }
370
463
let has_normal_map = self . normal_map_texture . is_some ( ) ;
371
464
if has_normal_map {
372
465
if let Some ( texture) = images. get ( self . normal_map_texture . as_ref ( ) . unwrap ( ) ) {
@@ -407,15 +500,19 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
407
500
reflectance : self . reflectance ,
408
501
flags : flags. bits ( ) ,
409
502
alpha_cutoff,
503
+ parallax_depth : self . parallax_depth ,
504
+ max_parallax_layer_count : self . max_parallax_layer_count ,
410
505
}
411
506
}
412
507
}
413
508
509
+ /// The pipeline key for [`StandardMaterial`].
414
510
#[ derive( Clone , PartialEq , Eq , Hash ) ]
415
511
pub struct StandardMaterialKey {
416
512
normal_map : bool ,
417
513
cull_mode : Option < Face > ,
418
514
depth_bias : i32 ,
515
+ relief_mapping : bool ,
419
516
}
420
517
421
518
impl From < & StandardMaterial > for StandardMaterialKey {
@@ -424,6 +521,10 @@ impl From<&StandardMaterial> for StandardMaterialKey {
424
521
normal_map : material. normal_map_texture . is_some ( ) ,
425
522
cull_mode : material. cull_mode ,
426
523
depth_bias : material. depth_bias as i32 ,
524
+ relief_mapping : matches ! (
525
+ material. parallax_mapping_method,
526
+ ParallaxMappingMethod :: ReliefMapping { .. }
527
+ ) ,
427
528
}
428
529
}
429
530
}
@@ -435,11 +536,14 @@ impl Material for StandardMaterial {
435
536
_layout : & MeshVertexBufferLayout ,
436
537
key : MaterialPipelineKey < Self > ,
437
538
) -> Result < ( ) , SpecializedMeshPipelineError > {
438
- if key. bind_group_data . normal_map {
439
- if let Some ( fragment) = descriptor. fragment . as_mut ( ) {
440
- fragment
441
- . shader_defs
442
- . push ( "STANDARDMATERIAL_NORMAL_MAP" . into ( ) ) ;
539
+ if let Some ( fragment) = descriptor. fragment . as_mut ( ) {
540
+ let shader_defs = & mut fragment. shader_defs ;
541
+
542
+ if key. bind_group_data . normal_map {
543
+ shader_defs. push ( "STANDARDMATERIAL_NORMAL_MAP" . into ( ) ) ;
544
+ }
545
+ if key. bind_group_data . relief_mapping {
546
+ shader_defs. push ( "RELIEF_MAPPING" . into ( ) ) ;
443
547
}
444
548
}
445
549
descriptor. primitive . cull_mode = key. bind_group_data . cull_mode ;
0 commit comments