Skip to content

Commit

Permalink
Parametrize MAX_STEPS, fix iteration count
Browse files Browse the repository at this point in the history
  • Loading branch information
nicopap committed Apr 2, 2023
1 parent 6863000 commit b7ca6ec
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 10 deletions.
24 changes: 20 additions & 4 deletions crates/bevy_pbr/src/parallax.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy_reflect::{FromReflect, Reflect};

/// The parallax mapping method to use to compute a displacement based on the
/// The parallax mapping method to use to compute depth based on the
/// material's [`depth_map`].
///
/// See the `parallax_mapping.wgsl` shader code for implementation details
Expand All @@ -12,9 +12,25 @@ 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.
/// Discovers the best depth value based on binary search.
///
/// Each iteration incurs a texture sample.
/// The result has fewer visual artifacts than `ParallaxOcclusionMapping`.
ReliefMapping { n_steps: u32 },
ReliefMapping {
/// How many additional steps to use at most to find the depth value.
max_steps: u32,
},
}
impl ParallaxMappingMethod {
/// [`ReliefMapping`] with a 5 steps, a reasonable default.
///
/// [`ReliefMapping`]: Self::ReliefMapping
pub const DEFAULT_RELIEF_MAPPING: Self = ParallaxMappingMethod::ReliefMapping { max_steps: 5 };

pub(crate) fn max_steps(&self) -> u32 {
match self {
ParallaxMappingMethod::ParallaxOcclusionMapping => 0,
ParallaxMappingMethod::ReliefMapping { max_steps } => *max_steps,
}
}
}
4 changes: 4 additions & 0 deletions crates/bevy_pbr/src/pbr_material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,9 @@ pub struct StandardMaterialUniform {
/// 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,
/// Using [`ParallaxMappingMethod::ReliefMapping`], how many additional
/// steps to use at most to find the depth value.
pub max_relief_mapping_search_steps: u32,
}

impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
Expand Down Expand Up @@ -502,6 +505,7 @@ impl AsBindGroupShaderType<StandardMaterialUniform> for StandardMaterial {
alpha_cutoff,
parallax_depth: self.parallax_depth,
max_parallax_layer_count: self.max_parallax_layer_count,
max_relief_mapping_search_steps: self.parallax_mapping_method.max_steps(),
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_pbr/src/render/parallax_mapping.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fn sample_depth_map(uv: vec2<f32>) -> f32 {
fn parallaxed_uv(
depth: f32,
max_layer_count: f32,
max_steps: u32,
// The original uv
uv: vec2<f32>,
// The vector from camera to the surface of material
Expand Down Expand Up @@ -42,7 +43,7 @@ fn parallaxed_uv(
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++) {
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);
Expand All @@ -55,13 +56,12 @@ fn parallaxed_uv(
// 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++) {
for (var i: u32 = 0u; i < max_steps; i++) {
// Sample depth at current offset
current_height = sample_depth_map(uv);

Expand Down
8 changes: 7 additions & 1 deletion crates/bevy_pbr/src/render/pbr.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
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);
uv = parallaxed_uv(
material.parallax_depth,
material.max_parallax_layer_count,
material.max_relief_mapping_search_steps,
uv,
tangent_V,
);
}
#endif
#endif
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_pbr/src/render/pbr_types.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct StandardMaterial {
alpha_cutoff: f32,
parallax_depth: f32,
max_parallax_layer_count: f32,
max_relief_mapping_search_steps: u32,
};

const STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT: u32 = 1u;
Expand Down Expand Up @@ -47,6 +48,7 @@ fn standard_material_new() -> StandardMaterial {
material.alpha_cutoff = 0.5;
material.parallax_depth = 0.1;
material.max_parallax_layer_count = 16.0;
material.max_relief_mapping_search_steps = 5u;

return material;
}
4 changes: 2 additions & 2 deletions examples/3d/parallax_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ fn switch_algo(
if input.just_pressed(KeyCode::Space) {
*current = match *current {
ReliefMapping { .. } => ParallaxOcclusionMapping,
ParallaxOcclusionMapping => ReliefMapping { n_steps: 5 },
ParallaxOcclusionMapping => ReliefMapping { max_steps: 5 },
}
} else {
return;
Expand Down Expand Up @@ -258,7 +258,7 @@ fn setup(
// white the lowest.
depth_map: Some(asset_server.load("textures/parallax_example/cube_depth.jpg")),
parallax_depth,
parallax_mapping_method: ParallaxMappingMethod::ReliefMapping { n_steps: 5 },
parallax_mapping_method: ParallaxMappingMethod::DEFAULT_RELIEF_MAPPING,
max_parallax_layer_count,
..default()
});
Expand Down

0 comments on commit b7ca6ec

Please sign in to comment.