mirror of
https://github.com/bevyengine/bevy
synced 2025-01-05 01:38:56 +00:00
5f1dd3918b
# Objective Bevy's animation system currently does tree traversals based on `Name` that aren't necessary. Not only do they require in unsafe code because tree traversals are awkward with parallelism, but they are also somewhat slow, brittle, and complex, which manifested itself as way too many queries in #11670. # Solution Divide animation into two phases: animation *advancement* and animation *evaluation*, which run after one another. *Advancement* operates on the `AnimationPlayer` and sets the current animation time to match the game time. *Evaluation* operates on all animation bones in the scene in parallel and sets the transforms and/or morph weights based on the time and the clip. To do this, we introduce a new component, `AnimationTarget`, which the asset loader places on every bone. It contains the ID of the entity containing the `AnimationPlayer`, as well as a UUID that identifies which bone in the animation the target corresponds to. In the case of glTF, the UUID is derived from the full path name to the bone. The rule that `AnimationTarget`s are descendants of the entity containing `AnimationPlayer` is now just a convention, not a requirement; this allows us to eliminate the unsafe code. # Migration guide * `AnimationClip` now uses UUIDs instead of hierarchical paths based on the `Name` component to refer to bones. This has several consequences: - A new component, `AnimationTarget`, should be placed on each bone that you wish to animate, in order to specify its UUID and the associated `AnimationPlayer`. The glTF loader automatically creates these components as necessary, so most uses of glTF rigs shouldn't need to change. - Moving a bone around the tree, or renaming it, no longer prevents an `AnimationPlayer` from affecting it. - Dynamically changing the `AnimationPlayer` component will likely require manual updating of the `AnimationTarget` components. * Entities with `AnimationPlayer` components may now possess descendants that also have `AnimationPlayer` components. They may not, however, animate the same bones. * As they aren't specific to `TypeId`s, `bevy_reflect::utility::NoOpTypeIdHash` and `bevy_reflect::utility::NoOpTypeIdHasher` have been renamed to `bevy_reflect::utility::NoOpHash` and `bevy_reflect::utility::NoOpHasher` respectively.
209 lines
8.4 KiB
Rust
209 lines
8.4 KiB
Rust
use bevy_app::{Plugin, PluginGroup, PluginGroupBuilder};
|
||
|
||
/// This plugin group will add all the default plugins for a *Bevy* application:
|
||
/// * [`LogPlugin`](crate::log::LogPlugin)
|
||
/// * [`TaskPoolPlugin`](crate::core::TaskPoolPlugin)
|
||
/// * [`TypeRegistrationPlugin`](crate::core::TypeRegistrationPlugin)
|
||
/// * [`FrameCountPlugin`](crate::core::FrameCountPlugin)
|
||
/// * [`TimePlugin`](crate::time::TimePlugin)
|
||
/// * [`TransformPlugin`](crate::transform::TransformPlugin)
|
||
/// * [`HierarchyPlugin`](crate::hierarchy::HierarchyPlugin)
|
||
/// * [`DiagnosticsPlugin`](crate::diagnostic::DiagnosticsPlugin)
|
||
/// * [`InputPlugin`](crate::input::InputPlugin)
|
||
/// * [`WindowPlugin`](crate::window::WindowPlugin)
|
||
/// * [`AccessibilityPlugin`](crate::a11y::AccessibilityPlugin)
|
||
/// * [`AssetPlugin`](crate::asset::AssetPlugin) - with feature `bevy_asset`
|
||
/// * [`ScenePlugin`](crate::scene::ScenePlugin) - with feature `bevy_scene`
|
||
/// * [`WinitPlugin`](crate::winit::WinitPlugin) - with feature `bevy_winit`
|
||
/// * [`RenderPlugin`](crate::render::RenderPlugin) - with feature `bevy_render`
|
||
/// * [`ImagePlugin`](crate::render::texture::ImagePlugin) - with feature `bevy_render`
|
||
/// * [`PipelinedRenderingPlugin`](crate::render::pipelined_rendering::PipelinedRenderingPlugin) - with feature `bevy_render` when not targeting `wasm32`
|
||
/// * [`CorePipelinePlugin`](crate::core_pipeline::CorePipelinePlugin) - with feature `bevy_core_pipeline`
|
||
/// * [`SpritePlugin`](crate::sprite::SpritePlugin) - with feature `bevy_sprite`
|
||
/// * [`TextPlugin`](crate::text::TextPlugin) - with feature `bevy_text`
|
||
/// * [`UiPlugin`](crate::ui::UiPlugin) - with feature `bevy_ui`
|
||
/// * [`PbrPlugin`](crate::pbr::PbrPlugin) - with feature `bevy_pbr`
|
||
/// * [`GltfPlugin`](crate::gltf::GltfPlugin) - with feature `bevy_gltf`
|
||
/// * [`AudioPlugin`](crate::audio::AudioPlugin) - with feature `bevy_audio`
|
||
/// * [`GilrsPlugin`](crate::gilrs::GilrsPlugin) - with feature `bevy_gilrs`
|
||
/// * [`AnimationPlugin`](crate::animation::AnimationPlugin) - with feature `bevy_animation`
|
||
///
|
||
/// [`DefaultPlugins`] obeys *Cargo* *feature* flags. Users may exert control over this plugin group
|
||
/// by disabling `default-features` in their `Cargo.toml` and enabling only those features
|
||
/// that they wish to use.
|
||
///
|
||
/// [`DefaultPlugins`] contains all the plugins typically required to build
|
||
/// a *Bevy* application which includes a *window* and presentation components.
|
||
/// For *headless* cases – without a *window* or presentation, see [`MinimalPlugins`].
|
||
pub struct DefaultPlugins;
|
||
|
||
impl PluginGroup for DefaultPlugins {
|
||
fn build(self) -> PluginGroupBuilder {
|
||
let mut group = PluginGroupBuilder::start::<Self>();
|
||
group = group
|
||
.add(bevy_log::LogPlugin::default())
|
||
.add(bevy_core::TaskPoolPlugin::default())
|
||
.add(bevy_core::TypeRegistrationPlugin)
|
||
.add(bevy_core::FrameCountPlugin)
|
||
.add(bevy_time::TimePlugin)
|
||
.add(bevy_transform::TransformPlugin)
|
||
.add(bevy_hierarchy::HierarchyPlugin)
|
||
.add(bevy_diagnostic::DiagnosticsPlugin)
|
||
.add(bevy_input::InputPlugin)
|
||
.add(bevy_window::WindowPlugin::default())
|
||
.add(bevy_a11y::AccessibilityPlugin);
|
||
|
||
#[cfg(feature = "bevy_asset")]
|
||
{
|
||
group = group.add(bevy_asset::AssetPlugin::default());
|
||
}
|
||
|
||
#[cfg(feature = "bevy_scene")]
|
||
{
|
||
group = group.add(bevy_scene::ScenePlugin);
|
||
}
|
||
|
||
#[cfg(feature = "bevy_winit")]
|
||
{
|
||
group = group.add(bevy_winit::WinitPlugin::default());
|
||
}
|
||
|
||
#[cfg(feature = "bevy_render")]
|
||
{
|
||
group = group
|
||
.add(bevy_render::RenderPlugin::default())
|
||
// NOTE: Load this after renderer initialization so that it knows about the supported
|
||
// compressed texture formats
|
||
.add(bevy_render::texture::ImagePlugin::default());
|
||
|
||
#[cfg(all(not(target_arch = "wasm32"), feature = "multi-threaded"))]
|
||
{
|
||
group = group.add(bevy_render::pipelined_rendering::PipelinedRenderingPlugin);
|
||
}
|
||
}
|
||
|
||
#[cfg(feature = "bevy_core_pipeline")]
|
||
{
|
||
group = group.add(bevy_core_pipeline::CorePipelinePlugin);
|
||
}
|
||
|
||
#[cfg(feature = "bevy_sprite")]
|
||
{
|
||
group = group.add(bevy_sprite::SpritePlugin);
|
||
}
|
||
|
||
#[cfg(feature = "bevy_text")]
|
||
{
|
||
group = group.add(bevy_text::TextPlugin);
|
||
}
|
||
|
||
#[cfg(feature = "bevy_ui")]
|
||
{
|
||
group = group.add(bevy_ui::UiPlugin);
|
||
}
|
||
|
||
#[cfg(feature = "bevy_pbr")]
|
||
{
|
||
group = group.add(bevy_pbr::PbrPlugin::default());
|
||
}
|
||
|
||
// NOTE: Load this after renderer initialization so that it knows about the supported
|
||
// compressed texture formats
|
||
#[cfg(feature = "bevy_gltf")]
|
||
{
|
||
group = group.add(bevy_gltf::GltfPlugin::default());
|
||
}
|
||
|
||
#[cfg(feature = "bevy_audio")]
|
||
{
|
||
group = group.add(bevy_audio::AudioPlugin::default());
|
||
}
|
||
|
||
#[cfg(feature = "bevy_gilrs")]
|
||
{
|
||
group = group.add(bevy_gilrs::GilrsPlugin);
|
||
}
|
||
|
||
#[cfg(feature = "bevy_animation")]
|
||
{
|
||
group = group.add(bevy_animation::AnimationPlugin);
|
||
}
|
||
|
||
#[cfg(feature = "bevy_gizmos")]
|
||
{
|
||
group = group.add(bevy_gizmos::GizmoPlugin);
|
||
}
|
||
|
||
group = group.add(IgnoreAmbiguitiesPlugin);
|
||
|
||
group
|
||
}
|
||
}
|
||
|
||
struct IgnoreAmbiguitiesPlugin;
|
||
|
||
impl Plugin for IgnoreAmbiguitiesPlugin {
|
||
#[allow(unused_variables)] // Variables are used depending on enabled features
|
||
fn build(&self, app: &mut bevy_app::App) {
|
||
// bevy_ui owns the Transform and cannot be animated
|
||
#[cfg(all(feature = "bevy_animation", feature = "bevy_ui"))]
|
||
app.ignore_ambiguity(
|
||
bevy_app::PostUpdate,
|
||
bevy_animation::advance_animations,
|
||
bevy_ui::ui_layout_system,
|
||
);
|
||
|
||
#[cfg(feature = "bevy_render")]
|
||
if let Ok(render_app) = app.get_sub_app_mut(bevy_render::RenderApp) {
|
||
#[cfg(all(feature = "bevy_gizmos", feature = "bevy_sprite"))]
|
||
{
|
||
render_app.ignore_ambiguity(
|
||
bevy_render::Render,
|
||
bevy_gizmos::GizmoRenderSystem::QueueLineGizmos2d,
|
||
bevy_sprite::queue_sprites,
|
||
);
|
||
render_app.ignore_ambiguity(
|
||
bevy_render::Render,
|
||
bevy_gizmos::GizmoRenderSystem::QueueLineGizmos2d,
|
||
bevy_sprite::queue_material2d_meshes::<bevy_sprite::ColorMaterial>,
|
||
);
|
||
}
|
||
#[cfg(all(feature = "bevy_gizmos", feature = "bevy_pbr"))]
|
||
{
|
||
render_app.ignore_ambiguity(
|
||
bevy_render::Render,
|
||
bevy_gizmos::GizmoRenderSystem::QueueLineGizmos3d,
|
||
bevy_pbr::queue_material_meshes::<bevy_pbr::StandardMaterial>,
|
||
);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// This plugin group will add the minimal plugins for a *Bevy* application:
|
||
/// * [`TaskPoolPlugin`](crate::core::TaskPoolPlugin)
|
||
/// * [`TypeRegistrationPlugin`](crate::core::TypeRegistrationPlugin)
|
||
/// * [`FrameCountPlugin`](crate::core::FrameCountPlugin)
|
||
/// * [`TimePlugin`](crate::time::TimePlugin)
|
||
/// * [`ScheduleRunnerPlugin`](crate::app::ScheduleRunnerPlugin)
|
||
///
|
||
/// This group of plugins is intended for use for minimal, *headless* programs –
|
||
/// see the [*Bevy* *headless* example](https://github.com/bevyengine/bevy/blob/main/examples/app/headless.rs)
|
||
/// – and includes a [schedule runner (`ScheduleRunnerPlugin`)](crate::app::ScheduleRunnerPlugin)
|
||
/// to provide functionality that would otherwise be driven by a windowed application's
|
||
/// *event loop* or *message loop*.
|
||
///
|
||
/// Windowed applications that wish to use a reduced set of plugins should consider the
|
||
/// [`DefaultPlugins`] plugin group which can be controlled with *Cargo* *feature* flags.
|
||
pub struct MinimalPlugins;
|
||
|
||
impl PluginGroup for MinimalPlugins {
|
||
fn build(self) -> PluginGroupBuilder {
|
||
PluginGroupBuilder::start::<Self>()
|
||
.add(bevy_core::TaskPoolPlugin::default())
|
||
.add(bevy_core::TypeRegistrationPlugin)
|
||
.add(bevy_core::FrameCountPlugin)
|
||
.add(bevy_time::TimePlugin)
|
||
.add(bevy_app::ScheduleRunnerPlugin::default())
|
||
}
|
||
}
|