From e975dd3171899081999ed2869a9d04a265848f21 Mon Sep 17 00:00:00 2001 From: Nicola Papale Date: Fri, 9 Sep 2022 19:07:38 +0200 Subject: [PATCH] Add parallax mapping to bevy_pbr Add a [parallax mapping] shader to bevy. Please note that this is a 3d technique, NOT a 2d sidescroller feature. - Add related fields to `StandardMaterial` - update the pbr shader - Add an example taking advantage of parallax mapping A pre-existing implementation exists at: https://github.com/nicopap/bevy_mod_paramap/ The implementation is derived from: https://web.archive.org/web/20150419215321/http://sunandblackcat.com/tipFullView.php?l=eng&topicid=28 Further discussion on literature is found in the `bevy_mod_paramap` README. Limitations ----------- - The mesh silhouette isn't affected by the depth map. - The depth of the pixel does not reflect its visual position, resulting in artifacts for depth-dependent features such as fog or SSAO - GLTF does not define a height map texture, so somehow the user will always need to work around this limitation, though [an extension is in the works][gltf] Future work ----------- - It's possible to update the depth in the depth buffer to follow the parallaxed texture. This would enable interop with depth-based visual effects, it also allows `discard`ing pixels of materials when computed depth is higher than the one in depth buffer - Cheap lower quality single-sample method using [offset limiting] - Add distance fading, to disable parallaxing (relatively expensive) on distant objects - GLTF extension to allow defining height maps. Or a workaround implemented through a blender plugin to the GLTF exporter that uses the `extras` field to add height map. - [Quadratic surface vertex attributes][oliveira_3] to enable parallax mapping on bending surfaces and allow clean silhouetting. - noise based sampling, to limit the pancake artifacts. - Cone mapping ([GPU gems], [Simcity (2013)][simcity]). Requires preprocessing, increase depth map size, reduces sample count greatly. - [Quadtree parallax mapping][qpm] (also requires preprocessing) - Self-shadowing of parallax-mapped surfaces by modifying the shadow map https://user-images.githubusercontent.com/26321040/223563792-dffcc6ab-70e8-4ff9-90d1-b36c338695ad.mp4 --- - Add a `depth_map` field to the `StandardMaterial`, it is a greyscale image where white represents bottom and black the top. If `depth_map` is set, bevy's pbr shader will use it to do [parallax mapping] to give an increased feel of depth to the material. This is similar to a displacement map, but with infinite precision at fairly low cost. - The fields `parallax_mapping_method`, `parallax_depth` and `max_parallax_layer_count` allow finer grained control over the behavior of the parallax shader. - Add the `parallax_mapping` example to show off the effect. [parallax mapping]: https://en.wikipedia.org/wiki/Parallax_mapping [oliveira_3]: https://www.inf.ufrgs.br/~oliveira/pubs_files/Oliveira_Policarpo_RP-351_Jan_2005.pdf [GPU gems]: https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-18-relaxed-cone-stepping-relief-mapping [simcity]: https://community.simtropolis.com/omnibus/other-games/building-and-rendering-simcity-2013-r247/ [offset limiting]: https://raw.githubusercontent.com/marcusstenbeck/tncg14-parallax-mapping/master/documents/Parallax%20Mapping%20with%20Offset%20Limiting%20-%20A%20Per-Pixel%20Approximation%20of%20Uneven%20Surfaces.pdf [gltf]: https://github.com/KhronosGroup/glTF/pull/2196 [qpm]: https://www.gamedevs.org/uploads/quadtree-displacement-mapping-with-height-blending.pdf Co-authored-by: Robert Swain --- Cargo.toml | 11 + .../textures/parallax_example/cube_color.jpg | Bin 0 -> 72155 bytes .../textures/parallax_example/cube_depth.jpg | Bin 0 -> 5959 bytes .../textures/parallax_example/cube_normal.jpg | Bin 0 -> 36040 bytes crates/bevy_pbr/src/lib.rs | 11 + crates/bevy_pbr/src/parallax.rs | 20 + crates/bevy_pbr/src/pbr_material.rs | 118 +++++- .../bevy_pbr/src/render/parallax_mapping.wgsl | 102 +++++ crates/bevy_pbr/src/render/pbr.wgsl | 30 +- crates/bevy_pbr/src/render/pbr_bindings.wgsl | 4 + crates/bevy_pbr/src/render/pbr_types.wgsl | 5 + examples/3d/parallax_mapping.rs | 354 ++++++++++++++++++ examples/README.md | 1 + 13 files changed, 642 insertions(+), 14 deletions(-) create mode 100644 assets/textures/parallax_example/cube_color.jpg create mode 100644 assets/textures/parallax_example/cube_depth.jpg create mode 100644 assets/textures/parallax_example/cube_normal.jpg create mode 100644 crates/bevy_pbr/src/parallax.rs create mode 100644 crates/bevy_pbr/src/render/parallax_mapping.wgsl create mode 100644 examples/3d/parallax_mapping.rs diff --git a/Cargo.toml b/Cargo.toml index a35c8ee752b86..6b6aaa778c717 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -561,6 +561,17 @@ description = "Demonstrates use of Physically Based Rendering (PBR) properties" category = "3D Rendering" wasm = true +[[example]] +name = "parallax_mapping" +path = "examples/3d/parallax_mapping.rs" +required-features = [ "jpeg" ] + +[package.metadata.example.parallax_mapping] +name = "Parallax Mapping" +description = "Demonstrates use of a normal map and height map for parallax mapping" +category = "3D Rendering" +wasm = true + [[example]] name = "render_to_texture" path = "examples/3d/render_to_texture.rs" diff --git a/assets/textures/parallax_example/cube_color.jpg b/assets/textures/parallax_example/cube_color.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f8b8dc7ee1c7a9122b075362d5ef3d2a65deec54 GIT binary patch literal 72155 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�?LuLfu15bp?4b00dpRS(8njkR?gq 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

