diff --git a/Cargo.toml b/Cargo.toml index 7743c04..be6cb0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ hdr = [] sdr = [] [dependencies] -bevy = { version = "0.10", default-features = false, features = [ +bevy = { version = "0.15", default-features = false, features = [ "bevy_asset", "bevy_render", "bevy_core_pipeline", @@ -27,8 +27,9 @@ bevy = { version = "0.10", default-features = false, features = [ "tga", ] } + [dev-dependencies] -bevy = { version = "0.10", features = ["tga"] } +bevy = "0.15" color-eyre = "0.6" image = "0.24" once_cell = "1" diff --git a/assets/shaders/blur.wgsl b/assets/shaders/blur.wgsl index 0f88344..70090a7 100644 --- a/assets/shaders/blur.wgsl +++ b/assets/shaders/blur.wgsl @@ -1,5 +1,5 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals @group(0) @binding(0) var t: texture_2d; diff --git a/assets/shaders/chromatic-aberration.wgsl b/assets/shaders/chromatic-aberration.wgsl index 8e844c3..dd7feb2 100644 --- a/assets/shaders/chromatic-aberration.wgsl +++ b/assets/shaders/chromatic-aberration.wgsl @@ -1,5 +1,5 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals @group(0) @binding(0) var t: texture_2d; diff --git a/assets/shaders/flip.wgsl b/assets/shaders/flip.wgsl index ef16c4b..30a018d 100644 --- a/assets/shaders/flip.wgsl +++ b/assets/shaders/flip.wgsl @@ -1,5 +1,5 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals @group(0) @binding(0) var t: texture_2d; diff --git a/assets/shaders/lut.wgsl b/assets/shaders/lut.wgsl index ad7ed93..06dc161 100644 --- a/assets/shaders/lut.wgsl +++ b/assets/shaders/lut.wgsl @@ -1,5 +1,5 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals @group(0) @binding(0) var t: texture_2d; diff --git a/assets/shaders/masks.wgsl b/assets/shaders/masks.wgsl index d79404a..fcf3b5d 100644 --- a/assets/shaders/masks.wgsl +++ b/assets/shaders/masks.wgsl @@ -1,5 +1,5 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals @group(0) @binding(0) var t: texture_2d; diff --git a/assets/shaders/pixelate.wgsl b/assets/shaders/pixelate.wgsl index e46a9ca..63da7a2 100644 --- a/assets/shaders/pixelate.wgsl +++ b/assets/shaders/pixelate.wgsl @@ -1,5 +1,5 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals @group(0) @binding(0) var t: texture_2d; diff --git a/assets/shaders/post_processing.wgsl b/assets/shaders/post_processing.wgsl new file mode 100644 index 0000000..85baed3 --- /dev/null +++ b/assets/shaders/post_processing.wgsl @@ -0,0 +1,51 @@ +// This shader computes the chromatic aberration effect + +// Since post processing is a fullscreen effect, we use the fullscreen vertex shader provided by bevy. +// This will import a vertex shader that renders a single fullscreen triangle. +// +// A fullscreen triangle is a single triangle that covers the entire screen. +// The box in the top left in that diagram is the screen. The 4 x are the corner of the screen +// +// Y axis +// 1 | x-----x...... +// 0 | | s | . ´ +// -1 | x_____x´ +// -2 | : .´ +// -3 | :´ +// +--------------- X axis +// -1 0 1 2 3 +// +// As you can see, the triangle ends up bigger than the screen. +// +// You don't need to worry about this too much since bevy will compute the correct UVs for you. +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals + +@group(0) @binding(0) var screen_texture: texture_2d; +@group(0) @binding(1) var texture_sampler: sampler; +struct PostProcessSettings { + intensity: f32, +#ifdef SIXTEEN_BYTE_ALIGNMENT + // WebGL2 structs must be 16 byte aligned. + _webgl2_padding: vec3 +#endif +} + +@group(0) @binding(2) +var globals: Globals; + +@group(1) @binding(0) var settings: PostProcessSettings; + +@fragment +fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { + // Chromatic aberration strength + let offset_strength = settings.intensity; + + // Sample each color channel with an arbitrary shift + return vec4( + textureSample(screen_texture, texture_sampler, in.uv + vec2(offset_strength, -offset_strength)).r, + textureSample(screen_texture, texture_sampler, in.uv + vec2(-offset_strength, 0.0)).g, + textureSample(screen_texture, texture_sampler, in.uv + vec2(0.0, offset_strength)).b, + 1.0 + ); +} \ No newline at end of file diff --git a/assets/shaders/raindrops.wgsl b/assets/shaders/raindrops.wgsl index 0e61722..86c1fd4 100644 --- a/assets/shaders/raindrops.wgsl +++ b/assets/shaders/raindrops.wgsl @@ -1,5 +1,5 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals @group(0) @binding(0) var t: texture_2d; diff --git a/assets/shaders/wave.wgsl b/assets/shaders/wave.wgsl index 9316c68..9c11977 100644 --- a/assets/shaders/wave.wgsl +++ b/assets/shaders/wave.wgsl @@ -1,6 +1,6 @@ -#import bevy_core_pipeline::fullscreen_vertex_shader -#import bevy_render::globals -#import bevy_pbr::utils +#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput +#import bevy_render::globals::Globals +#import bevy_render::maths::PI @group(0) @binding(0) var source: texture_2d; diff --git a/examples/examples_common.rs b/examples/examples_common.rs index 32d4517..3e5fb99 100644 --- a/examples/examples_common.rs +++ b/examples/examples_common.rs @@ -25,12 +25,21 @@ impl Plugin for SaneDefaultsPlugin { app.add_plugins( DefaultPlugins .set(AssetPlugin { - watch_for_changes: true, + watch_for_changes_override: Some(true), ..default() }) .set(ImagePlugin::default_nearest()), ) - .add_system(bevy::window::close_on_esc); + .add_systems(Update, close_on_esc_system); + } +} + +fn close_on_esc_system( + keyboard_input: Res>, + mut app_exit_events: EventWriter, +) { + if keyboard_input.just_pressed(KeyCode::Escape) { + app_exit_events.send(AppExit::Success); } } @@ -59,20 +68,24 @@ pub(crate) struct ShouldAdd3dCameraBundle(bool); impl Plugin for ShapesExamplePlugin { fn build(&self, app: &mut App) { app.insert_resource(ShouldAdd3dCameraBundle(self.add_3d_camera_bundle)) - .add_plugin(FrameTimeDiagnosticsPlugin::default()) - .add_startup_system(shapes::setup) - .add_startup_system(ui::setup) - .add_system(shapes::rotate) - .add_system(ui::fps_text_update); + .add_plugins(FrameTimeDiagnosticsPlugin) + .add_systems(Startup, shapes::setup) + .add_systems(Startup, ui::setup) + .add_systems(Update, shapes::rotate) + .add_systems(Update, ui::fps_text_update); } } #[derive(Component)] pub(crate) struct Shape; -const X_EXTENT: f32 = 14.; +const SHAPES_X_EXTENT: f32 = 14.0; +const EXTRUSION_X_EXTENT: f32 = 16.0; +const Z_EXTENT: f32 = 5.0; mod shapes { + use bevy::{asset::RenderAssetUsages, color::palettes::css::SILVER}; + use super::*; pub(crate) fn setup( @@ -88,82 +101,99 @@ mod shapes { }); let shapes = [ - meshes.add(shape::Cube::default().into()), - meshes.add(shape::Box::default().into()), - meshes.add(shape::Capsule::default().into()), - meshes.add(shape::Torus::default().into()), - meshes.add(shape::Icosphere::default().try_into().unwrap()), - meshes.add(shape::UVSphere::default().into()), + meshes.add(Cuboid::default()), + meshes.add(Tetrahedron::default()), + meshes.add(Capsule3d::default()), + meshes.add(Torus::default()), + meshes.add(Cylinder::default()), + meshes.add(Cone::default()), + meshes.add(ConicalFrustum::default()), + meshes.add(Sphere::default().mesh().ico(5).unwrap()), + meshes.add(Sphere::default().mesh().uv(32, 18)), + ]; + + let extrusions = [ + meshes.add(Extrusion::new(Rectangle::default(), 1.)), + meshes.add(Extrusion::new(Capsule2d::default(), 1.)), + meshes.add(Extrusion::new(Annulus::default(), 1.)), + meshes.add(Extrusion::new(Circle::default(), 1.)), + meshes.add(Extrusion::new(Ellipse::default(), 1.)), + meshes.add(Extrusion::new(RegularPolygon::default(), 1.)), + meshes.add(Extrusion::new(Triangle2d::default(), 1.)), ]; let num_shapes = shapes.len(); for (i, shape) in shapes.into_iter().enumerate() { - commands - .spawn(PbrBundle { - mesh: shape.clone(), - 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() - }) - .insert(Shape); - - 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() - }) - .insert(Shape); + commands.spawn(( + Mesh3d(shape), + MeshMaterial3d(debug_material.clone()), + Transform::from_xyz( + -SHAPES_X_EXTENT / 2. + i as f32 / (num_shapes - 1) as f32 * SHAPES_X_EXTENT, + 2.0, + Z_EXTENT / 2., + ) + .with_rotation(Quat::from_rotation_x(-PI / 4.)), + Shape, + )); } - commands.spawn(PointLightBundle { - point_light: PointLight { - intensity: 9000.0, - range: 100., + let num_extrusions = extrusions.len(); + + for (i, shape) in extrusions.into_iter().enumerate() { + commands.spawn(( + Mesh3d(shape), + MeshMaterial3d(debug_material.clone()), + Transform::from_xyz( + -EXTRUSION_X_EXTENT / 2. + + i as f32 / (num_extrusions - 1) as f32 * EXTRUSION_X_EXTENT, + 2.0, + -Z_EXTENT / 2., + ) + .with_rotation(Quat::from_rotation_x(-PI / 4.)), + Shape, + )); + } + + commands.spawn(( + 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() - }); + Transform::from_xyz(8.0, 16.0, 8.0), + )); // ground plane - commands.spawn(PbrBundle { - mesh: meshes.add( - shape::Plane { - size: 50., - ..default() - } - .into(), - ), - material: materials.add(Color::SILVER.into()), - ..default() - }); + commands.spawn(( + Mesh3d(meshes.add(Plane3d::default().mesh().size(50.0, 50.0).subdivisions(10))), + MeshMaterial3d(materials.add(Color::from(SILVER))), + )); if add_3d_camera_bundle.0 { - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(0.0, 6., 12.0) - .looking_at(Vec3::new(0., 1., 0.), Vec3::Y), - ..default() - }); + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(0.0, 7., 14.0).looking_at(Vec3::new(0., 1., 0.), Vec3::Y), + )); } + + // #[cfg(not(target_arch = "wasm32"))] + // commands.spawn(( + // Text::new("Press space to toggle wireframes"), + // Node { + // position_type: PositionType::Absolute, + // top: Val::Px(12.0), + // left: Val::Px(12.0), + // ..default() + // }, + // )); } pub(crate) fn rotate(mut query: Query<&mut Transform, With>, time: Res