mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Better depth biases (#23)
* 3d_scene_pipelined: Use a shallower directional light angle to provoke acne * cornell_box_pipelined: Remove bias tweaks * bevy_pbr2: Simplify shadow biases by moving them to linear depth
This commit is contained in:
parent
30b8324672
commit
44df4c1fae
5 changed files with 54 additions and 53 deletions
|
@ -199,7 +199,7 @@ fn setup(
|
|||
},
|
||||
transform: Transform {
|
||||
translation: Vec3::new(0.0, 2.0, 0.0),
|
||||
rotation: Quat::from_rotation_x(-1.2),
|
||||
rotation: Quat::from_rotation_x(-std::f32::consts::FRAC_PI_4),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
|
|
@ -136,8 +136,6 @@ fn setup(
|
|||
builder.spawn_bundle(PointLightBundle {
|
||||
point_light: PointLight {
|
||||
color: Color::WHITE,
|
||||
shadow_bias_min: 0.00001,
|
||||
shadow_bias_max: 0.0001,
|
||||
intensity: 25.0,
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -150,8 +148,6 @@ fn setup(
|
|||
commands.spawn_bundle(DirectionalLightBundle {
|
||||
directional_light: DirectionalLight {
|
||||
illuminance: 10000.0,
|
||||
shadow_bias_min: 0.00001,
|
||||
shadow_bias_max: 0.0001,
|
||||
shadow_projection: OrthographicProjection {
|
||||
left: -HALF_SIZE,
|
||||
right: HALF_SIZE,
|
||||
|
|
|
@ -7,8 +7,8 @@ pub struct PointLight {
|
|||
pub intensity: f32,
|
||||
pub range: f32,
|
||||
pub radius: f32,
|
||||
pub shadow_bias_min: f32,
|
||||
pub shadow_bias_max: f32,
|
||||
pub shadow_depth_bias: f32,
|
||||
pub shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
impl Default for PointLight {
|
||||
|
@ -18,15 +18,15 @@ impl Default for PointLight {
|
|||
intensity: 200.0,
|
||||
range: 20.0,
|
||||
radius: 0.0,
|
||||
shadow_bias_min: Self::DEFAULT_SHADOW_BIAS_MIN,
|
||||
shadow_bias_max: Self::DEFAULT_SHADOW_BIAS_MAX,
|
||||
shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS,
|
||||
shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PointLight {
|
||||
pub const DEFAULT_SHADOW_BIAS_MIN: f32 = 0.00005;
|
||||
pub const DEFAULT_SHADOW_BIAS_MAX: f32 = 0.002;
|
||||
pub const DEFAULT_SHADOW_DEPTH_BIAS: f32 = 0.02;
|
||||
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.02;
|
||||
}
|
||||
|
||||
/// A Directional light.
|
||||
|
@ -60,8 +60,8 @@ pub struct DirectionalLight {
|
|||
pub color: Color,
|
||||
pub illuminance: f32,
|
||||
pub shadow_projection: OrthographicProjection,
|
||||
pub shadow_bias_min: f32,
|
||||
pub shadow_bias_max: f32,
|
||||
pub shadow_depth_bias: f32,
|
||||
pub shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
impl Default for DirectionalLight {
|
||||
|
@ -79,15 +79,15 @@ impl Default for DirectionalLight {
|
|||
far: size,
|
||||
..Default::default()
|
||||
},
|
||||
shadow_bias_min: Self::DEFAULT_SHADOW_BIAS_MIN,
|
||||
shadow_bias_max: Self::DEFAULT_SHADOW_BIAS_MAX,
|
||||
shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS,
|
||||
shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DirectionalLight {
|
||||
pub const DEFAULT_SHADOW_BIAS_MIN: f32 = 0.00005;
|
||||
pub const DEFAULT_SHADOW_BIAS_MAX: f32 = 0.002;
|
||||
pub const DEFAULT_SHADOW_DEPTH_BIAS: f32 = 0.02;
|
||||
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.02;
|
||||
}
|
||||
|
||||
// Ambient light color.
|
||||
|
|
|
@ -29,8 +29,8 @@ pub struct ExtractedPointLight {
|
|||
range: f32,
|
||||
radius: f32,
|
||||
transform: GlobalTransform,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
pub struct ExtractedDirectionalLight {
|
||||
|
@ -38,8 +38,8 @@ pub struct ExtractedDirectionalLight {
|
|||
illuminance: f32,
|
||||
direction: Vec3,
|
||||
projection: Mat4,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -52,8 +52,8 @@ pub struct GpuPointLight {
|
|||
radius: f32,
|
||||
near: f32,
|
||||
far: f32,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -62,8 +62,8 @@ pub struct GpuDirectionalLight {
|
|||
view_projection: Mat4,
|
||||
color: Vec4,
|
||||
dir_to_light: Vec3,
|
||||
shadow_bias_min: f32,
|
||||
shadow_bias_max: f32,
|
||||
shadow_depth_bias: f32,
|
||||
shadow_normal_bias: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -235,8 +235,8 @@ pub fn extract_lights(
|
|||
range: point_light.range,
|
||||
radius: point_light.radius,
|
||||
transform: *transform,
|
||||
shadow_bias_min: point_light.shadow_bias_min,
|
||||
shadow_bias_max: point_light.shadow_bias_max,
|
||||
shadow_depth_bias: point_light.shadow_depth_bias,
|
||||
shadow_normal_bias: point_light.shadow_normal_bias,
|
||||
});
|
||||
}
|
||||
for (entity, directional_light, transform) in directional_lights.iter() {
|
||||
|
@ -247,8 +247,8 @@ pub fn extract_lights(
|
|||
illuminance: directional_light.illuminance,
|
||||
direction: transform.forward(),
|
||||
projection: directional_light.shadow_projection.get_projection_matrix(),
|
||||
shadow_bias_min: directional_light.shadow_bias_min,
|
||||
shadow_bias_max: directional_light.shadow_bias_max,
|
||||
shadow_depth_bias: directional_light.shadow_depth_bias,
|
||||
shadow_normal_bias: directional_light.shadow_normal_bias,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -443,8 +443,8 @@ pub fn prepare_lights(
|
|||
near: 0.1,
|
||||
far: light.range,
|
||||
// proj: projection,
|
||||
shadow_bias_min: light.shadow_bias_min,
|
||||
shadow_bias_max: light.shadow_bias_max,
|
||||
shadow_depth_bias: light.shadow_depth_bias,
|
||||
shadow_normal_bias: light.shadow_normal_bias,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -482,8 +482,8 @@ pub fn prepare_lights(
|
|||
dir_to_light,
|
||||
// NOTE: * view is correct, it should not be view.inverse() here
|
||||
view_projection: projection * view,
|
||||
shadow_bias_min: light.shadow_bias_min,
|
||||
shadow_bias_max: light.shadow_bias_max,
|
||||
shadow_depth_bias: light.shadow_depth_bias,
|
||||
shadow_normal_bias: light.shadow_normal_bias,
|
||||
};
|
||||
|
||||
let depth_texture_view =
|
||||
|
|
|
@ -95,16 +95,16 @@ struct PointLight {
|
|||
radius: f32;
|
||||
near: f32;
|
||||
far: f32;
|
||||
shadow_bias_min: f32;
|
||||
shadow_bias_max: f32;
|
||||
shadow_depth_bias: f32;
|
||||
shadow_normal_bias: f32;
|
||||
};
|
||||
|
||||
struct DirectionalLight {
|
||||
view_projection: mat4x4<f32>;
|
||||
color: vec4<f32>;
|
||||
direction_to_light: vec3<f32>;
|
||||
shadow_bias_min: f32;
|
||||
shadow_bias_max: f32;
|
||||
shadow_depth_bias: f32;
|
||||
shadow_normal_bias: f32;
|
||||
};
|
||||
|
||||
[[block]]
|
||||
|
@ -379,7 +379,7 @@ fn directional_light(light: DirectionalLight, roughness: f32, NdotV: f32, normal
|
|||
return (specular_light + diffuse) * light.color.rgb * NoL;
|
||||
}
|
||||
|
||||
fn fetch_point_shadow(light_id: i32, frag_position: vec4<f32>, shadow_bias: f32) -> f32 {
|
||||
fn fetch_point_shadow(light_id: i32, frag_position: vec4<f32>) -> f32 {
|
||||
let light = lights.point_lights[light_id];
|
||||
|
||||
// because the shadow maps align with the axes and the frustum planes are at 45 degrees
|
||||
|
@ -412,11 +412,12 @@ fn fetch_point_shadow(light_id: i32, frag_position: vec4<f32>, shadow_bias: f32)
|
|||
// a quad (2x2 fragments) being processed not being sampled, and this messing with
|
||||
// mip-mapping functionality. The shadow maps have no mipmaps so Level just samples
|
||||
// from LOD 0.
|
||||
let bias = 0.0001;
|
||||
return textureSampleCompareLevel(point_shadow_textures, point_shadow_textures_sampler, frag_ls, i32(light_id), depth - shadow_bias);
|
||||
return textureSampleCompareLevel(point_shadow_textures, point_shadow_textures_sampler, frag_ls, i32(light_id), depth);
|
||||
}
|
||||
|
||||
fn fetch_directional_shadow(light_id: i32, homogeneous_coords: vec4<f32>, shadow_bias: f32) -> f32 {
|
||||
fn fetch_directional_shadow(light_id: i32, frag_position: vec4<f32>) -> f32 {
|
||||
let light = lights.directional_lights[light_id];
|
||||
let homogeneous_coords = light.view_projection * frag_position;
|
||||
if (homogeneous_coords.w <= 0.0) {
|
||||
return 1.0;
|
||||
}
|
||||
|
@ -428,7 +429,7 @@ fn fetch_directional_shadow(light_id: i32, homogeneous_coords: vec4<f32>, shadow
|
|||
// do the lookup, using HW PCF and comparison
|
||||
// NOTE: Due to non-uniform control flow above, we must use the level variant of the texture
|
||||
// sampler to avoid use of implicit derivatives causing possible undefined behavior.
|
||||
return textureSampleCompareLevel(directional_shadow_textures, directional_shadow_textures_sampler, light_local, i32(light_id), homogeneous_coords.z * proj_correction - shadow_bias);
|
||||
return textureSampleCompareLevel(directional_shadow_textures, directional_shadow_textures_sampler, light_local, i32(light_id), homogeneous_coords.z * proj_correction);
|
||||
}
|
||||
|
||||
struct FragmentInput {
|
||||
|
@ -521,23 +522,27 @@ fn fragment(in: FragmentInput) -> [[location(0)]] vec4<f32> {
|
|||
let n_directional_lights = i32(lights.n_directional_lights);
|
||||
for (var i: i32 = 0; i < n_point_lights; i = i + 1) {
|
||||
let light = lights.point_lights[i];
|
||||
let light_contrib = point_light(in.world_position.xyz, light, roughness, NdotV, N, V, R, F0, diffuse_color);
|
||||
|
||||
let dir_to_light = normalize(light.position.xyz - in.world_position.xyz);
|
||||
let shadow_bias = max(
|
||||
light.shadow_bias_max * (1.0 - dot(in.world_normal, dir_to_light)),
|
||||
light.shadow_bias_min
|
||||
);
|
||||
let shadow = fetch_point_shadow(i, in.world_position, shadow_bias);
|
||||
let depth_bias = light.shadow_depth_bias * dir_to_light.xyz;
|
||||
let NdotL = dot(dir_to_light.xyz, in.world_normal.xyz);
|
||||
let normal_bias = light.shadow_normal_bias * (1.0 - NdotL) * in.world_normal.xyz;
|
||||
let biased_position = vec4<f32>(in.world_position.xyz + depth_bias + normal_bias, in.world_position.w);
|
||||
|
||||
let shadow = fetch_point_shadow(i, biased_position);
|
||||
let light_contrib = point_light(in.world_position.xyz, light, roughness, NdotV, N, V, R, F0, diffuse_color);
|
||||
light_accum = light_accum + light_contrib * shadow;
|
||||
}
|
||||
for (var i: i32 = 0; i < n_directional_lights; i = i + 1) {
|
||||
let light = lights.directional_lights[i];
|
||||
|
||||
let depth_bias = light.shadow_depth_bias * light.direction_to_light.xyz;
|
||||
let NdotL = dot(light.direction_to_light.xyz, in.world_normal.xyz);
|
||||
let normal_bias = light.shadow_normal_bias * (1.0 - NdotL) * in.world_normal.xyz;
|
||||
let biased_position = vec4<f32>(in.world_position.xyz + depth_bias + normal_bias, in.world_position.w);
|
||||
|
||||
let shadow = fetch_directional_shadow(i, biased_position);
|
||||
let light_contrib = directional_light(light, roughness, NdotV, N, V, R, F0, diffuse_color);
|
||||
let shadow_bias = max(
|
||||
light.shadow_bias_max * (1.0 - dot(in.world_normal, light.direction_to_light.xyz)),
|
||||
light.shadow_bias_min
|
||||
);
|
||||
let shadow = fetch_directional_shadow(i, light.view_projection * in.world_position, shadow_bias);
|
||||
light_accum = light_accum + light_contrib * shadow;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue