11use  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 , 
44} ; 
55use  bevy_asset:: Handle ; 
66use  bevy_math:: Vec4 ; 
@@ -231,6 +231,84 @@ pub struct StandardMaterial {
231231/// 
232232/// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting 
233233pub  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 , 
234312} 
235313
236314impl  Default  for  StandardMaterial  { 
@@ -260,6 +338,10 @@ impl Default for StandardMaterial {
260338            fog_enabled :  true , 
261339            alpha_mode :  AlphaMode :: Opaque , 
262340            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 , 
263345        } 
264346    } 
265347} 
@@ -302,6 +384,7 @@ bitflags::bitflags! {
302384        const  TWO_COMPONENT_NORMAL_MAP    = ( 1  << 6 ) ; 
303385        const  FLIP_NORMAL_MAP_Y           = ( 1  << 7 ) ; 
304386        const  FOG_ENABLED                 = ( 1  << 8 ) ; 
387+         const  DEPTH_MAP                   = ( 1  << 9 ) ;  // Used for parallax mapping 
305388        const  ALPHA_MODE_RESERVED_BITS    = ( Self :: ALPHA_MODE_MASK_BITS  << Self :: ALPHA_MODE_SHIFT_BITS ) ;  // ← Bitmask reserving bits for the `AlphaMode` 
306389        const  ALPHA_MODE_OPAQUE           = ( 0  << Self :: ALPHA_MODE_SHIFT_BITS ) ;                           // ← Values are just sequential values bitshifted into 
307390        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 {
341424    /// When the alpha mode mask flag is set, any base color alpha above this cutoff means fully opaque, 
342425/// and any below means fully transparent. 
343426pub  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 , 
344434} 
345435
346436impl  AsBindGroupShaderType < StandardMaterialUniform >  for  StandardMaterial  { 
@@ -367,6 +457,9 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
367457        if  self . fog_enabled  { 
368458            flags |= StandardMaterialFlags :: FOG_ENABLED ; 
369459        } 
460+         if  self . depth_map . is_some ( )  { 
461+             flags |= StandardMaterialFlags :: DEPTH_MAP ; 
462+         } 
370463        let  has_normal_map = self . normal_map_texture . is_some ( ) ; 
371464        if  has_normal_map { 
372465            if  let  Some ( texture)  = images. get ( self . normal_map_texture . as_ref ( ) . unwrap ( ) )  { 
@@ -407,15 +500,19 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
407500            reflectance :  self . reflectance , 
408501            flags :  flags. bits ( ) , 
409502            alpha_cutoff, 
503+             parallax_depth :  self . parallax_depth , 
504+             max_parallax_layer_count :  self . max_parallax_layer_count , 
410505        } 
411506    } 
412507} 
413508
509+ /// The pipeline key for [`StandardMaterial`]. 
414510#[ derive( Clone ,  PartialEq ,  Eq ,  Hash ) ]  
415511pub  struct  StandardMaterialKey  { 
416512    normal_map :  bool , 
417513    cull_mode :  Option < Face > , 
418514    depth_bias :  i32 , 
515+     relief_mapping :  bool , 
419516} 
420517
421518impl  From < & StandardMaterial >  for  StandardMaterialKey  { 
@@ -424,6 +521,10 @@ impl From<&StandardMaterial> for StandardMaterialKey {
424521            normal_map :  material. normal_map_texture . is_some ( ) , 
425522            cull_mode :  material. cull_mode , 
426523            depth_bias :  material. depth_bias  as  i32 , 
524+             relief_mapping :  matches ! ( 
525+                 material. parallax_mapping_method, 
526+                 ParallaxMappingMethod :: ReliefMapping  {  .. } 
527+             ) , 
427528        } 
428529    } 
429530} 
@@ -435,11 +536,14 @@ impl Material for StandardMaterial {
435536        _layout :  & MeshVertexBufferLayout , 
436537        key :  MaterialPipelineKey < Self > , 
437538    )  -> 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 ( ) ) ; 
443547            } 
444548        } 
445549        descriptor. primitive . cull_mode  = key. bind_group_data . cull_mode ; 
0 commit comments