mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 14:40:19 +00:00
d59b1e71ef
I ported the two existing PCF techniques to the cubemap domain as best I could. Generally, the technique is to create a 2D orthonormal basis using Gram-Schmidt normalization, then apply the technique over that basis. The results look fine, though the shadow bias often needs adjusting. For comparison, Unity uses a 4-tap pattern for PCF on point lights of (1, 1, 1), (-1, -1, 1), (-1, 1, -1), (1, -1, -1). I tried this but didn't like the look, so I went with the design above, which ports the 2D techniques to the 3D domain. There's surprisingly little material on point light PCF. I've gone through every example using point lights and verified that the shadow maps look fine, adjusting biases as necessary. Fixes #3628. --- ## Changelog ### Added * Shadows from point lights now support percentage-closer filtering (PCF), and as a result look less aliased. ### Changed * `ShadowFilteringMethod::Castano13` and `ShadowFilteringMethod::Jimenez14` have been renamed to `ShadowFilteringMethod::Gaussian` and `ShadowFilteringMethod::Temporal` respectively. ## Migration Guide * `ShadowFilteringMethod::Castano13` and `ShadowFilteringMethod::Jimenez14` have been renamed to `ShadowFilteringMethod::Gaussian` and `ShadowFilteringMethod::Temporal` respectively.
126 lines
3.6 KiB
Rust
126 lines
3.6 KiB
Rust
//! This example demonstrates the built-in 3d shapes in Bevy.
|
|
//! The scene includes a patterned texture and a rotation for visualizing the normals and UVs.
|
|
|
|
use std::f32::consts::PI;
|
|
|
|
use bevy::{
|
|
color::palettes::basic::SILVER,
|
|
prelude::*,
|
|
render::{
|
|
render_asset::RenderAssetUsages,
|
|
render_resource::{Extent3d, TextureDimension, TextureFormat},
|
|
},
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
|
|
.add_systems(Startup, setup)
|
|
.add_systems(Update, rotate)
|
|
.run();
|
|
}
|
|
|
|
/// A marker component for our shapes so we can query them separately from the ground plane
|
|
#[derive(Component)]
|
|
struct Shape;
|
|
|
|
const X_EXTENT: f32 = 12.0;
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut images: ResMut<Assets<Image>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
) {
|
|
let debug_material = materials.add(StandardMaterial {
|
|
base_color_texture: Some(images.add(uv_debug_texture())),
|
|
..default()
|
|
});
|
|
|
|
let shapes = [
|
|
meshes.add(Cuboid::default()),
|
|
meshes.add(Capsule3d::default()),
|
|
meshes.add(Torus::default()),
|
|
meshes.add(Cylinder::default()),
|
|
meshes.add(Sphere::default().mesh().ico(5).unwrap()),
|
|
meshes.add(Sphere::default().mesh().uv(32, 18)),
|
|
];
|
|
|
|
let num_shapes = shapes.len();
|
|
|
|
for (i, shape) in shapes.into_iter().enumerate() {
|
|
commands.spawn((
|
|
PbrBundle {
|
|
mesh: shape,
|
|
material: debug_material.clone(),
|
|
transform: Transform::from_xyz(
|
|
-X_EXTENT / 2. + i as f32 / (num_shapes - 1) as f32 * X_EXTENT,
|
|
2.0,
|
|
0.0,
|
|
)
|
|
.with_rotation(Quat::from_rotation_x(-PI / 4.)),
|
|
..default()
|
|
},
|
|
Shape,
|
|
));
|
|
}
|
|
|
|
commands.spawn(PointLightBundle {
|
|
point_light: PointLight {
|
|
shadows_enabled: true,
|
|
intensity: 10_000_000.,
|
|
range: 100.0,
|
|
shadow_depth_bias: 0.2,
|
|
..default()
|
|
},
|
|
transform: Transform::from_xyz(8.0, 16.0, 8.0),
|
|
..default()
|
|
});
|
|
|
|
// ground plane
|
|
commands.spawn(PbrBundle {
|
|
mesh: meshes.add(Plane3d::default().mesh().size(50.0, 50.0)),
|
|
material: materials.add(Color::from(SILVER)),
|
|
..default()
|
|
});
|
|
|
|
commands.spawn(Camera3dBundle {
|
|
transform: Transform::from_xyz(0.0, 6., 12.0).looking_at(Vec3::new(0., 1., 0.), Vec3::Y),
|
|
..default()
|
|
});
|
|
}
|
|
|
|
fn rotate(mut query: Query<&mut Transform, With<Shape>>, time: Res<Time>) {
|
|
for mut transform in &mut query {
|
|
transform.rotate_y(time.delta_seconds() / 2.);
|
|
}
|
|
}
|
|
|
|
/// Creates a colorful test pattern
|
|
fn uv_debug_texture() -> Image {
|
|
const TEXTURE_SIZE: usize = 8;
|
|
|
|
let mut palette: [u8; 32] = [
|
|
255, 102, 159, 255, 255, 159, 102, 255, 236, 255, 102, 255, 121, 255, 102, 255, 102, 255,
|
|
198, 255, 102, 198, 255, 255, 121, 102, 255, 255, 236, 102, 255, 255,
|
|
];
|
|
|
|
let mut texture_data = [0; TEXTURE_SIZE * TEXTURE_SIZE * 4];
|
|
for y in 0..TEXTURE_SIZE {
|
|
let offset = TEXTURE_SIZE * y * 4;
|
|
texture_data[offset..(offset + TEXTURE_SIZE * 4)].copy_from_slice(&palette);
|
|
palette.rotate_right(4);
|
|
}
|
|
|
|
Image::new_fill(
|
|
Extent3d {
|
|
width: TEXTURE_SIZE as u32,
|
|
height: TEXTURE_SIZE as u32,
|
|
depth_or_array_layers: 1,
|
|
},
|
|
TextureDimension::D2,
|
|
&texture_data,
|
|
TextureFormat::Rgba8UnormSrgb,
|
|
RenderAssetUsages::RENDER_WORLD,
|
|
)
|
|
}
|