mirror of
https://github.com/bevyengine/bevy
synced 2024-11-29 16:10:19 +00:00
c19aa5939d
# Objective - Add Time-Adjusted Rolling EMA-based smoothing to diagnostics. - Closes #4983; see that issue for more more information. ## Terms - EMA - [Exponential Moving Average](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average) - SMA - [Simple Moving Average](https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average) ## Solution - We use a fairly standard approximation of a true EMA where $EMA_{\text{frame}} = EMA_{\text{previous}} + \alpha \left( x_{\text{frame}} - EMA_{\text{previous}} \right)$ where $\alpha = \Delta t / \tau$ and $\tau$ is an arbitrary smoothness factor. (See #4983 for more discussion of the math.) - The smoothness factor is here defaulted to $2 / 21$; this was chosen fairly arbitrarily as supposedly related to the existing 20-bucket SMA. - The smoothness factor can be set on a per-diagnostic basis via `Diagnostic::with_smoothing_factor`. --- ## Changelog ### Added - `Diagnostic::smoothed` - provides an exponentially smoothed view of a recorded diagnostic, to e.g. reduce jitter in frametime readings. ### Changed - `LogDiagnosticsPlugin` now records the smoothed value rather than the raw value. - For diagnostics recorded less often than every 0.1 seconds, this change to defaults will have no visible effect. - For discrete diagnostics where this smoothing is not desirable, set a smoothing factor of 0 to disable smoothing. - The average of the recent history is still shown when available.
102 lines
3.4 KiB
Rust
102 lines
3.4 KiB
Rust
//! This example illustrates how to create UI text and update it in a system.
|
|
//!
|
|
//! It displays the current FPS in the top left corner, as well as text that changes color
|
|
//! in the bottom right. For text within a scene, please see the text2d example.
|
|
|
|
use bevy::{
|
|
diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin},
|
|
prelude::*,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_plugin(FrameTimeDiagnosticsPlugin::default())
|
|
.add_startup_system(setup)
|
|
.add_system(text_update_system)
|
|
.add_system(text_color_system)
|
|
.run();
|
|
}
|
|
|
|
// A unit struct to help identify the FPS UI component, since there may be many Text components
|
|
#[derive(Component)]
|
|
struct FpsText;
|
|
|
|
// A unit struct to help identify the color-changing Text component
|
|
#[derive(Component)]
|
|
struct ColorText;
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
// UI camera
|
|
commands.spawn(Camera2dBundle::default());
|
|
// Text with one section
|
|
commands.spawn((
|
|
// Create a TextBundle that has a Text with a single section.
|
|
TextBundle::from_section(
|
|
// Accepts a `String` or any type that converts into a `String`, such as `&str`
|
|
"hello\nbevy!",
|
|
TextStyle {
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
font_size: 100.0,
|
|
color: Color::WHITE,
|
|
},
|
|
) // Set the alignment of the Text
|
|
.with_text_alignment(TextAlignment::TOP_CENTER)
|
|
// Set the style of the TextBundle itself.
|
|
.with_style(Style {
|
|
position_type: PositionType::Absolute,
|
|
position: UiRect {
|
|
bottom: Val::Px(5.0),
|
|
right: Val::Px(15.0),
|
|
..default()
|
|
},
|
|
..default()
|
|
}),
|
|
ColorText,
|
|
));
|
|
// Text with multiple sections
|
|
commands.spawn((
|
|
// Create a TextBundle that has a Text with a list of sections.
|
|
TextBundle::from_sections([
|
|
TextSection::new(
|
|
"FPS: ",
|
|
TextStyle {
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
font_size: 60.0,
|
|
color: Color::WHITE,
|
|
},
|
|
),
|
|
TextSection::from_style(TextStyle {
|
|
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
|
font_size: 60.0,
|
|
color: Color::GOLD,
|
|
}),
|
|
]),
|
|
FpsText,
|
|
));
|
|
}
|
|
|
|
fn text_color_system(time: Res<Time>, mut query: Query<&mut Text, With<ColorText>>) {
|
|
for mut text in &mut query {
|
|
let seconds = time.elapsed_seconds();
|
|
|
|
// Update the color of the first and only section.
|
|
text.sections[0].style.color = Color::Rgba {
|
|
red: (1.25 * seconds).sin() / 2.0 + 0.5,
|
|
green: (0.75 * seconds).sin() / 2.0 + 0.5,
|
|
blue: (0.50 * seconds).sin() / 2.0 + 0.5,
|
|
alpha: 1.0,
|
|
};
|
|
}
|
|
}
|
|
|
|
fn text_update_system(diagnostics: Res<Diagnostics>, mut query: Query<&mut Text, With<FpsText>>) {
|
|
for mut text in &mut query {
|
|
if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) {
|
|
if let Some(value) = fps.smoothed() {
|
|
// Update the value of the second section
|
|
text.sections[1].value = format!("{value:.2}");
|
|
}
|
|
}
|
|
}
|
|
}
|