forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Scale normal bias by texel size (#26)
* 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 * bevy_pbr2: Do not use DepthBiasState * bevy_pbr2: Do not use bilinear filtering for sampling depth textures * pbr.wgsl: Remove unnecessary comment * bevy_pbr2: Do manual shadow map depth comparisons for more flexibility * examples: Add shadow_biases_pipelined example This is useful for stress testing biases. * bevy_pbr2: Scale the point light normal bias by the shadow map texel size This allows the normal bias to be small close to the light source where the shadow map texel to screen texel ratio is high, but is appropriately large further away from the light source where the shadow map texel can easily cover multiple screen texels. * shadow_biases_pipelined: Add support for toggling directional / point light * shadow_biases_pipelined: Cleanup * bevy_pbr2: Scale the directional light normal bias by the shadow map texel size * shadow_biases_pipelined: Fit the orthographic projection around the scene * bevy_pbr2: Directional lights should have no shadows outside their projection Before this change, sampling a fragment position from outside the ndc volume would result in the return sample being clamped to the edge in x,y or possibly always casting a shadow for fragment positions past the orthographic projection's far plane. * bevy_pbr2: Fix the default directional light normal bias * Revert "bevy_pbr2: Do manual shadow map depth comparisons for more flexibility" This reverts commit 7df1bab. * shadow_biases_pipelined: Adjust directional light normal bias in 0.1 increments * pbr.wgsl: Add a couple of clarifying comments * Revert "bevy_pbr2: Do not use bilinear filtering for sampling depth textures" This reverts commit f53baab. * shadow_biases_pipelined: Print usage to terminal
- Loading branch information
Showing
5 changed files
with
412 additions
and
39 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
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,334 @@ | ||
use bevy::{ | ||
core::Time, | ||
ecs::prelude::*, | ||
input::{mouse::MouseMotion, Input}, | ||
math::{EulerRot, Mat4, Quat, Vec2, Vec3}, | ||
pbr2::{ | ||
DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight, PointLightBundle, | ||
StandardMaterial, | ||
}, | ||
prelude::{App, Assets, KeyCode, Transform}, | ||
render2::{ | ||
camera::{Camera, OrthographicProjection, PerspectiveCameraBundle}, | ||
color::Color, | ||
mesh::{shape, Mesh}, | ||
}, | ||
PipelinedDefaultPlugins, | ||
}; | ||
|
||
fn main() { | ||
println!( | ||
"Controls: | ||
WSAD - forward/back/strafe left/right | ||
LShift - 'run' | ||
E - up | ||
Q - down | ||
L - switch between directional and point lights | ||
1/2 - decrease/increase point light depth bias | ||
3/4 - decrease/increase point light normal bias | ||
5/6 - decrease/increase direction light depth bias | ||
7/8 - decrease/increase direction light normal bias" | ||
); | ||
App::new() | ||
.add_plugins(PipelinedDefaultPlugins) | ||
.add_startup_system(setup.system()) | ||
.add_system(adjust_point_light_biases.system()) | ||
.add_system(toggle_light.system()) | ||
.add_system(adjust_directional_light_biases.system()) | ||
.add_system(camera_controller.system()) | ||
.run(); | ||
} | ||
|
||
/// set up a 3D scene to test shadow biases and perspective projections | ||
fn setup( | ||
mut commands: Commands, | ||
mut meshes: ResMut<Assets<Mesh>>, | ||
mut materials: ResMut<Assets<StandardMaterial>>, | ||
) { | ||
let spawn_plane_depth = 500.0f32; | ||
let spawn_height = 2.0; | ||
let sphere_radius = 0.25; | ||
|
||
let white_handle = materials.add(StandardMaterial { | ||
base_color: Color::WHITE, | ||
perceptual_roughness: 1.0, | ||
..Default::default() | ||
}); | ||
let sphere_handle = meshes.add(Mesh::from(shape::Icosphere { | ||
radius: sphere_radius, | ||
..Default::default() | ||
})); | ||
|
||
println!("Using DirectionalLight"); | ||
|
||
commands.spawn_bundle(PointLightBundle { | ||
transform: Transform::from_xyz(5.0, 5.0, 0.0), | ||
point_light: PointLight { | ||
intensity: 0.0, | ||
range: spawn_plane_depth, | ||
color: Color::WHITE, | ||
shadow_depth_bias: 0.0, | ||
shadow_normal_bias: 0.0, | ||
..Default::default() | ||
}, | ||
..Default::default() | ||
}); | ||
|
||
let theta = std::f32::consts::FRAC_PI_4; | ||
let light_transform = Mat4::from_euler(EulerRot::ZYX, 0.0, std::f32::consts::FRAC_PI_2, -theta); | ||
commands.spawn_bundle(DirectionalLightBundle { | ||
directional_light: DirectionalLight { | ||
illuminance: 100000.0, | ||
shadow_projection: OrthographicProjection { | ||
left: -0.35, | ||
right: 500.35, | ||
bottom: -0.1, | ||
top: 5.0, | ||
near: -5.0, | ||
far: 5.0, | ||
..Default::default() | ||
}, | ||
shadow_depth_bias: 0.0, | ||
shadow_normal_bias: 0.0, | ||
..Default::default() | ||
}, | ||
transform: Transform::from_matrix(light_transform), | ||
..Default::default() | ||
}); | ||
|
||
// camera | ||
commands | ||
.spawn_bundle(PerspectiveCameraBundle { | ||
transform: Transform::from_xyz(-1.0, 1.0, 1.0) | ||
.looking_at(Vec3::new(-1.0, 1.0, 0.0), Vec3::Y), | ||
..Default::default() | ||
}) | ||
.insert(CameraController::default()); | ||
|
||
for z_i32 in -spawn_plane_depth as i32..=0 { | ||
commands.spawn_bundle(PbrBundle { | ||
mesh: sphere_handle.clone(), | ||
material: white_handle.clone(), | ||
transform: Transform::from_xyz(0.0, spawn_height, z_i32 as f32), | ||
..Default::default() | ||
}); | ||
} | ||
|
||
// ground plane | ||
commands.spawn_bundle(PbrBundle { | ||
mesh: meshes.add(Mesh::from(shape::Plane { | ||
size: 2.0 * spawn_plane_depth, | ||
})), | ||
material: white_handle.clone(), | ||
..Default::default() | ||
}); | ||
} | ||
|
||
fn toggle_light( | ||
input: Res<Input<KeyCode>>, | ||
mut point_lights: Query<&mut PointLight>, | ||
mut directional_lights: Query<&mut DirectionalLight>, | ||
) { | ||
if input.just_pressed(KeyCode::L) { | ||
for mut light in point_lights.iter_mut() { | ||
light.intensity = if light.intensity == 0.0 { | ||
println!("Using PointLight"); | ||
100000000.0 | ||
} else { | ||
0.0 | ||
}; | ||
} | ||
for mut light in directional_lights.iter_mut() { | ||
light.illuminance = if light.illuminance == 0.0 { | ||
println!("Using DirectionalLight"); | ||
100000.0 | ||
} else { | ||
0.0 | ||
}; | ||
} | ||
} | ||
} | ||
|
||
fn adjust_point_light_biases(input: Res<Input<KeyCode>>, mut query: Query<&mut PointLight>) { | ||
let depth_bias_step_size = 0.01; | ||
let normal_bias_step_size = 0.1; | ||
for mut light in query.iter_mut() { | ||
if input.just_pressed(KeyCode::Key1) { | ||
light.shadow_depth_bias -= depth_bias_step_size; | ||
println!("PointLight shadow_depth_bias: {}", light.shadow_depth_bias); | ||
} | ||
if input.just_pressed(KeyCode::Key2) { | ||
light.shadow_depth_bias += depth_bias_step_size; | ||
println!("PointLight shadow_depth_bias: {}", light.shadow_depth_bias); | ||
} | ||
if input.just_pressed(KeyCode::Key3) { | ||
light.shadow_normal_bias -= normal_bias_step_size; | ||
println!( | ||
"PointLight shadow_normal_bias: {}", | ||
light.shadow_normal_bias | ||
); | ||
} | ||
if input.just_pressed(KeyCode::Key4) { | ||
light.shadow_normal_bias += normal_bias_step_size; | ||
println!( | ||
"PointLight shadow_normal_bias: {}", | ||
light.shadow_normal_bias | ||
); | ||
} | ||
} | ||
} | ||
|
||
fn adjust_directional_light_biases( | ||
input: Res<Input<KeyCode>>, | ||
mut query: Query<&mut DirectionalLight>, | ||
) { | ||
let depth_bias_step_size = 0.01; | ||
let normal_bias_step_size = 0.1; | ||
for mut light in query.iter_mut() { | ||
if input.just_pressed(KeyCode::Key5) { | ||
light.shadow_depth_bias -= depth_bias_step_size; | ||
println!( | ||
"DirectionalLight shadow_depth_bias: {}", | ||
light.shadow_depth_bias | ||
); | ||
} | ||
if input.just_pressed(KeyCode::Key6) { | ||
light.shadow_depth_bias += depth_bias_step_size; | ||
println!( | ||
"DirectionalLight shadow_depth_bias: {}", | ||
light.shadow_depth_bias | ||
); | ||
} | ||
if input.just_pressed(KeyCode::Key7) { | ||
light.shadow_normal_bias -= normal_bias_step_size; | ||
println!( | ||
"DirectionalLight shadow_normal_bias: {}", | ||
light.shadow_normal_bias | ||
); | ||
} | ||
if input.just_pressed(KeyCode::Key8) { | ||
light.shadow_normal_bias += normal_bias_step_size; | ||
println!( | ||
"DirectionalLight shadow_normal_bias: {}", | ||
light.shadow_normal_bias | ||
); | ||
} | ||
} | ||
} | ||
|
||
struct CameraController { | ||
pub enabled: bool, | ||
pub sensitivity: f32, | ||
pub key_forward: KeyCode, | ||
pub key_back: KeyCode, | ||
pub key_left: KeyCode, | ||
pub key_right: KeyCode, | ||
pub key_up: KeyCode, | ||
pub key_down: KeyCode, | ||
pub key_run: KeyCode, | ||
pub walk_speed: f32, | ||
pub run_speed: f32, | ||
pub friction: f32, | ||
pub pitch: f32, | ||
pub yaw: f32, | ||
pub velocity: Vec3, | ||
} | ||
|
||
impl Default for CameraController { | ||
fn default() -> Self { | ||
Self { | ||
enabled: true, | ||
sensitivity: 0.5, | ||
key_forward: KeyCode::W, | ||
key_back: KeyCode::S, | ||
key_left: KeyCode::A, | ||
key_right: KeyCode::D, | ||
key_up: KeyCode::E, | ||
key_down: KeyCode::Q, | ||
key_run: KeyCode::LShift, | ||
walk_speed: 10.0, | ||
run_speed: 30.0, | ||
friction: 0.5, | ||
pitch: 0.0, | ||
yaw: 0.0, | ||
velocity: Vec3::ZERO, | ||
} | ||
} | ||
} | ||
|
||
fn camera_controller( | ||
time: Res<Time>, | ||
mut mouse_events: EventReader<MouseMotion>, | ||
key_input: Res<Input<KeyCode>>, | ||
mut query: Query<(&mut Transform, &mut CameraController), With<Camera>>, | ||
) { | ||
let dt = time.delta_seconds(); | ||
|
||
// Handle mouse input | ||
let mut mouse_delta = Vec2::ZERO; | ||
for mouse_event in mouse_events.iter() { | ||
mouse_delta += mouse_event.delta; | ||
} | ||
|
||
for (mut transform, mut options) in query.iter_mut() { | ||
if !options.enabled { | ||
continue; | ||
} | ||
|
||
// Handle key input | ||
let mut axis_input = Vec3::ZERO; | ||
if key_input.pressed(options.key_forward) { | ||
axis_input.z += 1.0; | ||
} | ||
if key_input.pressed(options.key_back) { | ||
axis_input.z -= 1.0; | ||
} | ||
if key_input.pressed(options.key_right) { | ||
axis_input.x += 1.0; | ||
} | ||
if key_input.pressed(options.key_left) { | ||
axis_input.x -= 1.0; | ||
} | ||
if key_input.pressed(options.key_up) { | ||
axis_input.y += 1.0; | ||
} | ||
if key_input.pressed(options.key_down) { | ||
axis_input.y -= 1.0; | ||
} | ||
|
||
// Apply movement update | ||
if axis_input != Vec3::ZERO { | ||
let max_speed = if key_input.pressed(options.key_run) { | ||
options.run_speed | ||
} else { | ||
options.walk_speed | ||
}; | ||
options.velocity = axis_input.normalize() * max_speed; | ||
} else { | ||
let friction = options.friction.clamp(0.0, 1.0); | ||
options.velocity *= 1.0 - friction; | ||
if options.velocity.length_squared() < 1e-6 { | ||
options.velocity = Vec3::ZERO; | ||
} | ||
} | ||
let forward = transform.forward(); | ||
let right = transform.right(); | ||
transform.translation += options.velocity.x * dt * right | ||
+ options.velocity.y * dt * Vec3::Y | ||
+ options.velocity.z * dt * forward; | ||
|
||
if mouse_delta != Vec2::ZERO { | ||
// Apply look update | ||
let (pitch, yaw) = ( | ||
(options.pitch - mouse_delta.y * 0.5 * options.sensitivity * dt).clamp( | ||
-0.99 * std::f32::consts::FRAC_PI_2, | ||
0.99 * std::f32::consts::FRAC_PI_2, | ||
), | ||
options.yaw - mouse_delta.x * options.sensitivity * dt, | ||
); | ||
transform.rotation = Quat::from_euler(EulerRot::ZYX, 0.0, yaw, pitch); | ||
options.pitch = pitch; | ||
options.yaw = yaw; | ||
} | ||
} | ||
} |
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.