-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add parallax mapping to bevy PBR (#5928)
# Objective Add a [parallax mapping] shader to bevy. Please note that this is a 3d technique, NOT a 2d sidescroller feature. ## Solution - 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 - Generate depth map from normal map [link to slides], [blender question] https://user-images.githubusercontent.com/26321040/223563792-dffcc6ab-70e8-4ff9-90d1-b36c338695ad.mp4 [blender question]: https://blender.stackexchange.com/questions/89278/how-to-get-a-smooth-curvature-map-from-a-normal-map [link to slides]: https://developer.download.nvidia.com/assets/gamedev/docs/nmap2displacement.pdf [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://github.com/raw/marcusstenbeck/tncg14-parallax-mapping/master/documents/Parallax%20Mapping%20with%20Offset%20Limiting%20-%20A%20Per-Pixel%20Approximation%20of%20Uneven%20Surfaces.pdf [gltf]: KhronosGroup/glTF#2196 [qpm]: https://www.gamedevs.org/uploads/quadtree-displacement-mapping-with-height-blending.pdf --- ## Changelog - Add a `depth_map` field to the `StandardMaterial`, it is a grayscale 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_scale` 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 --------- Co-authored-by: Robert Swain <robert.swain@gmail.com>
- Loading branch information
Showing
13 changed files
with
719 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use bevy_reflect::{FromReflect, Reflect}; | ||
|
||
/// The [parallax mapping] method to use to compute depth based on the | ||
/// material's [`depth_map`]. | ||
/// | ||
/// Parallax Mapping uses a depth map texture to give the illusion of depth | ||
/// variation on a mesh surface that is geometrically flat. | ||
/// | ||
/// See the `parallax_mapping.wgsl` shader code for implementation details | ||
/// and explanation of the methods used. | ||
/// | ||
/// [`depth_map`]: crate::StandardMaterial::depth_map | ||
/// [parallax mapping]: https://en.wikipedia.org/wiki/Parallax_mapping | ||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Reflect, FromReflect)] | ||
pub enum ParallaxMappingMethod { | ||
/// A simple linear interpolation, using a single texture sample. | ||
/// | ||
/// This method is named "Parallax Occlusion Mapping". | ||
/// | ||
/// Unlike [`ParallaxMappingMethod::Relief`], only requires a single lookup, | ||
/// but may skip small details and result in writhing material artifacts. | ||
#[default] | ||
Occlusion, | ||
/// Discovers the best depth value based on binary search. | ||
/// | ||
/// Each iteration incurs a texture sample. | ||
/// The result has fewer visual artifacts than [`ParallaxMappingMethod::Occlusion`]. | ||
/// | ||
/// This method is named "Relief Mapping". | ||
Relief { | ||
/// How many additional steps to use at most to find the depth value. | ||
max_steps: u32, | ||
}, | ||
} | ||
impl ParallaxMappingMethod { | ||
/// [`ParallaxMappingMethod::Relief`] with a 5 steps, a reasonable default. | ||
pub const DEFAULT_RELIEF_MAPPING: Self = ParallaxMappingMethod::Relief { max_steps: 5 }; | ||
|
||
pub(crate) fn max_steps(&self) -> u32 { | ||
match self { | ||
ParallaxMappingMethod::Occlusion => 0, | ||
ParallaxMappingMethod::Relief { max_steps } => *max_steps, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.