,
name: &str,
curve: CubicCurve,
diff --git a/benches/benches/bevy_picking/ray_mesh_intersection.rs b/benches/benches/bevy_picking/ray_mesh_intersection.rs
index 871a6d1062..e9fd0caf9f 100644
--- a/benches/benches/bevy_picking/ray_mesh_intersection.rs
+++ b/benches/benches/bevy_picking/ray_mesh_intersection.rs
@@ -155,6 +155,7 @@ fn bench(c: &mut Criterion) {
&mesh.positions,
Some(&mesh.normals),
Some(&mesh.indices),
+ None,
backface_culling,
);
diff --git a/benches/benches/bevy_reflect/map.rs b/benches/benches/bevy_reflect/map.rs
index 1eab01a587..a70f89e12b 100644
--- a/benches/benches/bevy_reflect/map.rs
+++ b/benches/benches/bevy_reflect/map.rs
@@ -142,7 +142,7 @@ fn concrete_map_apply(criterion: &mut Criterion) {
fn u64_to_n_byte_key(k: u64, n: usize) -> String {
let mut key = String::with_capacity(n);
- write!(&mut key, "{}", k).unwrap();
+ write!(&mut key, "{k}").unwrap();
// Pad key to n bytes.
key.extend(iter::repeat_n('\0', n - key.len()));
diff --git a/benches/benches/bevy_reflect/struct.rs b/benches/benches/bevy_reflect/struct.rs
index 7750213b6d..52d539f64d 100644
--- a/benches/benches/bevy_reflect/struct.rs
+++ b/benches/benches/bevy_reflect/struct.rs
@@ -55,7 +55,7 @@ fn concrete_struct_field(criterion: &mut Criterion) {
&s,
|bencher, s| {
let field_names = (0..field_count)
- .map(|i| format!("field_{}", i))
+ .map(|i| format!("field_{i}"))
.collect::>();
bencher.iter(|| {
@@ -256,7 +256,7 @@ fn dynamic_struct_apply(criterion: &mut Criterion) {
let mut base = DynamicStruct::default();
for i in 0..field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
base.insert(&field_name, 1u32);
}
@@ -283,7 +283,7 @@ fn dynamic_struct_apply(criterion: &mut Criterion) {
let mut base = DynamicStruct::default();
let mut patch = DynamicStruct::default();
for i in 0..field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
base.insert(&field_name, 0u32);
patch.insert(&field_name, 1u32);
}
@@ -309,11 +309,11 @@ fn dynamic_struct_insert(criterion: &mut Criterion) {
|bencher, field_count| {
let mut s = DynamicStruct::default();
for i in 0..*field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
s.insert(&field_name, ());
}
- let field = format!("field_{}", field_count);
+ let field = format!("field_{field_count}");
bencher.iter_batched(
|| s.to_dynamic_struct(),
|mut s| {
@@ -339,7 +339,7 @@ fn dynamic_struct_get_field(criterion: &mut Criterion) {
|bencher, field_count| {
let mut s = DynamicStruct::default();
for i in 0..*field_count {
- let field_name = format!("field_{}", i);
+ let field_name = format!("field_{i}");
s.insert(&field_name, ());
}
diff --git a/clippy.toml b/clippy.toml
index 2c98e8ed02..372ffbaf0b 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -41,7 +41,6 @@ disallowed-methods = [
{ path = "f32::asinh", reason = "use bevy_math::ops::asinh instead for libm determinism" },
{ path = "f32::acosh", reason = "use bevy_math::ops::acosh instead for libm determinism" },
{ path = "f32::atanh", reason = "use bevy_math::ops::atanh instead for libm determinism" },
- { path = "criterion::black_box", reason = "use core::hint::black_box instead" },
]
# Require `bevy_ecs::children!` to use `[]` braces, instead of `()` or `{}`.
diff --git a/crates/bevy_a11y/Cargo.toml b/crates/bevy_a11y/Cargo.toml
index 759cf3e787..70ee16cf77 100644
--- a/crates/bevy_a11y/Cargo.toml
+++ b/crates/bevy_a11y/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "bevy_a11y"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides accessibility support for Bevy Engine"
-homepage = "https://bevyengine.org"
+homepage = "https://bevy.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
keywords = ["bevy", "accessibility", "a11y"]
@@ -40,13 +40,13 @@ critical-section = [
[dependencies]
# bevy
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev", default-features = false }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev", default-features = false }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
# other
-accesskit = { version = "0.18", default-features = false }
+accesskit = { version = "0.19", default-features = false }
serde = { version = "1", default-features = false, features = [
"alloc",
], optional = true }
diff --git a/crates/bevy_a11y/src/lib.rs b/crates/bevy_a11y/src/lib.rs
index 94468c148c..22b2f71f07 100644
--- a/crates/bevy_a11y/src/lib.rs
+++ b/crates/bevy_a11y/src/lib.rs
@@ -1,8 +1,8 @@
#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(
- html_logo_url = "https://bevyengine.org/assets/icon.png",
- html_favicon_url = "https://bevyengine.org/assets/icon.png"
+ html_logo_url = "https://bevy.org/assets/icon.png",
+ html_favicon_url = "https://bevy.org/assets/icon.png"
)]
#![no_std]
@@ -26,7 +26,8 @@ use accesskit::Node;
use bevy_app::Plugin;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
- prelude::{Component, Event},
+ component::Component,
+ event::{BufferedEvent, Event},
resource::Resource,
schedule::SystemSet,
};
@@ -44,7 +45,7 @@ use serde::{Deserialize, Serialize};
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
/// Wrapper struct for [`accesskit::ActionRequest`]. Required to allow it to be used as an `Event`.
-#[derive(Event, Deref, DerefMut)]
+#[derive(Event, BufferedEvent, Deref, DerefMut)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ActionRequest(pub accesskit::ActionRequest);
diff --git a/crates/bevy_animation/Cargo.toml b/crates/bevy_animation/Cargo.toml
index 11e819806c..731a6c7c4f 100644
--- a/crates/bevy_animation/Cargo.toml
+++ b/crates/bevy_animation/Cargo.toml
@@ -1,47 +1,46 @@
[package]
name = "bevy_animation"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides animation functionality for Bevy Engine"
-homepage = "https://bevyengine.org"
+homepage = "https://bevy.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
keywords = ["bevy"]
[dependencies]
# bevy
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
-bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
-bevy_color = { path = "../bevy_color", version = "0.16.0-dev" }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
-bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
-bevy_mesh = { path = "../bevy_mesh", version = "0.16.0-dev" }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
+bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
+bevy_color = { path = "../bevy_color", version = "0.17.0-dev" }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
+bevy_mesh = { path = "../bevy_mesh", version = "0.17.0-dev" }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", features = [
"petgraph",
] }
-bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
-bevy_time = { path = "../bevy_time", version = "0.16.0-dev" }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
-bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" }
-bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false, features = [
+bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
+bevy_time = { path = "../bevy_time", version = "0.17.0-dev" }
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
+bevy_transform = { path = "../bevy_transform", version = "0.17.0-dev" }
+bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
"serialize",
] }
# other
-petgraph = { version = "0.7", features = ["serde-1"] }
-ron = "0.8"
+petgraph = { version = "0.8", features = ["serde-1"] }
+ron = "0.10"
serde = "1"
blake3 = { version = "1.0" }
downcast-rs = { version = "2", default-features = false, features = ["std"] }
thiserror = { version = "2", default-features = false }
-derive_more = { version = "1", default-features = false, features = ["from"] }
+derive_more = { version = "2", default-features = false, features = ["from"] }
either = "1.13"
thread_local = "1"
uuid = { version = "1.13.1", features = ["v4"] }
-smallvec = "1"
+smallvec = { version = "1", default-features = false }
tracing = { version = "0.1", default-features = false, features = ["std"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
diff --git a/crates/bevy_animation/src/gltf_curves.rs b/crates/bevy_animation/src/gltf_curves.rs
index 688011a32c..593ca04d2e 100644
--- a/crates/bevy_animation/src/gltf_curves.rs
+++ b/crates/bevy_animation/src/gltf_curves.rs
@@ -55,7 +55,7 @@ pub struct CubicKeyframeCurve {
impl Curve for CubicKeyframeCurve
where
- V: VectorSpace,
+ V: VectorSpace,
{
#[inline]
fn domain(&self) -> Interval {
@@ -179,7 +179,7 @@ pub struct WideLinearKeyframeCurve {
impl IterableCurve for WideLinearKeyframeCurve
where
- T: VectorSpace,
+ T: VectorSpace,
{
#[inline]
fn domain(&self) -> Interval {
@@ -289,7 +289,7 @@ pub struct WideCubicKeyframeCurve {
impl IterableCurve for WideCubicKeyframeCurve
where
- T: VectorSpace,
+ T: VectorSpace,
{
#[inline]
fn domain(&self) -> Interval {
@@ -406,7 +406,7 @@ fn cubic_spline_interpolation(
step_duration: f32,
) -> T
where
- T: VectorSpace,
+ T: VectorSpace,
{
let coeffs = (vec4(2.0, 1.0, -2.0, 1.0) * lerp + vec4(-3.0, -2.0, 3.0, -1.0)) * lerp;
value_start * (coeffs.x * lerp + 1.0)
@@ -415,7 +415,7 @@ where
+ tangent_in_end * step_duration * lerp * coeffs.w
}
-fn cubic_spline_interpolate_slices<'a, T: VectorSpace>(
+fn cubic_spline_interpolate_slices<'a, T: VectorSpace>(
width: usize,
first: &'a [T],
second: &'a [T],
diff --git a/crates/bevy_animation/src/graph.rs b/crates/bevy_animation/src/graph.rs
index aa6d252fee..adb4a7c7ac 100644
--- a/crates/bevy_animation/src/graph.rs
+++ b/crates/bevy_animation/src/graph.rs
@@ -1,10 +1,11 @@
//! The animation graph, which allows animations to be blended together.
use core::{
+ fmt::Write,
iter,
ops::{Index, IndexMut, Range},
};
-use std::io::{self, Write};
+use std::io;
use bevy_asset::{
io::Reader, Asset, AssetEvent, AssetId, AssetLoader, AssetPath, Assets, Handle, LoadContext,
@@ -18,7 +19,7 @@ use bevy_ecs::{
system::{Res, ResMut},
};
use bevy_platform::collections::HashMap;
-use bevy_reflect::{prelude::ReflectDefault, Reflect, ReflectSerialize};
+use bevy_reflect::{prelude::ReflectDefault, Reflect};
use derive_more::derive::From;
use petgraph::{
graph::{DiGraph, NodeIndex},
@@ -28,6 +29,7 @@ use ron::de::SpannedError;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use thiserror::Error;
+use tracing::warn;
use crate::{AnimationClip, AnimationTargetId};
@@ -107,9 +109,8 @@ use crate::{AnimationClip, AnimationTargetId};
/// [RON]: https://github.com/ron-rs/ron
///
/// [RFC 51]: https://github.com/bevyengine/rfcs/blob/main/rfcs/51-animation-composition.md
-#[derive(Asset, Reflect, Clone, Debug, Serialize)]
-#[reflect(Serialize, Debug, Clone)]
-#[serde(into = "SerializedAnimationGraph")]
+#[derive(Asset, Reflect, Clone, Debug)]
+#[reflect(Debug, Clone)]
pub struct AnimationGraph {
/// The `petgraph` data structure that defines the animation graph.
pub graph: AnimationDiGraph,
@@ -241,20 +242,40 @@ pub enum AnimationNodeType {
#[derive(Default)]
pub struct AnimationGraphAssetLoader;
-/// Various errors that can occur when serializing or deserializing animation
-/// graphs to and from RON, respectively.
+/// Errors that can occur when serializing animation graphs to RON.
+#[derive(Error, Debug)]
+pub enum AnimationGraphSaveError {
+ /// An I/O error occurred.
+ #[error(transparent)]
+ Io(#[from] io::Error),
+ /// An error occurred in RON serialization.
+ #[error(transparent)]
+ Ron(#[from] ron::Error),
+ /// An error occurred converting the graph to its serialization form.
+ #[error(transparent)]
+ ConvertToSerialized(#[from] NonPathHandleError),
+}
+
+/// Errors that can occur when deserializing animation graphs from RON.
#[derive(Error, Debug)]
pub enum AnimationGraphLoadError {
/// An I/O error occurred.
- #[error("I/O")]
+ #[error(transparent)]
Io(#[from] io::Error),
- /// An error occurred in RON serialization or deserialization.
- #[error("RON serialization")]
+ /// An error occurred in RON deserialization.
+ #[error(transparent)]
Ron(#[from] ron::Error),
/// An error occurred in RON deserialization, and the location of the error
/// is supplied.
- #[error("RON serialization")]
+ #[error(transparent)]
SpannedRon(#[from] SpannedError),
+ /// The deserialized graph contained legacy data that we no longer support.
+ #[error(
+ "The deserialized AnimationGraph contained an AnimationClip referenced by an AssetId, \
+ which is no longer supported. Consider manually deserializing the SerializedAnimationGraph \
+ type and determine how to migrate any SerializedAnimationClip::AssetId animation clips"
+ )]
+ GraphContainsLegacyAssetId,
}
/// Acceleration structures for animation graphs that allows Bevy to evaluate
@@ -387,18 +408,32 @@ pub struct SerializedAnimationGraphNode {
#[derive(Serialize, Deserialize)]
pub enum SerializedAnimationNodeType {
/// Corresponds to [`AnimationNodeType::Clip`].
- Clip(SerializedAnimationClip),
+ Clip(MigrationSerializedAnimationClip),
/// Corresponds to [`AnimationNodeType::Blend`].
Blend,
/// Corresponds to [`AnimationNodeType::Add`].
Add,
}
-/// A version of `Handle` suitable for serializing as an asset.
+/// A type to facilitate migration from the legacy format of [`SerializedAnimationGraph`] to the
+/// new format.
///
-/// This replaces any handle that has a path with an [`AssetPath`]. Failing
-/// that, the asset ID is serialized directly.
+/// By using untagged serde deserialization, we can try to deserialize the modern form, then
+/// fallback to the legacy form. Users must migrate to the modern form by Bevy 0.18.
+// TODO: Delete this after Bevy 0.17.
#[derive(Serialize, Deserialize)]
+#[serde(untagged)]
+pub enum MigrationSerializedAnimationClip {
+ /// This is the new type of this field.
+ Modern(AssetPath<'static>),
+ /// This is the legacy type of this field. Users must migrate away from this.
+ #[serde(skip_serializing)]
+ Legacy(SerializedAnimationClip),
+}
+
+/// The legacy form of serialized animation clips. This allows raw asset IDs to be deserialized.
+// TODO: Delete this after Bevy 0.17.
+#[derive(Deserialize)]
pub enum SerializedAnimationClip {
/// Records an asset path.
AssetPath(AssetPath<'static>),
@@ -647,12 +682,13 @@ impl AnimationGraph {
///
/// If writing to a file, it can later be loaded with the
/// [`AnimationGraphAssetLoader`] to reconstruct the graph.
- pub fn save(&self, writer: &mut W) -> Result<(), AnimationGraphLoadError>
+ pub fn save(&self, writer: &mut W) -> Result<(), AnimationGraphSaveError>
where
W: Write,
{
let mut ron_serializer = ron::ser::Serializer::new(writer, None)?;
- Ok(self.serialize(&mut ron_serializer)?)
+ let serialized_graph: SerializedAnimationGraph = self.clone().try_into()?;
+ Ok(serialized_graph.serialize(&mut ron_serializer)?)
}
/// Adds an animation target (bone) to the mask group with the given ID.
@@ -757,28 +793,55 @@ impl AssetLoader for AnimationGraphAssetLoader {
let serialized_animation_graph = SerializedAnimationGraph::deserialize(&mut deserializer)
.map_err(|err| deserializer.span_error(err))?;
- // Load all `AssetPath`s to convert from a
- // `SerializedAnimationGraph` to a real `AnimationGraph`.
- Ok(AnimationGraph {
- graph: serialized_animation_graph.graph.map(
- |_, serialized_node| AnimationGraphNode {
- node_type: match serialized_node.node_type {
- SerializedAnimationNodeType::Clip(ref clip) => match clip {
- SerializedAnimationClip::AssetId(asset_id) => {
- AnimationNodeType::Clip(Handle::Weak(*asset_id))
+ // Load all `AssetPath`s to convert from a `SerializedAnimationGraph` to a real
+ // `AnimationGraph`. This is effectively a `DiGraph::map`, but this allows us to return
+ // errors.
+ let mut animation_graph = DiGraph::with_capacity(
+ serialized_animation_graph.graph.node_count(),
+ serialized_animation_graph.graph.edge_count(),
+ );
+
+ let mut already_warned = false;
+ for serialized_node in serialized_animation_graph.graph.node_weights() {
+ animation_graph.add_node(AnimationGraphNode {
+ node_type: match serialized_node.node_type {
+ SerializedAnimationNodeType::Clip(ref clip) => match clip {
+ MigrationSerializedAnimationClip::Modern(path) => {
+ AnimationNodeType::Clip(load_context.load(path.clone()))
+ }
+ MigrationSerializedAnimationClip::Legacy(
+ SerializedAnimationClip::AssetPath(path),
+ ) => {
+ if !already_warned {
+ let path = load_context.asset_path();
+ warn!(
+ "Loaded an AnimationGraph asset at \"{path}\" which contains a \
+ legacy-style SerializedAnimationClip. Please re-save the asset \
+ using AnimationGraph::save to automatically migrate to the new \
+ format"
+ );
+ already_warned = true;
}
- SerializedAnimationClip::AssetPath(asset_path) => {
- AnimationNodeType::Clip(load_context.load(asset_path))
- }
- },
- SerializedAnimationNodeType::Blend => AnimationNodeType::Blend,
- SerializedAnimationNodeType::Add => AnimationNodeType::Add,
+ AnimationNodeType::Clip(load_context.load(path.clone()))
+ }
+ MigrationSerializedAnimationClip::Legacy(
+ SerializedAnimationClip::AssetId(_),
+ ) => {
+ return Err(AnimationGraphLoadError::GraphContainsLegacyAssetId);
+ }
},
- mask: serialized_node.mask,
- weight: serialized_node.weight,
+ SerializedAnimationNodeType::Blend => AnimationNodeType::Blend,
+ SerializedAnimationNodeType::Add => AnimationNodeType::Add,
},
- |_, _| (),
- ),
+ mask: serialized_node.mask,
+ weight: serialized_node.weight,
+ });
+ }
+ for edge in serialized_animation_graph.graph.raw_edges() {
+ animation_graph.add_edge(edge.source(), edge.target(), ());
+ }
+ Ok(AnimationGraph {
+ graph: animation_graph,
root: serialized_animation_graph.root,
mask_groups: serialized_animation_graph.mask_groups,
})
@@ -789,37 +852,50 @@ impl AssetLoader for AnimationGraphAssetLoader {
}
}
-impl From for SerializedAnimationGraph {
- fn from(animation_graph: AnimationGraph) -> Self {
- // If any of the animation clips have paths, then serialize them as
- // `SerializedAnimationClip::AssetPath` so that the
- // `AnimationGraphAssetLoader` can load them.
- Self {
- graph: animation_graph.graph.map(
- |_, node| SerializedAnimationGraphNode {
- weight: node.weight,
- mask: node.mask,
- node_type: match node.node_type {
- AnimationNodeType::Clip(ref clip) => match clip.path() {
- Some(path) => SerializedAnimationNodeType::Clip(
- SerializedAnimationClip::AssetPath(path.clone()),
- ),
- None => SerializedAnimationNodeType::Clip(
- SerializedAnimationClip::AssetId(clip.id()),
- ),
- },
- AnimationNodeType::Blend => SerializedAnimationNodeType::Blend,
- AnimationNodeType::Add => SerializedAnimationNodeType::Add,
+impl TryFrom for SerializedAnimationGraph {
+ type Error = NonPathHandleError;
+
+ fn try_from(animation_graph: AnimationGraph) -> Result {
+ // Convert all the `Handle` to AssetPath, so that
+ // `AnimationGraphAssetLoader` can load them. This is effectively just doing a
+ // `DiGraph::map`, except we need to return an error if any handles aren't associated to a
+ // path.
+ let mut serialized_graph = DiGraph::with_capacity(
+ animation_graph.graph.node_count(),
+ animation_graph.graph.edge_count(),
+ );
+ for node in animation_graph.graph.node_weights() {
+ serialized_graph.add_node(SerializedAnimationGraphNode {
+ weight: node.weight,
+ mask: node.mask,
+ node_type: match node.node_type {
+ AnimationNodeType::Clip(ref clip) => match clip.path() {
+ Some(path) => SerializedAnimationNodeType::Clip(
+ MigrationSerializedAnimationClip::Modern(path.clone()),
+ ),
+ None => return Err(NonPathHandleError),
},
+ AnimationNodeType::Blend => SerializedAnimationNodeType::Blend,
+ AnimationNodeType::Add => SerializedAnimationNodeType::Add,
},
- |_, _| (),
- ),
+ });
+ }
+ for edge in animation_graph.graph.raw_edges() {
+ serialized_graph.add_edge(edge.source(), edge.target(), ());
+ }
+ Ok(Self {
+ graph: serialized_graph,
root: animation_graph.root,
mask_groups: animation_graph.mask_groups,
- }
+ })
}
}
+/// Error for when only path [`Handle`]s are supported.
+#[derive(Error, Debug)]
+#[error("AnimationGraph contains a handle to an AnimationClip that does not correspond to an asset path")]
+pub struct NonPathHandleError;
+
/// A system that creates, updates, and removes [`ThreadedAnimationGraph`]
/// structures for every changed [`AnimationGraph`].
///
diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs
index 21ea15f96f..ae7ce42ed6 100644
--- a/crates/bevy_animation/src/lib.rs
+++ b/crates/bevy_animation/src/lib.rs
@@ -1,8 +1,8 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![forbid(unsafe_code)]
#![doc(
- html_logo_url = "https://bevyengine.org/assets/icon.png",
- html_favicon_url = "https://bevyengine.org/assets/icon.png"
+ html_logo_url = "https://bevy.org/assets/icon.png",
+ html_favicon_url = "https://bevy.org/assets/icon.png"
)]
//! Animation for the game engine Bevy
@@ -324,13 +324,13 @@ impl AnimationClip {
.push(variable_curve);
}
- /// Add a untargeted [`Event`] to this [`AnimationClip`].
+ /// Add an [`EntityEvent`] with no [`AnimationTarget`] to this [`AnimationClip`].
///
/// The `event` will be cloned and triggered on the [`AnimationPlayer`] entity once the `time` (in seconds)
/// is reached in the animation.
///
/// See also [`add_event_to_target`](Self::add_event_to_target).
- pub fn add_event(&mut self, time: f32, event: impl Event + Clone) {
+ pub fn add_event(&mut self, time: f32, event: impl EntityEvent + Clone) {
self.add_event_fn(
time,
move |commands: &mut Commands, entity: Entity, _time: f32, _weight: f32| {
@@ -339,7 +339,7 @@ impl AnimationClip {
);
}
- /// Add an [`Event`] to an [`AnimationTarget`] named by an [`AnimationTargetId`].
+ /// Add an [`EntityEvent`] to an [`AnimationTarget`] named by an [`AnimationTargetId`].
///
/// The `event` will be cloned and triggered on the entity matching the target once the `time` (in seconds)
/// is reached in the animation.
@@ -349,7 +349,7 @@ impl AnimationClip {
&mut self,
target_id: AnimationTargetId,
time: f32,
- event: impl Event + Clone,
+ event: impl EntityEvent + Clone,
) {
self.add_event_fn_to_target(
target_id,
@@ -360,19 +360,19 @@ impl AnimationClip {
);
}
- /// Add a untargeted event function to this [`AnimationClip`].
+ /// Add an event function with no [`AnimationTarget`] to this [`AnimationClip`].
///
/// The `func` will trigger on the [`AnimationPlayer`] entity once the `time` (in seconds)
/// is reached in the animation.
///
- /// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event`].
+ /// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event`].
/// See also [`add_event_to_target`](Self::add_event_to_target).
///
/// ```
/// # use bevy_animation::AnimationClip;
/// # let mut clip = AnimationClip::default();
/// clip.add_event_fn(1.0, |commands, entity, time, weight| {
- /// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}");
+ /// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
/// })
/// ```
pub fn add_event_fn(
@@ -388,14 +388,14 @@ impl AnimationClip {
/// The `func` will trigger on the entity matching the target once the `time` (in seconds)
/// is reached in the animation.
///
- /// For a simpler [`Event`]-based alternative, see [`AnimationClip::add_event_to_target`].
+ /// For a simpler [`EntityEvent`]-based alternative, see [`AnimationClip::add_event_to_target`].
/// Use [`add_event`](Self::add_event) instead if you don't have a specific target.
///
/// ```
/// # use bevy_animation::{AnimationClip, AnimationTargetId};
/// # let mut clip = AnimationClip::default();
/// clip.add_event_fn_to_target(AnimationTargetId::from_iter(["Arm", "Hand"]), 1.0, |commands, entity, time, weight| {
- /// println!("Animation Event Triggered {entity:#?} at time {time} with weight {weight}");
+ /// println!("Animation event triggered {entity:#?} at time {time} with weight {weight}");
/// })
/// ```
pub fn add_event_fn_to_target(
@@ -1534,7 +1534,7 @@ mod tests {
use super::*;
- #[derive(Event, Reflect, Clone)]
+ #[derive(Event, EntityEvent, Reflect, Clone)]
struct A;
#[track_caller]
diff --git a/crates/bevy_anti_aliasing/Cargo.toml b/crates/bevy_anti_aliasing/Cargo.toml
index 5a8e48ecb5..8c32d70fff 100644
--- a/crates/bevy_anti_aliasing/Cargo.toml
+++ b/crates/bevy_anti_aliasing/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "bevy_anti_aliasing"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides various anti aliasing implementations for Bevy Engine"
-homepage = "https://bevyengine.org"
+homepage = "https://bevy.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
keywords = ["bevy"]
@@ -16,17 +16,17 @@ smaa_luts = ["bevy_render/ktx2", "bevy_image/ktx2", "bevy_image/zstd"]
[dependencies]
# bevy
-bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" }
-bevy_render = { path = "../bevy_render", version = "0.16.0-dev" }
-bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" }
-bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
-bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
-bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.16.0-dev" }
-bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
+bevy_asset = { path = "../bevy_asset", version = "0.17.0-dev" }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
+bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
+bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev" }
+bevy_app = { path = "../bevy_app", version = "0.17.0-dev" }
+bevy_image = { path = "../bevy_image", version = "0.17.0-dev" }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev" }
+bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.17.0-dev" }
+bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.17.0-dev" }
# other
tracing = { version = "0.1", default-features = false, features = ["std"] }
diff --git a/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs b/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs
index 707d75819d..872175dbc7 100644
--- a/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs
+++ b/crates/bevy_anti_aliasing/src/contrast_adaptive_sharpening/mod.rs
@@ -1,9 +1,9 @@
use bevy_app::prelude::*;
-use bevy_asset::{load_internal_asset, weak_handle, Handle};
+use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
+ FullscreenShader,
};
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_image::BevyDefault as _;
@@ -11,15 +11,16 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin},
prelude::Camera,
- render_graph::RenderGraphApp,
+ render_graph::RenderGraphExt,
render_resource::{
binding_types::{sampler, texture_2d, uniform_buffer},
*,
},
renderer::RenderDevice,
view::{ExtractedView, ViewTarget},
- Render, RenderApp, RenderSystems,
+ Render, RenderApp, RenderStartup, RenderSystems,
};
+use bevy_utils::default;
mod node;
@@ -95,20 +96,12 @@ impl ExtractComponent for ContrastAdaptiveSharpening {
}
}
-const CONTRAST_ADAPTIVE_SHARPENING_SHADER_HANDLE: Handle =
- weak_handle!("ef83f0a5-51df-4b51-9ab7-b5fd1ae5a397");
-
/// Adds Support for Contrast Adaptive Sharpening (CAS).
pub struct CasPlugin;
impl Plugin for CasPlugin {
fn build(&self, app: &mut App) {
- load_internal_asset!(
- app,
- CONTRAST_ADAPTIVE_SHARPENING_SHADER_HANDLE,
- "robust_contrast_adaptive_sharpening.wgsl",
- Shader::from_wgsl
- );
+ embedded_asset!(app, "robust_contrast_adaptive_sharpening.wgsl");
app.register_type::();
app.add_plugins((
@@ -121,6 +114,7 @@ impl Plugin for CasPlugin {
};
render_app
.init_resource::>()
+ .add_systems(RenderStartup, init_cas_pipeline)
.add_systems(Render, prepare_cas_pipelines.in_set(RenderSystems::Prepare));
{
@@ -158,44 +152,46 @@ impl Plugin for CasPlugin {
);
}
}
-
- fn finish(&self, app: &mut App) {
- let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
- return;
- };
- render_app.init_resource::();
- }
}
#[derive(Resource)]
pub struct CasPipeline {
texture_bind_group: BindGroupLayout,
sampler: Sampler,
+ fullscreen_shader: FullscreenShader,
+ fragment_shader: Handle,
}
-impl FromWorld for CasPipeline {
- fn from_world(render_world: &mut World) -> Self {
- let render_device = render_world.resource::();
- let texture_bind_group = render_device.create_bind_group_layout(
- "sharpening_texture_bind_group_layout",
- &BindGroupLayoutEntries::sequential(
- ShaderStages::FRAGMENT,
- (
- texture_2d(TextureSampleType::Float { filterable: true }),
- sampler(SamplerBindingType::Filtering),
- // CAS Settings
- uniform_buffer::(true),
- ),
+pub fn init_cas_pipeline(
+ mut commands: Commands,
+ render_device: Res,
+ fullscreen_shader: Res,
+ asset_server: Res,
+) {
+ let texture_bind_group = render_device.create_bind_group_layout(
+ "sharpening_texture_bind_group_layout",
+ &BindGroupLayoutEntries::sequential(
+ ShaderStages::FRAGMENT,
+ (
+ texture_2d(TextureSampleType::Float { filterable: true }),
+ sampler(SamplerBindingType::Filtering),
+ // CAS Settings
+ uniform_buffer::(true),
),
- );
+ ),
+ );
- let sampler = render_device.create_sampler(&SamplerDescriptor::default());
+ let sampler = render_device.create_sampler(&SamplerDescriptor::default());
- CasPipeline {
- texture_bind_group,
- sampler,
- }
- }
+ commands.insert_resource(CasPipeline {
+ texture_bind_group,
+ sampler,
+ fullscreen_shader: fullscreen_shader.clone(),
+ fragment_shader: load_embedded_asset!(
+ asset_server.as_ref(),
+ "robust_contrast_adaptive_sharpening.wgsl"
+ ),
+ });
}
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
@@ -215,22 +211,18 @@ impl SpecializedRenderPipeline for CasPipeline {
RenderPipelineDescriptor {
label: Some("contrast_adaptive_sharpening".into()),
layout: vec![self.texture_bind_group.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: CONTRAST_ADAPTIVE_SHARPENING_SHADER_HANDLE,
+ shader: self.fragment_shader.clone(),
shader_defs,
- entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format: key.texture_format,
blend: None,
write_mask: ColorWrites::ALL,
})],
+ ..default()
}),
- primitive: PrimitiveState::default(),
- depth_stencil: None,
- multisample: MultisampleState::default(),
- push_constant_ranges: Vec::new(),
- zero_initialize_workgroup_memory: false,
+ ..default()
}
}
}
diff --git a/crates/bevy_anti_aliasing/src/experimental/mod.rs b/crates/bevy_anti_aliasing/src/experimental/mod.rs
deleted file mode 100644
index a8dc522c56..0000000000
--- a/crates/bevy_anti_aliasing/src/experimental/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//! Experimental rendering features.
-//!
-//! Experimental features are features with known problems, missing features,
-//! compatibility issues, low performance, and/or future breaking changes, but
-//! are included nonetheless for testing purposes.
-
-pub mod taa {
- pub use crate::taa::{TemporalAntiAliasNode, TemporalAntiAliasPlugin, TemporalAntiAliasing};
-}
diff --git a/crates/bevy_anti_aliasing/src/fxaa/mod.rs b/crates/bevy_anti_aliasing/src/fxaa/mod.rs
index 4848d3d268..bba5596263 100644
--- a/crates/bevy_anti_aliasing/src/fxaa/mod.rs
+++ b/crates/bevy_anti_aliasing/src/fxaa/mod.rs
@@ -1,9 +1,9 @@
use bevy_app::prelude::*;
-use bevy_asset::{load_internal_asset, weak_handle, Handle};
+use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_core_pipeline::{
core_2d::graph::{Core2d, Node2d},
core_3d::graph::{Core3d, Node3d},
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
+ FullscreenShader,
};
use bevy_ecs::prelude::*;
use bevy_image::BevyDefault as _;
@@ -11,14 +11,14 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin},
prelude::Camera,
- render_graph::{RenderGraphApp, ViewNodeRunner},
+ render_graph::{RenderGraphExt, ViewNodeRunner},
render_resource::{
binding_types::{sampler, texture_2d},
*,
},
renderer::RenderDevice,
view::{ExtractedView, ViewTarget},
- Render, RenderApp, RenderSystems,
+ Render, RenderApp, RenderStartup, RenderSystems,
};
use bevy_utils::default;
@@ -80,13 +80,11 @@ impl Default for Fxaa {
}
}
-const FXAA_SHADER_HANDLE: Handle = weak_handle!("fc58c0a8-01c0-46e9-94cc-83a794bae7b0");
-
/// Adds support for Fast Approximate Anti-Aliasing (FXAA)
pub struct FxaaPlugin;
impl Plugin for FxaaPlugin {
fn build(&self, app: &mut App) {
- load_internal_asset!(app, FXAA_SHADER_HANDLE, "fxaa.wgsl", Shader::from_wgsl);
+ embedded_asset!(app, "fxaa.wgsl");
app.register_type::();
app.add_plugins(ExtractComponentPlugin::::default());
@@ -96,6 +94,7 @@ impl Plugin for FxaaPlugin {
};
render_app
.init_resource::>()
+ .add_systems(RenderStartup, init_fxaa_pipeline)
.add_systems(
Render,
prepare_fxaa_pipelines.in_set(RenderSystems::Prepare),
@@ -119,47 +118,46 @@ impl Plugin for FxaaPlugin {
),
);
}
-
- fn finish(&self, app: &mut App) {
- let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
- return;
- };
- render_app.init_resource::();
- }
}
#[derive(Resource)]
pub struct FxaaPipeline {
texture_bind_group: BindGroupLayout,
sampler: Sampler,
+ fullscreen_shader: FullscreenShader,
+ fragment_shader: Handle,
}
-impl FromWorld for FxaaPipeline {
- fn from_world(render_world: &mut World) -> Self {
- let render_device = render_world.resource::();
- let texture_bind_group = render_device.create_bind_group_layout(
- "fxaa_texture_bind_group_layout",
- &BindGroupLayoutEntries::sequential(
- ShaderStages::FRAGMENT,
- (
- texture_2d(TextureSampleType::Float { filterable: true }),
- sampler(SamplerBindingType::Filtering),
- ),
+pub fn init_fxaa_pipeline(
+ mut commands: Commands,
+ render_device: Res,
+ fullscreen_shader: Res,
+ asset_server: Res,
+) {
+ let texture_bind_group = render_device.create_bind_group_layout(
+ "fxaa_texture_bind_group_layout",
+ &BindGroupLayoutEntries::sequential(
+ ShaderStages::FRAGMENT,
+ (
+ texture_2d(TextureSampleType::Float { filterable: true }),
+ sampler(SamplerBindingType::Filtering),
),
- );
+ ),
+ );
- let sampler = render_device.create_sampler(&SamplerDescriptor {
- mipmap_filter: FilterMode::Linear,
- mag_filter: FilterMode::Linear,
- min_filter: FilterMode::Linear,
- ..default()
- });
+ let sampler = render_device.create_sampler(&SamplerDescriptor {
+ mipmap_filter: FilterMode::Linear,
+ mag_filter: FilterMode::Linear,
+ min_filter: FilterMode::Linear,
+ ..default()
+ });
- FxaaPipeline {
- texture_bind_group,
- sampler,
- }
- }
+ commands.insert_resource(FxaaPipeline {
+ texture_bind_group,
+ sampler,
+ fullscreen_shader: fullscreen_shader.clone(),
+ fragment_shader: load_embedded_asset!(asset_server.as_ref(), "fxaa.wgsl"),
+ });
}
#[derive(Component)]
@@ -181,25 +179,21 @@ impl SpecializedRenderPipeline for FxaaPipeline {
RenderPipelineDescriptor {
label: Some("fxaa".into()),
layout: vec![self.texture_bind_group.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: FXAA_SHADER_HANDLE,
+ shader: self.fragment_shader.clone(),
shader_defs: vec![
format!("EDGE_THRESH_{}", key.edge_threshold.get_str()).into(),
format!("EDGE_THRESH_MIN_{}", key.edge_threshold_min.get_str()).into(),
],
- entry_point: "fragment".into(),
targets: vec![Some(ColorTargetState {
format: key.texture_format,
blend: None,
write_mask: ColorWrites::ALL,
})],
+ ..default()
}),
- primitive: PrimitiveState::default(),
- depth_stencil: None,
- multisample: MultisampleState::default(),
- push_constant_ranges: Vec::new(),
- zero_initialize_workgroup_memory: false,
+ ..default()
}
}
}
diff --git a/crates/bevy_anti_aliasing/src/lib.rs b/crates/bevy_anti_aliasing/src/lib.rs
index be09a2e5b2..12b7982cb5 100644
--- a/crates/bevy_anti_aliasing/src/lib.rs
+++ b/crates/bevy_anti_aliasing/src/lib.rs
@@ -2,26 +2,25 @@
#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(
- html_logo_url = "https://bevyengine.org/assets/icon.png",
- html_favicon_url = "https://bevyengine.org/assets/icon.png"
+ html_logo_url = "https://bevy.org/assets/icon.png",
+ html_favicon_url = "https://bevy.org/assets/icon.png"
)]
use bevy_app::Plugin;
use contrast_adaptive_sharpening::CasPlugin;
use fxaa::FxaaPlugin;
use smaa::SmaaPlugin;
+use taa::TemporalAntiAliasPlugin;
pub mod contrast_adaptive_sharpening;
-pub mod experimental;
pub mod fxaa;
pub mod smaa;
-
-mod taa;
+pub mod taa;
#[derive(Default)]
pub struct AntiAliasingPlugin;
impl Plugin for AntiAliasingPlugin {
fn build(&self, app: &mut bevy_app::App) {
- app.add_plugins((FxaaPlugin, CasPlugin, SmaaPlugin));
+ app.add_plugins((FxaaPlugin, SmaaPlugin, TemporalAntiAliasPlugin, CasPlugin));
}
}
diff --git a/crates/bevy_anti_aliasing/src/smaa/mod.rs b/crates/bevy_anti_aliasing/src/smaa/mod.rs
index 4259b5e33d..33a916e489 100644
--- a/crates/bevy_anti_aliasing/src/smaa/mod.rs
+++ b/crates/bevy_anti_aliasing/src/smaa/mod.rs
@@ -30,9 +30,7 @@
//!
//! [SMAA]: https://www.iryoku.com/smaa/
use bevy_app::{App, Plugin};
-#[cfg(feature = "smaa_luts")]
-use bevy_asset::load_internal_binary_asset;
-use bevy_asset::{load_internal_asset, weak_handle, Handle};
+use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
#[cfg(not(feature = "smaa_luts"))]
use bevy_core_pipeline::tonemapping::lut_placeholder;
use bevy_core_pipeline::{
@@ -48,9 +46,9 @@ use bevy_ecs::{
resource::Resource,
schedule::IntoScheduleConfigs as _,
system::{lifetimeless::Read, Commands, Query, Res, ResMut},
- world::{FromWorld, World},
+ world::World,
};
-use bevy_image::{BevyDefault, Image};
+use bevy_image::{BevyDefault, Image, ToExtents};
use bevy_math::{vec4, Vec4};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{
@@ -58,37 +56,27 @@ use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin},
render_asset::RenderAssets,
render_graph::{
- NodeRunError, RenderGraphApp as _, RenderGraphContext, ViewNode, ViewNodeRunner,
+ NodeRunError, RenderGraphContext, RenderGraphExt as _, ViewNode, ViewNodeRunner,
},
render_resource::{
binding_types::{sampler, texture_2d, uniform_buffer},
AddressMode, BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries,
CachedRenderPipelineId, ColorTargetState, ColorWrites, CompareFunction, DepthStencilState,
- DynamicUniformBuffer, Extent3d, FilterMode, FragmentState, LoadOp, MultisampleState,
- Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment,
- RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPipeline,
- RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, Shader, ShaderDefVal,
- ShaderStages, ShaderType, SpecializedRenderPipeline, SpecializedRenderPipelines,
- StencilFaceState, StencilOperation, StencilState, StoreOp, TextureDescriptor,
- TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureView,
- VertexState,
+ DynamicUniformBuffer, FilterMode, FragmentState, LoadOp, Operations, PipelineCache,
+ RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor,
+ RenderPipeline, RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, Shader,
+ ShaderDefVal, ShaderStages, ShaderType, SpecializedRenderPipeline,
+ SpecializedRenderPipelines, StencilFaceState, StencilOperation, StencilState, StoreOp,
+ TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
+ TextureView, VertexState,
},
renderer::{RenderContext, RenderDevice, RenderQueue},
texture::{CachedTexture, GpuImage, TextureCache},
view::{ExtractedView, ViewTarget},
- Render, RenderApp, RenderSystems,
+ Render, RenderApp, RenderStartup, RenderSystems,
};
use bevy_utils::prelude::default;
-/// The handle of the `smaa.wgsl` shader.
-const SMAA_SHADER_HANDLE: Handle = weak_handle!("fdd9839f-1ab4-4e0d-88a0-240b67da2ddf");
-/// The handle of the area LUT, a KTX2 format texture that SMAA uses internally.
-const SMAA_AREA_LUT_TEXTURE_HANDLE: Handle =
- weak_handle!("569c4d67-c7fa-4958-b1af-0836023603c0");
-/// The handle of the search LUT, a KTX2 format texture that SMAA uses internally.
-const SMAA_SEARCH_LUT_TEXTURE_HANDLE: Handle =
- weak_handle!("43b97515-252e-4c8a-b9af-f2fc528a1c27");
-
/// Adds support for subpixel morphological antialiasing, or SMAA.
pub struct SmaaPlugin;
@@ -128,6 +116,14 @@ pub enum SmaaPreset {
Ultra,
}
+#[derive(Resource)]
+struct SmaaLuts {
+ /// The handle of the area LUT, a KTX2 format texture that SMAA uses internally.
+ area_lut: Handle,
+ /// The handle of the search LUT, a KTX2 format texture that SMAA uses internally.
+ search_lut: Handle,
+}
+
/// A render world resource that holds all render pipeline data needed for SMAA.
///
/// There are three separate passes, so we need three separate pipelines.
@@ -147,6 +143,8 @@ struct SmaaEdgeDetectionPipeline {
postprocess_bind_group_layout: BindGroupLayout,
/// The bind group layout for data specific to this pass.
edge_detection_bind_group_layout: BindGroupLayout,
+ /// The shader asset handle.
+ shader: Handle,
}
/// The pipeline data for phase 2 of SMAA: blending weight calculation.
@@ -155,6 +153,8 @@ struct SmaaBlendingWeightCalculationPipeline {
postprocess_bind_group_layout: BindGroupLayout,
/// The bind group layout for data specific to this pass.
blending_weight_calculation_bind_group_layout: BindGroupLayout,
+ /// The shader asset handle.
+ shader: Handle,
}
/// The pipeline data for phase 3 of SMAA: neighborhood blending.
@@ -163,6 +163,8 @@ struct SmaaNeighborhoodBlendingPipeline {
postprocess_bind_group_layout: BindGroupLayout,
/// The bind group layout for data specific to this pass.
neighborhood_blending_bind_group_layout: BindGroupLayout,
+ /// The shader asset handle.
+ shader: Handle,
}
/// A unique identifier for a set of SMAA pipelines.
@@ -287,51 +289,28 @@ pub struct SmaaSpecializedRenderPipelines {
impl Plugin for SmaaPlugin {
fn build(&self, app: &mut App) {
// Load the shader.
- load_internal_asset!(app, SMAA_SHADER_HANDLE, "smaa.wgsl", Shader::from_wgsl);
-
- // Load the two lookup textures. These are compressed textures in KTX2
- // format.
- #[cfg(feature = "smaa_luts")]
- load_internal_binary_asset!(
- app,
- SMAA_AREA_LUT_TEXTURE_HANDLE,
- "SMAAAreaLUT.ktx2",
- |bytes, _: String| Image::from_buffer(
- bytes,
- bevy_image::ImageType::Format(bevy_image::ImageFormat::Ktx2),
- bevy_image::CompressedImageFormats::NONE,
- false,
- bevy_image::ImageSampler::Default,
- bevy_asset::RenderAssetUsages::RENDER_WORLD,
- )
- .expect("Failed to load SMAA area LUT")
- );
+ embedded_asset!(app, "smaa.wgsl");
#[cfg(feature = "smaa_luts")]
- load_internal_binary_asset!(
- app,
- SMAA_SEARCH_LUT_TEXTURE_HANDLE,
- "SMAASearchLUT.ktx2",
- |bytes, _: String| Image::from_buffer(
- bytes,
- bevy_image::ImageType::Format(bevy_image::ImageFormat::Ktx2),
- bevy_image::CompressedImageFormats::NONE,
- false,
- bevy_image::ImageSampler::Default,
- bevy_asset::RenderAssetUsages::RENDER_WORLD,
- )
- .expect("Failed to load SMAA search LUT")
- );
+ let smaa_luts = {
+ // Load the two lookup textures. These are compressed textures in KTX2 format.
+ embedded_asset!(app, "SMAAAreaLUT.ktx2");
+ embedded_asset!(app, "SMAASearchLUT.ktx2");
+ SmaaLuts {
+ area_lut: load_embedded_asset!(app, "SMAAAreaLUT.ktx2"),
+ search_lut: load_embedded_asset!(app, "SMAASearchLUT.ktx2"),
+ }
+ };
#[cfg(not(feature = "smaa_luts"))]
- app.world_mut()
- .resource_mut::>()
- .insert(SMAA_AREA_LUT_TEXTURE_HANDLE.id(), lut_placeholder());
-
- #[cfg(not(feature = "smaa_luts"))]
- app.world_mut()
- .resource_mut::>()
- .insert(SMAA_SEARCH_LUT_TEXTURE_HANDLE.id(), lut_placeholder());
+ let smaa_luts = {
+ let mut images = app.world_mut().resource_mut::>();
+ let handle = images.add(lut_placeholder());
+ SmaaLuts {
+ area_lut: handle.clone(),
+ search_lut: handle.clone(),
+ }
+ };
app.add_plugins(ExtractComponentPlugin::::default())
.register_type::();
@@ -341,8 +320,10 @@ impl Plugin for SmaaPlugin {
};
render_app
+ .insert_resource(smaa_luts)
.init_resource::()
.init_resource::()
+ .add_systems(RenderStartup, init_smaa_pipelines)
.add_systems(
Render,
(
@@ -371,81 +352,79 @@ impl Plugin for SmaaPlugin {
),
);
}
-
- fn finish(&self, app: &mut App) {
- if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
- render_app.init_resource::();
- }
- }
}
-impl FromWorld for SmaaPipelines {
- fn from_world(world: &mut World) -> Self {
- let render_device = world.resource::();
-
- // Create the postprocess bind group layout (all passes, bind group 0).
- let postprocess_bind_group_layout = render_device.create_bind_group_layout(
- "SMAA postprocess bind group layout",
- &BindGroupLayoutEntries::sequential(
- ShaderStages::FRAGMENT,
- (
- texture_2d(TextureSampleType::Float { filterable: true }),
- uniform_buffer::(true)
- .visibility(ShaderStages::VERTEX_FRAGMENT),
- ),
+pub fn init_smaa_pipelines(
+ mut commands: Commands,
+ render_device: Res,
+ asset_server: Res,
+) {
+ // Create the postprocess bind group layout (all passes, bind group 0).
+ let postprocess_bind_group_layout = render_device.create_bind_group_layout(
+ "SMAA postprocess bind group layout",
+ &BindGroupLayoutEntries::sequential(
+ ShaderStages::FRAGMENT,
+ (
+ texture_2d(TextureSampleType::Float { filterable: true }),
+ uniform_buffer::(true).visibility(ShaderStages::VERTEX_FRAGMENT),
),
- );
+ ),
+ );
- // Create the edge detection bind group layout (pass 1, bind group 1).
- let edge_detection_bind_group_layout = render_device.create_bind_group_layout(
- "SMAA edge detection bind group layout",
- &BindGroupLayoutEntries::sequential(
- ShaderStages::FRAGMENT,
- (sampler(SamplerBindingType::Filtering),),
+ // Create the edge detection bind group layout (pass 1, bind group 1).
+ let edge_detection_bind_group_layout = render_device.create_bind_group_layout(
+ "SMAA edge detection bind group layout",
+ &BindGroupLayoutEntries::sequential(
+ ShaderStages::FRAGMENT,
+ (sampler(SamplerBindingType::Filtering),),
+ ),
+ );
+
+ // Create the blending weight calculation bind group layout (pass 2, bind group 1).
+ let blending_weight_calculation_bind_group_layout = render_device.create_bind_group_layout(
+ "SMAA blending weight calculation bind group layout",
+ &BindGroupLayoutEntries::sequential(
+ ShaderStages::FRAGMENT,
+ (
+ texture_2d(TextureSampleType::Float { filterable: true }), // edges texture
+ sampler(SamplerBindingType::Filtering), // edges sampler
+ texture_2d(TextureSampleType::Float { filterable: true }), // search texture
+ texture_2d(TextureSampleType::Float { filterable: true }), // area texture
),
- );
+ ),
+ );
- // Create the blending weight calculation bind group layout (pass 2, bind group 1).
- let blending_weight_calculation_bind_group_layout = render_device.create_bind_group_layout(
- "SMAA blending weight calculation bind group layout",
- &BindGroupLayoutEntries::sequential(
- ShaderStages::FRAGMENT,
- (
- texture_2d(TextureSampleType::Float { filterable: true }), // edges texture
- sampler(SamplerBindingType::Filtering), // edges sampler
- texture_2d(TextureSampleType::Float { filterable: true }), // search texture
- texture_2d(TextureSampleType::Float { filterable: true }), // area texture
- ),
+ // Create the neighborhood blending bind group layout (pass 3, bind group 1).
+ let neighborhood_blending_bind_group_layout = render_device.create_bind_group_layout(
+ "SMAA neighborhood blending bind group layout",
+ &BindGroupLayoutEntries::sequential(
+ ShaderStages::FRAGMENT,
+ (
+ texture_2d(TextureSampleType::Float { filterable: true }),
+ sampler(SamplerBindingType::Filtering),
),
- );
+ ),
+ );
- // Create the neighborhood blending bind group layout (pass 3, bind group 1).
- let neighborhood_blending_bind_group_layout = render_device.create_bind_group_layout(
- "SMAA neighborhood blending bind group layout",
- &BindGroupLayoutEntries::sequential(
- ShaderStages::FRAGMENT,
- (
- texture_2d(TextureSampleType::Float { filterable: true }),
- sampler(SamplerBindingType::Filtering),
- ),
- ),
- );
+ let shader = load_embedded_asset!(asset_server.as_ref(), "smaa.wgsl");
- SmaaPipelines {
- edge_detection: SmaaEdgeDetectionPipeline {
- postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
- edge_detection_bind_group_layout,
- },
- blending_weight_calculation: SmaaBlendingWeightCalculationPipeline {
- postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
- blending_weight_calculation_bind_group_layout,
- },
- neighborhood_blending: SmaaNeighborhoodBlendingPipeline {
- postprocess_bind_group_layout,
- neighborhood_blending_bind_group_layout,
- },
- }
- }
+ commands.insert_resource(SmaaPipelines {
+ edge_detection: SmaaEdgeDetectionPipeline {
+ postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
+ edge_detection_bind_group_layout,
+ shader: shader.clone(),
+ },
+ blending_weight_calculation: SmaaBlendingWeightCalculationPipeline {
+ postprocess_bind_group_layout: postprocess_bind_group_layout.clone(),
+ blending_weight_calculation_bind_group_layout,
+ shader: shader.clone(),
+ },
+ neighborhood_blending: SmaaNeighborhoodBlendingPipeline {
+ postprocess_bind_group_layout,
+ neighborhood_blending_bind_group_layout,
+ shader,
+ },
+ });
}
// Phase 1: edge detection.
@@ -472,23 +451,21 @@ impl SpecializedRenderPipeline for SmaaEdgeDetectionPipeline {
self.edge_detection_bind_group_layout.clone(),
],
vertex: VertexState {
- shader: SMAA_SHADER_HANDLE,
+ shader: self.shader.clone(),
shader_defs: shader_defs.clone(),
- entry_point: "edge_detection_vertex_main".into(),
+ entry_point: Some("edge_detection_vertex_main".into()),
buffers: vec![],
},
fragment: Some(FragmentState {
- shader: SMAA_SHADER_HANDLE,
+ shader: self.shader.clone(),
shader_defs,
- entry_point: "luma_edge_detection_fragment_main".into(),
+ entry_point: Some("luma_edge_detection_fragment_main".into()),
targets: vec![Some(ColorTargetState {
format: TextureFormat::Rg8Unorm,
blend: None,
write_mask: ColorWrites::ALL,
})],
}),
- push_constant_ranges: vec![],
- primitive: PrimitiveState::default(),
depth_stencil: Some(DepthStencilState {
format: TextureFormat::Stencil8,
depth_write_enabled: false,
@@ -501,8 +478,7 @@ impl SpecializedRenderPipeline for SmaaEdgeDetectionPipeline {
},
bias: default(),
}),
- multisample: MultisampleState::default(),
- zero_initialize_workgroup_memory: false,
+ ..default()
}
}
}
@@ -532,23 +508,21 @@ impl SpecializedRenderPipeline for SmaaBlendingWeightCalculationPipeline {
self.blending_weight_calculation_bind_group_layout.clone(),
],
vertex: VertexState {
- shader: SMAA_SHADER_HANDLE,
+ shader: self.shader.clone(),
shader_defs: shader_defs.clone(),
- entry_point: "blending_weight_calculation_vertex_main".into(),
+ entry_point: Some("blending_weight_calculation_vertex_main".into()),
buffers: vec![],
},
fragment: Some(FragmentState {
- shader: SMAA_SHADER_HANDLE,
+ shader: self.shader.clone(),
shader_defs,
- entry_point: "blending_weight_calculation_fragment_main".into(),
+ entry_point: Some("blending_weight_calculation_fragment_main".into()),
targets: vec![Some(ColorTargetState {
format: TextureFormat::Rgba8Unorm,
blend: None,
write_mask: ColorWrites::ALL,
})],
}),
- push_constant_ranges: vec![],
- primitive: PrimitiveState::default(),
depth_stencil: Some(DepthStencilState {
format: TextureFormat::Stencil8,
depth_write_enabled: false,
@@ -561,8 +535,7 @@ impl SpecializedRenderPipeline for SmaaBlendingWeightCalculationPipeline {
},
bias: default(),
}),
- multisample: MultisampleState::default(),
- zero_initialize_workgroup_memory: false,
+ ..default()
}
}
}
@@ -580,26 +553,22 @@ impl SpecializedRenderPipeline for SmaaNeighborhoodBlendingPipeline {
self.neighborhood_blending_bind_group_layout.clone(),
],
vertex: VertexState {
- shader: SMAA_SHADER_HANDLE,
+ shader: self.shader.clone(),
shader_defs: shader_defs.clone(),
- entry_point: "neighborhood_blending_vertex_main".into(),
+ entry_point: Some("neighborhood_blending_vertex_main".into()),
buffers: vec![],
},
fragment: Some(FragmentState {
- shader: SMAA_SHADER_HANDLE,
+ shader: self.shader.clone(),
shader_defs,
- entry_point: "neighborhood_blending_fragment_main".into(),
+ entry_point: Some("neighborhood_blending_fragment_main".into()),
targets: vec![Some(ColorTargetState {
format: key.texture_format,
blend: None,
write_mask: ColorWrites::ALL,
})],
}),
- push_constant_ranges: vec![],
- primitive: PrimitiveState::default(),
- depth_stencil: None,
- multisample: MultisampleState::default(),
- zero_initialize_workgroup_memory: false,
+ ..default()
}
}
}
@@ -695,18 +664,12 @@ fn prepare_smaa_textures(
continue;
};
- let texture_size = Extent3d {
- width: texture_size.x,
- height: texture_size.y,
- depth_or_array_layers: 1,
- };
-
// Create the two-channel RG texture for phase 1 (edge detection).
let edge_detection_color_texture = texture_cache.get(
&render_device,
TextureDescriptor {
label: Some("SMAA edge detection color texture"),
- size: texture_size,
+ size: texture_size.to_extents(),
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
@@ -721,7 +684,7 @@ fn prepare_smaa_textures(
&render_device,
TextureDescriptor {
label: Some("SMAA edge detection stencil texture"),
- size: texture_size,
+ size: texture_size.to_extents(),
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
@@ -737,7 +700,7 @@ fn prepare_smaa_textures(
&render_device,
TextureDescriptor {
label: Some("SMAA blend texture"),
- size: texture_size,
+ size: texture_size.to_extents(),
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
@@ -761,13 +724,14 @@ fn prepare_smaa_bind_groups(
mut commands: Commands,
render_device: Res,
smaa_pipelines: Res,
+ smaa_luts: Res,
images: Res>,
view_targets: Query<(Entity, &SmaaTextures), (With, With)>,
) {
// Fetch the two lookup textures. These are bundled in this library.
let (Some(search_texture), Some(area_texture)) = (
- images.get(&SMAA_SEARCH_LUT_TEXTURE_HANDLE),
- images.get(&SMAA_AREA_LUT_TEXTURE_HANDLE),
+ images.get(&smaa_luts.search_lut),
+ images.get(&smaa_luts.area_lut),
) else {
return;
};
@@ -838,7 +802,7 @@ impl ViewNode for SmaaNode {
view_smaa_uniform_offset,
smaa_textures,
view_smaa_bind_groups,
- ): QueryItem<'w, Self::ViewQuery>,
+ ): QueryItem<'w, '_, Self::ViewQuery>,
world: &'w World,
) -> Result<(), NodeRunError> {
let pipeline_cache = world.resource::();
diff --git a/crates/bevy_anti_aliasing/src/smaa/smaa.wgsl b/crates/bevy_anti_aliasing/src/smaa/smaa.wgsl
index 0872325448..24dc6baa25 100644
--- a/crates/bevy_anti_aliasing/src/smaa/smaa.wgsl
+++ b/crates/bevy_anti_aliasing/src/smaa/smaa.wgsl
@@ -146,10 +146,10 @@
* * (See SMAA_INCLUDE_VS and SMAA_INCLUDE_PS below).
*
* And four presets:
- * SMAA_PRESET_LOW (%60 of the quality)
- * SMAA_PRESET_MEDIUM (%80 of the quality)
- * SMAA_PRESET_HIGH (%95 of the quality)
- * SMAA_PRESET_ULTRA (%99 of the quality)
+ * SMAA_PRESET_LOW (60% of the quality)
+ * SMAA_PRESET_MEDIUM (80% of the quality)
+ * SMAA_PRESET_HIGH (95% of the quality)
+ * SMAA_PRESET_ULTRA (99% of the quality)
*
* For example:
* #define SMAA_RT_METRICS float4(1.0 / 1280.0, 1.0 / 720.0, 1280.0, 720.0)
diff --git a/crates/bevy_anti_aliasing/src/taa/mod.rs b/crates/bevy_anti_aliasing/src/taa/mod.rs
index dc12d34423..f182108f10 100644
--- a/crates/bevy_anti_aliasing/src/taa/mod.rs
+++ b/crates/bevy_anti_aliasing/src/taa/mod.rs
@@ -1,10 +1,10 @@
use bevy_app::{App, Plugin};
-use bevy_asset::{load_internal_asset, weak_handle, Handle};
+use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
use bevy_core_pipeline::{
core_3d::graph::{Core3d, Node3d},
- fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prelude::Camera3d,
prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures},
+ FullscreenShader,
};
use bevy_diagnostic::FrameCount;
use bevy_ecs::{
@@ -13,35 +13,34 @@ use bevy_ecs::{
resource::Resource,
schedule::IntoScheduleConfigs,
system::{Commands, Query, Res, ResMut},
- world::{FromWorld, World},
+ world::World,
};
-use bevy_image::BevyDefault as _;
+use bevy_image::{BevyDefault as _, ToExtents};
use bevy_math::vec2;
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{
camera::{ExtractedCamera, MipBias, TemporalJitter},
prelude::{Camera, Projection},
- render_graph::{NodeRunError, RenderGraphApp, RenderGraphContext, ViewNode, ViewNodeRunner},
+ render_graph::{NodeRunError, RenderGraphContext, RenderGraphExt, ViewNode, ViewNodeRunner},
render_resource::{
binding_types::{sampler, texture_2d, texture_depth_2d},
BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, CachedRenderPipelineId,
- ColorTargetState, ColorWrites, Extent3d, FilterMode, FragmentState, MultisampleState,
- Operations, PipelineCache, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor,
- RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, Shader,
- ShaderStages, SpecializedRenderPipeline, SpecializedRenderPipelines, TextureDescriptor,
- TextureDimension, TextureFormat, TextureSampleType, TextureUsages,
+ ColorTargetState, ColorWrites, FilterMode, FragmentState, Operations, PipelineCache,
+ RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineDescriptor, Sampler,
+ SamplerBindingType, SamplerDescriptor, Shader, ShaderStages, SpecializedRenderPipeline,
+ SpecializedRenderPipelines, TextureDescriptor, TextureDimension, TextureFormat,
+ TextureSampleType, TextureUsages,
},
renderer::{RenderContext, RenderDevice},
sync_component::SyncComponentPlugin,
sync_world::RenderEntity,
texture::{CachedTexture, TextureCache},
view::{ExtractedView, Msaa, ViewTarget},
- ExtractSchedule, MainWorld, Render, RenderApp, RenderSystems,
+ ExtractSchedule, MainWorld, Render, RenderApp, RenderStartup, RenderSystems,
};
+use bevy_utils::default;
use tracing::warn;
-const TAA_SHADER_HANDLE: Handle = weak_handle!("fea20d50-86b6-4069-aa32-374346aec00c");
-
/// Plugin for temporal anti-aliasing.
///
/// See [`TemporalAntiAliasing`] for more details.
@@ -49,7 +48,7 @@ pub struct TemporalAntiAliasPlugin;
impl Plugin for TemporalAntiAliasPlugin {
fn build(&self, app: &mut App) {
- load_internal_asset!(app, TAA_SHADER_HANDLE, "taa.wgsl", Shader::from_wgsl);
+ embedded_asset!(app, "taa.wgsl");
app.register_type::();
@@ -60,11 +59,12 @@ impl Plugin for TemporalAntiAliasPlugin {
};
render_app
.init_resource::>()
+ .add_systems(RenderStartup, init_taa_pipeline)
.add_systems(ExtractSchedule, extract_taa_settings)
.add_systems(
Render,
(
- prepare_taa_jitter_and_mip_bias.in_set(RenderSystems::ManageViews),
+ prepare_taa_jitter.in_set(RenderSystems::ManageViews),
prepare_taa_pipelines.in_set(RenderSystems::Prepare),
prepare_taa_history_textures.in_set(RenderSystems::PrepareResources),
),
@@ -81,14 +81,6 @@ impl Plugin for TemporalAntiAliasPlugin {
),
);
}
-
- fn finish(&self, app: &mut App) {
- let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
- return;
- };
-
- render_app.init_resource::();
- }
}
/// Component to apply temporal anti-aliasing to a 3D perspective camera.
@@ -115,7 +107,6 @@ impl Plugin for TemporalAntiAliasPlugin {
///
/// # Usage Notes
///
-/// The [`TemporalAntiAliasPlugin`] must be added to your app.
/// Any camera with this component must also disable [`Msaa`] by setting it to [`Msaa::Off`].
///
/// [Currently](https://github.com/bevyengine/bevy/issues/8423), TAA cannot be used with [`bevy_render::camera::OrthographicProjection`].
@@ -128,11 +119,9 @@ impl Plugin for TemporalAntiAliasPlugin {
///
/// 1. Write particle motion vectors to the motion vectors prepass texture
/// 2. Render particles after TAA
-///
-/// If no [`MipBias`] component is attached to the camera, TAA will add a `MipBias(-1.0)` component.
#[derive(Component, Reflect, Clone)]
#[reflect(Component, Default, Clone)]
-#[require(TemporalJitter, DepthPrepass, MotionVectorPrepass)]
+#[require(TemporalJitter, MipBias, DepthPrepass, MotionVectorPrepass)]
#[doc(alias = "Taa")]
pub struct TemporalAntiAliasing {
/// Set to true to delete the saved temporal history (past frames).
@@ -243,52 +232,57 @@ struct TaaPipeline {
taa_bind_group_layout: BindGroupLayout,
nearest_sampler: Sampler,
linear_sampler: Sampler,
+ fullscreen_shader: FullscreenShader,
+ fragment_shader: Handle,
}
-impl FromWorld for TaaPipeline {
- fn from_world(world: &mut World) -> Self {
- let render_device = world.resource::();
+fn init_taa_pipeline(
+ mut commands: Commands,
+ render_device: Res,
+ fullscreen_shader: Res,
+ asset_server: Res,
+) {
+ let nearest_sampler = render_device.create_sampler(&SamplerDescriptor {
+ label: Some("taa_nearest_sampler"),
+ mag_filter: FilterMode::Nearest,
+ min_filter: FilterMode::Nearest,
+ ..SamplerDescriptor::default()
+ });
+ let linear_sampler = render_device.create_sampler(&SamplerDescriptor {
+ label: Some("taa_linear_sampler"),
+ mag_filter: FilterMode::Linear,
+ min_filter: FilterMode::Linear,
+ ..SamplerDescriptor::default()
+ });
- let nearest_sampler = render_device.create_sampler(&SamplerDescriptor {
- label: Some("taa_nearest_sampler"),
- mag_filter: FilterMode::Nearest,
- min_filter: FilterMode::Nearest,
- ..SamplerDescriptor::default()
- });
- let linear_sampler = render_device.create_sampler(&SamplerDescriptor {
- label: Some("taa_linear_sampler"),
- mag_filter: FilterMode::Linear,
- min_filter: FilterMode::Linear,
- ..SamplerDescriptor::default()
- });
-
- let taa_bind_group_layout = render_device.create_bind_group_layout(
- "taa_bind_group_layout",
- &BindGroupLayoutEntries::sequential(
- ShaderStages::FRAGMENT,
- (
- // View target (read)
- texture_2d(TextureSampleType::Float { filterable: true }),
- // TAA History (read)
- texture_2d(TextureSampleType::Float { filterable: true }),
- // Motion Vectors
- texture_2d(TextureSampleType::Float { filterable: true }),
- // Depth
- texture_depth_2d(),
- // Nearest sampler
- sampler(SamplerBindingType::NonFiltering),
- // Linear sampler
- sampler(SamplerBindingType::Filtering),
- ),
+ let taa_bind_group_layout = render_device.create_bind_group_layout(
+ "taa_bind_group_layout",
+ &BindGroupLayoutEntries::sequential(
+ ShaderStages::FRAGMENT,
+ (
+ // View target (read)
+ texture_2d(TextureSampleType::Float { filterable: true }),
+ // TAA History (read)
+ texture_2d(TextureSampleType::Float { filterable: true }),
+ // Motion Vectors
+ texture_2d(TextureSampleType::Float { filterable: true }),
+ // Depth
+ texture_depth_2d(),
+ // Nearest sampler
+ sampler(SamplerBindingType::NonFiltering),
+ // Linear sampler
+ sampler(SamplerBindingType::Filtering),
),
- );
+ ),
+ );
- TaaPipeline {
- taa_bind_group_layout,
- nearest_sampler,
- linear_sampler,
- }
- }
+ commands.insert_resource(TaaPipeline {
+ taa_bind_group_layout,
+ nearest_sampler,
+ linear_sampler,
+ fullscreen_shader: fullscreen_shader.clone(),
+ fragment_shader: load_embedded_asset!(asset_server.as_ref(), "taa.wgsl"),
+ });
}
#[derive(PartialEq, Eq, Hash, Clone)]
@@ -317,11 +311,10 @@ impl SpecializedRenderPipeline for TaaPipeline {
RenderPipelineDescriptor {
label: Some("taa_pipeline".into()),
layout: vec![self.taa_bind_group_layout.clone()],
- vertex: fullscreen_shader_vertex_state(),
+ vertex: self.fullscreen_shader.to_vertex_state(),
fragment: Some(FragmentState {
- shader: TAA_SHADER_HANDLE,
+ shader: self.fragment_shader.clone(),
shader_defs,
- entry_point: "taa".into(),
targets: vec![
Some(ColorTargetState {
format,
@@ -334,27 +327,19 @@ impl SpecializedRenderPipeline for TaaPipeline {
write_mask: ColorWrites::ALL,
}),
],
+ ..default()
}),
- primitive: PrimitiveState::default(),
- depth_stencil: None,
- multisample: MultisampleState::default(),
- push_constant_ranges: Vec::new(),
- zero_initialize_workgroup_memory: false,
+ ..default()
}
}
}
fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut) {
- let mut cameras_3d = main_world.query_filtered::<(
+ let mut cameras_3d = main_world.query::<(
RenderEntity,
&Camera,
&Projection,
- &mut TemporalAntiAliasing,
- ), (
- With,
- With,
- With,
- With,
+ Option<&mut TemporalAntiAliasing>,
)>();
for (entity, camera, camera_projection, mut taa_settings) in
@@ -364,14 +349,12 @@ fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut();
@@ -379,13 +362,22 @@ fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut,
- mut query: Query<(Entity, &mut TemporalJitter, Option<&MipBias>), With>,
- mut commands: Commands,
+ mut query: Query<
+ &mut TemporalJitter,
+ (
+ With,
+ With,
+ With,
+ With,
+ With,
+ ),
+ >,
) {
- // Halton sequence (2, 3) - 0.5, skipping i = 0
+ // Halton sequence (2, 3) - 0.5
let halton_sequence = [
+ vec2(0.0, 0.0),
vec2(0.0, -0.16666666),
vec2(-0.25, 0.16666669),
vec2(0.25, -0.3888889),
@@ -393,17 +385,12 @@ fn prepare_taa_jitter_and_mip_bias(
vec2(0.125, 0.2777778),
vec2(-0.125, -0.2777778),
vec2(0.375, 0.055555582),
- vec2(-0.4375, 0.3888889),
];
let offset = halton_sequence[frame_count.0 as usize % halton_sequence.len()];
- for (entity, mut jitter, mip_bias) in &mut query {
+ for mut jitter in &mut query {
jitter.offset = offset;
-
- if mip_bias.is_none() {
- commands.entity(entity).insert(MipBias(-1.0));
- }
}
}
@@ -424,11 +411,7 @@ fn prepare_taa_history_textures(
if let Some(physical_target_size) = camera.physical_target_size {
let mut texture_descriptor = TextureDescriptor {
label: None,
- size: Extent3d {
- depth_or_array_layers: 1,
- width: physical_target_size.x,
- height: physical_target_size.y,
- },
+ size: physical_target_size.to_extents(),
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
diff --git a/crates/bevy_app/Cargo.toml b/crates/bevy_app/Cargo.toml
index f46db94db3..a0c5222b0b 100644
--- a/crates/bevy_app/Cargo.toml
+++ b/crates/bevy_app/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "bevy_app"
-version = "0.16.0-dev"
+version = "0.17.0-dev"
edition = "2024"
description = "Provides core App functionality for Bevy Engine"
-homepage = "https://bevyengine.org"
+homepage = "https://bevy.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
keywords = ["bevy"]
@@ -47,7 +47,6 @@ std = [
"bevy_ecs/std",
"dep:ctrlc",
"downcast-rs/std",
- "bevy_utils/std",
"bevy_tasks/std",
"bevy_platform/std",
]
@@ -72,16 +71,20 @@ web = [
"dep:console_error_panic_hook",
]
+hotpatching = [
+ "bevy_ecs/hotpatching",
+ "dep:dioxus-devtools",
+ "dep:crossbeam-channel",
+]
+
[dependencies]
# bevy
-bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
-bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev", default-features = false }
-bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", default-features = false, optional = true }
-bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev", default-features = false, features = [
- "alloc",
-] }
-bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", default-features = false }
-bevy_platform = { path = "../bevy_platform", version = "0.16.0-dev", default-features = false }
+bevy_derive = { path = "../bevy_derive", version = "0.17.0-dev" }
+bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = false }
+bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, optional = true }
+bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev", default-features = false }
+bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false }
+bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false }
# other
downcast-rs = { version = "2", default-features = false }
@@ -90,8 +93,10 @@ variadics_please = "1.1"
tracing = { version = "0.1", default-features = false, optional = true }
log = { version = "0.4", default-features = false }
cfg-if = "1.0.0"
+dioxus-devtools = { version = "0.7.0-alpha.1", optional = true }
+crossbeam-channel = { version = "0.5.0", optional = true }
-[target.'cfg(any(unix, windows))'.dependencies]
+[target.'cfg(any(all(unix, not(target_os = "horizon")), windows))'.dependencies]
ctrlc = { version = "3.4.4", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs
index 60431ca479..a9057c787d 100644
--- a/crates/bevy_app/src/app.rs
+++ b/crates/bevy_app/src/app.rs
@@ -10,6 +10,7 @@ use alloc::{
pub use bevy_derive::AppLabel;
use bevy_ecs::{
component::RequiredComponentsError,
+ error::{DefaultErrorHandler, ErrorHandler},
event::{event_update_system, EventCursor},
intern::Interned,
prelude::*,
@@ -85,6 +86,7 @@ pub struct App {
/// [`WinitPlugin`]: https://docs.rs/bevy/latest/bevy/winit/struct.WinitPlugin.html
/// [`ScheduleRunnerPlugin`]: https://docs.rs/bevy/latest/bevy/app/struct.ScheduleRunnerPlugin.html
pub(crate) runner: RunnerFn,
+ default_error_handler: Option,
}
impl Debug for App {
@@ -104,10 +106,13 @@ impl Default for App {
#[cfg(feature = "bevy_reflect")]
{
+ use bevy_ecs::observer::ObservedBy;
+
app.init_resource::();
app.register_type::();
app.register_type::();
app.register_type::();
+ app.register_type::