pl9#rOLeLjEqsN#c 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 |uA^ahtyBI% zOF-7kjH3{u^7~6Fof=C0ZFvj)%d1e275@Mrf-EQx{Fkgg#IZC>0b7fEV(QFF_=#|P zc!@fE7XhON78L=IR6B?kP9gXJFSjDr{NXqpkz&m8rbx=3KM`irlGG`%GfCygMQ3FhQ@WVL1aq`0*)-)-MhHM3gGLY6-t%6%c~Q z1A60f!Z6kbSyo;aB91}*cQ7)MiD*o@z9&E(UAUii%H^H$dtd8OnNArP%ZfGHIDlMrG^n=ZZffkpBQtDjJZm0d&y1T=Obw#@ogICMAOk==g-t zTejQ$h$z+DU!nut=C*xH!R=0bV3je403X*e>P6r<`;|~HcliVsmsA**a{x5fBVYx? zK`PmiLCy$7Tv+GgDVPS#GX$!!3->58-H1LIGI|=U_ZlLvAU{&K$4v+7T4i|wc!jF& zqBX>}1vy-tW}B@af-SLTa9e;2d^(9jJK%&EMRo%}616frE8B==+jIuXi!Hg0WR+~^ zc!69hnHv2}4N5T7$Pa`3P7*^zLjmM*^#G+@e<~IiVXS}1MUuR4>MXikc2Uud#MQq9 zi!uk)gsE~>(7;ujJP~z=;GBxTLMM|Kq!{Y7o@yzuXH3t#5Y!U<60>Pukj5x_AE|lA zRcQT0VJB31^o&$&=zgQbQ5@2v*y`vbXu$5b0JH_c2m_cEnaa`i8$f8w`bw}tk-$CS zf1nT2QMNXieyM;}Y*e`OxD+E=O=l3L&S?w}MMg!s=+7LR%<+;OpCm|mhydsId_fmG zgP+WAT4C&QXOG0nK+)?IEgrB%!wFPArLe+NGvglfKPL#{B^|E5U<5awWd*JtB?VZl zh!NSprx4Y*_COfg;FDVVI#XCyOix-!d^ zO0X^ntSk;QG1NGfUWOW`m8LS@p{Y?rn#Wzi*wwSdTKyI&#A?&Yh$CAXvavLtl1u;& z*7SeuS|1878Futwfw{bZYpH1{_ZNXG+;q0bac+jQS(Yl$7|a@vsWvG+Hw#ZCM775L zlH+fP?8k|@m@b*9w`vBU5?Ts}4~cxjv9B>^?73Un=>}b;?Ma9%r<;xB&#M=L2&aeK z4iUht&h9J(&F%%HRqgW<9sdBZ(Xlvri4>yvfr9LEu+$xLM7JY_jl*hnb5ey?I-1(s z-H_IrLL?r=^)Ih(t3-;K9BeV^ c3f1fuueo~KX!7)(z{@MzGb^C18Ga}K*=f!Y+W-In literal 0 HcmV?d00001 diff --git a/assets/textures/parallax_example/cube_depth.jpg b/assets/textures/parallax_example/cube_depth.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f92efe5245f85156bc3828051e58dc01c1ed15bc GIT binary patch literal 5959 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 Uz~yg56M513V!-_O^#1>w0G^ZdUjP6A literal 0 HcmV?d00001 diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 917fd007c308a..bf7af957dfcde 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -8,6 +8,7 @@ mod environment_map; mod fog; mod light; mod material; +mod parallax; mod pbr_material; mod prepass; mod render; @@ -18,6 +19,7 @@ pub use environment_map::EnvironmentMapLight; pub use fog::*; pub use light::*; pub use material::*; +pub use parallax::*; pub use pbr_material::*; pub use prepass::*; pub use render::*; @@ -34,6 +36,7 @@ pub mod prelude { fog::{FogFalloff, FogSettings}, light::{AmbientLight, DirectionalLight, PointLight, SpotLight}, material::{Material, MaterialPlugin}, + parallax::ParallaxMappingMethod, pbr_material::StandardMaterial, }; } @@ -82,6 +85,8 @@ pub const PBR_FUNCTIONS_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 16550102964439850292); pub const PBR_AMBIENT_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 2441520459096337034); +pub const PARALLAX_MAPPING_SHADER_HANDLE: HandleUntyped = + HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 17035894873630133905); /// Sets up the entire PBR infrastructure of bevy. pub struct PbrPlugin { @@ -150,6 +155,12 @@ impl Plugin for PbrPlugin { "render/pbr_prepass.wgsl", Shader::from_wgsl ); + load_internal_asset!( + app, + PARALLAX_MAPPING_SHADER_HANDLE, + "render/parallax_mapping.wgsl", + Shader::from_wgsl + ); app.register_asset_reflect::() .register_type::() diff --git a/crates/bevy_pbr/src/parallax.rs b/crates/bevy_pbr/src/parallax.rs new file mode 100644 index 0000000000000..cc7b2c200f210 --- /dev/null +++ b/crates/bevy_pbr/src/parallax.rs @@ -0,0 +1,20 @@ +use bevy_reflect::{FromReflect, Reflect}; + +/// The parallax mapping method to use to compute a displacement based on the +/// material's [`depth_map`]. +/// +/// See the `parallax_mapping.wgsl` shader code for implementation details +/// and explanation of the methods used. +/// +/// [`depth_map`]: crate::StandardMaterial::depth_map +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Reflect, FromReflect)] +pub enum ParallaxMappingMethod { + /// A simple linear interpolation, using a single texture sample. + #[default] + ParallaxOcclusionMapping, + /// A discovery of 5 iterations of the best displacement + /// value. Each iteration incurs a texture sample. + /// + /// The result has fewer visual artifacts than `ParallaxOcclusionMapping`. + ReliefMapping { n_steps: u32 }, +} diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index c8be48f8fccd9..732ce289c6f78 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -1,6 +1,6 @@ use crate::{ - AlphaMode, Material, MaterialPipeline, MaterialPipelineKey, PBR_PREPASS_SHADER_HANDLE, - PBR_SHADER_HANDLE, + AlphaMode, Material, MaterialPipeline, MaterialPipelineKey, ParallaxMappingMethod, + PBR_PREPASS_SHADER_HANDLE, PBR_SHADER_HANDLE, }; use bevy_asset::Handle; use bevy_math::Vec4; @@ -231,6 +231,84 @@ pub struct StandardMaterial { /// /// [z-fighting]: https://en.wikipedia.org/wiki/Z-fighting pub depth_bias: f32, + + /// The depth map used for [parallax mapping]. + /// + /// It is a greyscale image where white represents bottom and black the top. + /// If this field is set, bevy will apply [parallax mapping]. + /// Parallax mapping, unlike simple normal maps, will move the texture + /// coordinate according to the current perspective, + /// giving actual depth to the texture. + /// + /// The visual result is similar to a displacement map, + /// but does not require additional geometry. + /// + /// Use the [`parallax_depth`] field to control the depth of the parallax. + /// + /// ## Limitations + /// + /// - It will look weird on bent/non-planar surfaces. + /// - The depth of the pixel does not reflect its visual position, resulting + /// in artifacts for depth-dependent features such as fog or SSAO. + /// - For the same reason, the the geometry silhouette will always be + /// the one of the actual geometry, not the parallaxed version, resulting + /// in awkward looks on intersecting parallaxed surfaces. + /// + /// ## Performance + /// + /// Parallax mapping requires multiple texture lookups, proportional to + /// [`max_parallax_layer_count`], which might be costly. + /// + /// Use the [`parallax_mapping_method`] and [`max_parallax_layer_count`] fields + /// to tweak the shader, trading graphical quality for performance. + /// + /// To improve performance, set your `depth_map`'s [`Image::sampler_descriptor`] + /// filter mode to `FilterMode::Nearest`, as [this paper] indicates, it improves + /// performance a bit. + /// + /// To reduce artifacts, avoid steep changes in depth, blurring the depth + /// map helps with this. + /// + /// Larger depth maps haves a disproportionate performance impact. + /// + /// [this paper]: https://www.diva-portal.org/smash/get/diva2:831762/FULLTEXT01.pdf + /// [parallax mapping]: https://en.wikipedia.org/wiki/Parallax_mapping + /// [`parallax_depth`]: StandardMaterial::parallax_depth + /// [`parallax_mapping_method`]: StandardMaterial::parallax_mapping_method + /// [`max_parallax_layer_count`]: StandardMaterial::max_parallax_layer_count + #[texture(11)] + #[sampler(12)] + pub depth_map: Option>, + + /// How deep the offset introduced by the depth map should be. + /// + /// Default is `0.1`, anything over that value may look distorted. + /// Lower values lessen the effect. + /// + /// The depth is relative to texture size. This means that if your texture + /// occupies a surface of `1` world unit, and `parallax_depth` is `0.1`, then + /// the in-world depth will be of `0.1` world units. + /// If the texture stretches for `10` world units, then the final depth + /// will be of `1` world unit. + pub parallax_depth: f32, + + /// Which parallax mapping method to use. + /// + /// We recommend that all objects use the same [`ParallaxMappingMethod`], to avoid + /// duplicating and running two shaders. + pub parallax_mapping_method: ParallaxMappingMethod, + + /// In how many layers to split the depth maps for parallax mapping. + /// + /// If you are seeing jaggy edges, increase this value. + /// However, this incurs a performance cost. + /// + /// Dependent on the situation, switching to [`ParallaxMappingMethod::ReliefMapping`] + /// and keeping this value low might have better performance than increasing the + /// layer count while using [`ParallaxMappingMethod::ParallaxOcclusionMapping`]. + /// + /// Default is `16.0`. + pub max_parallax_layer_count: f32, } impl Default for StandardMaterial { @@ -260,6 +338,10 @@ impl Default for StandardMaterial { fog_enabled: true, alpha_mode: AlphaMode::Opaque, depth_bias: 0.0, + depth_map: None, + parallax_depth: 0.1, + max_parallax_layer_count: 16.0, + parallax_mapping_method: ParallaxMappingMethod::ParallaxOcclusionMapping, } } } @@ -302,6 +384,7 @@ bitflags::bitflags! { const TWO_COMPONENT_NORMAL_MAP = (1 << 6); const FLIP_NORMAL_MAP_Y = (1 << 7); const FOG_ENABLED = (1 << 8); + const DEPTH_MAP = (1 << 9); // Used for parallax mapping const ALPHA_MODE_RESERVED_BITS = (Self::ALPHA_MODE_MASK_BITS << Self::ALPHA_MODE_SHIFT_BITS); // ← Bitmask reserving bits for the `AlphaMode` const ALPHA_MODE_OPAQUE = (0 << Self::ALPHA_MODE_SHIFT_BITS); // ← Values are just sequential values bitshifted into 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 { /// When the alpha mode mask flag is set, any base color alpha above this cutoff means fully opaque, /// and any below means fully transparent. pub alpha_cutoff: f32, + /// The depth of the [`StandardMaterial::depth_map`] to apply. + pub parallax_depth: f32, + /// In how many layers to split the depth maps for Steep parallax mapping. + /// + /// If your `parallax_depth` is >0.1 and you are seeing jaggy edges, + /// increase this value. However, this incurs a performance cost. + pub max_parallax_layer_count: f32, } impl AsBindGroupShaderType for StandardMaterial { @@ -367,6 +457,9 @@ impl AsBindGroupShaderType for StandardMaterial { if self.fog_enabled { flags |= StandardMaterialFlags::FOG_ENABLED; } + if self.depth_map.is_some() { + flags |= StandardMaterialFlags::DEPTH_MAP; + } let has_normal_map = self.normal_map_texture.is_some(); if has_normal_map { if let Some(texture) = images.get(self.normal_map_texture.as_ref().unwrap()) { @@ -407,15 +500,19 @@ impl AsBindGroupShaderType for StandardMaterial { reflectance: self.reflectance, flags: flags.bits(), alpha_cutoff, + parallax_depth: self.parallax_depth, + max_parallax_layer_count: self.max_parallax_layer_count, } } } +/// The pipeline key for [`StandardMaterial`]. #[derive(Clone, PartialEq, Eq, Hash)] pub struct StandardMaterialKey { normal_map: bool, cull_mode: Option, depth_bias: i32, + relief_mapping: bool, } impl From<&StandardMaterial> for StandardMaterialKey { @@ -424,6 +521,10 @@ impl From<&StandardMaterial> for StandardMaterialKey { normal_map: material.normal_map_texture.is_some(), cull_mode: material.cull_mode, depth_bias: material.depth_bias as i32, + relief_mapping: matches!( + material.parallax_mapping_method, + ParallaxMappingMethod::ReliefMapping { .. } + ), } } } @@ -435,11 +536,14 @@ impl Material for StandardMaterial { _layout: &MeshVertexBufferLayout, key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { - if key.bind_group_data.normal_map { - if let Some(fragment) = descriptor.fragment.as_mut() { - fragment - .shader_defs - .push("STANDARDMATERIAL_NORMAL_MAP".into()); + if let Some(fragment) = descriptor.fragment.as_mut() { + let shader_defs = &mut fragment.shader_defs; + + if key.bind_group_data.normal_map { + shader_defs.push("STANDARDMATERIAL_NORMAL_MAP".into()); + } + if key.bind_group_data.relief_mapping { + shader_defs.push("RELIEF_MAPPING".into()); } } descriptor.primitive.cull_mode = key.bind_group_data.cull_mode; diff --git a/crates/bevy_pbr/src/render/parallax_mapping.wgsl b/crates/bevy_pbr/src/render/parallax_mapping.wgsl new file mode 100644 index 0000000000000..321200e2bcde4 --- /dev/null +++ b/crates/bevy_pbr/src/render/parallax_mapping.wgsl @@ -0,0 +1,102 @@ +#define_import_path bevy_pbr::parallax_mapping + +fn sample_depth_map(uv: vec2) -> f32 { + return textureSample(depth_map_texture, depth_map_sampler, uv).r; +} + +// An implementation of parallax mapping, see https://en.wikipedia.org/wiki/Parallax_mapping +// Code derived from: https://web.archive.org/web/20150419215321/http://sunandblackcat.com/tipFullView.php?l=eng&topicid=28 +fn parallaxed_uv( + depth: f32, + max_layer_count: f32, + // The original uv + uv: vec2, + // The vector from camera to the surface of material + V: vec3, +) -> vec2 { + var uv = uv; + if max_layer_count < 1.0 { + return uv; + } + + // Steep Parallax Mapping + // ====================== + // Split the depth map into `layer_count` layers. + // When V hits the surface of the mesh (excluding depth displacement), + // if the depth is not below or on surface including depth displacement (textureSample), then + // look forward (-= delta_uv) according to V and distance between hit surface and + // depth map surface, repeat until below the surface. + // + // Where `layer_count` is interpolated between `min_layer_count` and + // `max_layer_count` according to the steepness of V. + + let view_steepness = abs(dot(vec3(0.0, 0.0, 1.0), V)); + // We mix with minimum value 1.0 because otherwise, with 0.0, we get + // a nice division by zero in surfaces parallel to viewport, resulting + // in a singularity. + let layer_count = mix(max_layer_count, 1.0, view_steepness); + let layer_height = 1.0 / layer_count; + var delta_uv = depth * V.xy / V.z / layer_count; + + var current_layer_height = 0.0; + var current_height = sample_depth_map(uv); + + // This at most runs layer_count times + for (var i: i32 = 0; current_height > current_layer_height && i < i32(layer_count); i++) { + current_layer_height += layer_height; + uv -= delta_uv; + current_height = sample_depth_map(uv); + } + +#ifdef RELIEF_MAPPING + // Relief Mapping + // ============== + // "Refine" the rough result from Steep Parallax Mapping + // with a binary search between the layer selected by steep parallax + // and the next one to find a point closer to the depth map surface. + // This reduces the jaggy step artifacts from steep parallax mapping. + let MAX_STEPS: i32 = 5; + + delta_uv *= 0.5; + var delta_height = 0.5 * layer_height; + uv += delta_uv; + current_layer_height -= delta_height; + for (var i: i32 = 0; i < MAX_STEPS; i++) { + // Sample depth at current offset + current_height = sample_depth_map(uv); + + // Halve the deltas for the next step + delta_uv *= 0.5; + delta_height *= 0.5; + + // Step based on whether the current depth is above or below the depth map + if (current_height > current_layer_height) { + uv -= delta_uv; + current_layer_height += delta_height; + } else { + uv += delta_uv; + current_layer_height -= delta_height; + } + } +#else + // Parallax Occlusion mapping + // ========================== + // "Refine" Steep Parallax Mapping by interpolating between the + // previous layer's height and the computed layer height. + // Only requires a single lookup, unlike Relief Mapping, but + // may incur artifacts on very steep relief. + let previous_uv = uv + delta_uv; + let next_height = current_height - current_layer_height; + let previous_height = sample_depth_map(previous_uv) - current_layer_height + layer_height; + + let weight = next_height / (next_height - previous_height); + + uv = mix(uv, previous_uv, weight); + + current_layer_height += mix(next_height, previous_height, weight); +#endif + + // Note: `current_layer_height` is not returned, but may be useful + // for light computation later on in future improvements of the pbr shader. + return uv; +} diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index dbd0de51b34a7..be5414f6ea049 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -9,6 +9,7 @@ #import bevy_pbr::shadows #import bevy_pbr::fog #import bevy_pbr::pbr_functions +#import bevy_pbr::parallax_mapping #import bevy_pbr::prepass_utils @@ -20,13 +21,28 @@ struct FragmentInput { @fragment fn fragment(in: FragmentInput) -> @location(0) vec4 { + let is_orthographic = view.projection[3].w == 1.0; + let V = calculate_view(in.world_position, is_orthographic); + var uv = in.uv; +#ifdef VERTEX_UVS +#ifdef VERTEX_TANGENTS + if ((material.flags & STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) { + let tangent_V = vec3( + dot(V, in.world_tangent.xyz), + dot(V, -cross(in.world_normal, in.world_tangent.xyz) * sign(in.world_tangent.w)), + dot(V, in.world_normal), + ); + uv = parallaxed_uv(material.parallax_depth, material.max_parallax_layer_count, uv, tangent_V); + } +#endif +#endif var output_color: vec4 = material.base_color; #ifdef VERTEX_COLORS output_color = output_color * in.color; #endif #ifdef VERTEX_UVS if ((material.flags & STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) { - output_color = output_color * textureSample(base_color_texture, base_color_sampler, in.uv); + output_color = output_color * textureSample(base_color_texture, base_color_sampler, uv); } #endif @@ -45,7 +61,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { var emissive: vec4 = material.emissive; #ifdef VERTEX_UVS if ((material.flags & STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) { - emissive = vec4(emissive.rgb * textureSample(emissive_texture, emissive_sampler, in.uv).rgb, 1.0); + emissive = vec4(emissive.rgb * textureSample(emissive_texture, emissive_sampler, uv).rgb, 1.0); } #endif pbr_input.material.emissive = emissive; @@ -54,7 +70,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { var perceptual_roughness: f32 = material.perceptual_roughness; #ifdef VERTEX_UVS if ((material.flags & STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) { - let metallic_roughness = textureSample(metallic_roughness_texture, metallic_roughness_sampler, in.uv); + let metallic_roughness = textureSample(metallic_roughness_texture, metallic_roughness_sampler, uv); // Sampling from GLTF standard channels for now metallic = metallic * metallic_roughness.b; perceptual_roughness = perceptual_roughness * metallic_roughness.g; @@ -66,7 +82,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { var occlusion: f32 = 1.0; #ifdef VERTEX_UVS if ((material.flags & STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) { - occlusion = textureSample(occlusion_texture, occlusion_sampler, in.uv).r; + occlusion = textureSample(occlusion_texture, occlusion_sampler, uv).r; } #endif pbr_input.frag_coord = in.frag_coord; @@ -82,7 +98,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { ); #endif // LOAD_PREPASS_NORMALS - pbr_input.is_orthographic = view.projection[3].w == 1.0; + pbr_input.is_orthographic = is_orthographic; pbr_input.N = apply_normal_mapping( material.flags, @@ -93,10 +109,10 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { #endif #endif #ifdef VERTEX_UVS - in.uv, + uv, #endif ); - pbr_input.V = calculate_view(in.world_position, pbr_input.is_orthographic); + pbr_input.V = V; pbr_input.occlusion = occlusion; pbr_input.flags = mesh.flags; diff --git a/crates/bevy_pbr/src/render/pbr_bindings.wgsl b/crates/bevy_pbr/src/render/pbr_bindings.wgsl index f4e4d34f3b4c2..c5400dd20491e 100644 --- a/crates/bevy_pbr/src/render/pbr_bindings.wgsl +++ b/crates/bevy_pbr/src/render/pbr_bindings.wgsl @@ -24,3 +24,7 @@ var occlusion_sampler: sampler; var normal_map_texture: texture_2d; @group(1) @binding(10) var normal_map_sampler: sampler; +@group(1) @binding(11) +var depth_map_texture: texture_2d; +@group(1) @binding(12) +var depth_map_sampler: sampler; diff --git a/crates/bevy_pbr/src/render/pbr_types.wgsl b/crates/bevy_pbr/src/render/pbr_types.wgsl index 722f9b8411c21..dcfcc597a79b2 100644 --- a/crates/bevy_pbr/src/render/pbr_types.wgsl +++ b/crates/bevy_pbr/src/render/pbr_types.wgsl @@ -9,6 +9,8 @@ struct StandardMaterial { // 'flags' is a bit field indicating various options. u32 is 32 bits so we have up to 32 options. flags: u32, alpha_cutoff: f32, + parallax_depth: f32, + max_parallax_layer_count: f32, }; const STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT: u32 = 1u; @@ -20,6 +22,7 @@ const STANDARD_MATERIAL_FLAGS_UNLIT_BIT: u32 = 32u; const STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP: u32 = 64u; const STANDARD_MATERIAL_FLAGS_FLIP_NORMAL_MAP_Y: u32 = 128u; const STANDARD_MATERIAL_FLAGS_FOG_ENABLED_BIT: u32 = 256u; +const STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT: u32 = 512u; const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS: u32 = 3758096384u; // (0b111u32 << 29) const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE: u32 = 0u; // (0u32 << 29) const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK: u32 = 536870912u; // (1u32 << 29) @@ -42,6 +45,8 @@ fn standard_material_new() -> StandardMaterial { material.reflectance = 0.5; material.flags = STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE; material.alpha_cutoff = 0.5; + material.parallax_depth = 0.1; + material.max_parallax_layer_count = 16.0; return material; } diff --git a/examples/3d/parallax_mapping.rs b/examples/3d/parallax_mapping.rs new file mode 100644 index 0000000000000..b6aeed403aa63 --- /dev/null +++ b/examples/3d/parallax_mapping.rs @@ -0,0 +1,354 @@ +//! A simple 3D scene with a spinning cube with a normal map and depth map to demonstrate parallax mapping. +//! Press left mouse button to cycle through different views. + +use bevy::{prelude::*, render::render_resource::TextureFormat, window::close_on_esc}; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .insert_resource(Normal(None)) + .add_systems(Startup, setup) + .add_systems( + Update, + ( + spin, + update_normal, + move_camera, + update_parallax_depth, + update_parallax_layers, + switch_algo, + close_on_esc, + ), + ) + .run(); +} + +#[derive(Component)] +struct Spin { + speed: f32, +} + +/// The camera, used to move camera on click. +#[derive(Component)] +struct CameraController; + +const DEPTH_CHANGE_RATE: f32 = 0.1; +const DEPTH_UPDATE_STEP: f32 = 0.03; +const MAX_DEPTH: f32 = 0.3; + +struct TargetDepth(f32); +impl Default for TargetDepth { + fn default() -> Self { + TargetDepth(0.09) + } +} +struct TargetLayers(f32); +impl Default for TargetLayers { + fn default() -> Self { + TargetLayers(5.0) + } +} +fn update_parallax_depth( + input: Res>, + mut materials: ResMut>, + mut target_depth: Local, + mut depth_update: Local, + mut text: Query<&mut Text>, +) { + if input.just_pressed(KeyCode::Key1) { + target_depth.0 -= DEPTH_UPDATE_STEP; + target_depth.0 = target_depth.0.max(-MAX_DEPTH); + *depth_update = true; + } + if input.just_pressed(KeyCode::Key2) { + target_depth.0 += DEPTH_UPDATE_STEP; + target_depth.0 = target_depth.0.min(MAX_DEPTH); + *depth_update = true; + } + if *depth_update { + let mut text = text.single_mut(); + for (_, mat) in materials.iter_mut() { + let current_depth = mat.parallax_depth; + let new_depth = + current_depth * (1.0 - DEPTH_CHANGE_RATE) + (target_depth.0 * DEPTH_CHANGE_RATE); + mat.parallax_depth = new_depth; + text.sections[0].value = format!("Parallax depth: {new_depth:.5}\n"); + if (new_depth - current_depth).abs() <= 0.000000001 { + *depth_update = false; + } + } + } +} + +fn switch_algo( + input: Res>, + mut materials: ResMut>, + mut text: Query<&mut Text>, + mut current: Local, +) { + use ParallaxMappingMethod::*; + if input.just_pressed(KeyCode::Space) { + *current = match *current { + ReliefMapping { .. } => ParallaxOcclusionMapping, + ParallaxOcclusionMapping => ReliefMapping { n_steps: 5 }, + } + } else { + return; + } + let method_name = match *current { + ReliefMapping { .. } => "Relief Mapping", + ParallaxOcclusionMapping => "Parallax Occlusion Mapping", + }; + let mut text = text.single_mut(); + text.sections[2].value = format!("Method: {method_name}\n"); + + for (_, mat) in materials.iter_mut() { + mat.parallax_mapping_method = *current; + } +} + +fn update_parallax_layers( + input: Res>, + mut materials: ResMut>, + mut target_layers: Local, + mut text: Query<&mut Text>, +) { + if input.just_pressed(KeyCode::Key3) { + target_layers.0 -= 1.0; + target_layers.0 = target_layers.0.max(0.0); + } else if input.just_pressed(KeyCode::Key4) { + target_layers.0 += 1.0; + } else { + return; + } + let layer_count = target_layers.0.exp2(); + let mut text = text.single_mut(); + text.sections[1].value = format!("Layers: {layer_count:.0}\n"); + + for (_, mat) in materials.iter_mut() { + mat.max_parallax_layer_count = layer_count; + } +} + +fn spin(time: Res