diff --git a/Cargo.toml b/Cargo.toml index d649d14573787..5f22ca367218b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2866,6 +2866,17 @@ description = "Displays many Text2d! Used for performance testing." category = "Stress Tests" wasm = true +[[example]] +name = "many_materials" +path = "examples/stress_tests/many_materials.rs" +doc-scrape-examples = true + +[package.metadata.example.many_materials] +name = "Many Animated Materials" +description = "Benchmark to test rendering many animated materials" +category = "Stress Tests" +wasm = true + [[example]] name = "transform_hierarchy" path = "examples/stress_tests/transform_hierarchy.rs" diff --git a/examples/README.md b/examples/README.md index b1a97eef77fa5..e24d4ecbe4a66 100644 --- a/examples/README.md +++ b/examples/README.md @@ -465,6 +465,7 @@ cargo run --release --example Example | Description --- | --- [Bevymark](../examples/stress_tests/bevymark.rs) | A heavy sprite rendering workload to benchmark your system with Bevy +[Many Animated Materials](../examples/stress_tests/many_materials.rs) | Benchmark to test rendering many animated materials [Many Animated Sprites](../examples/stress_tests/many_animated_sprites.rs) | Displays many animated sprites in a grid arrangement with slight offsets to their animation timers. Used for performance testing. [Many Buttons](../examples/stress_tests/many_buttons.rs) | Test rendering of many UI elements [Many Cameras & Lights](../examples/stress_tests/many_cameras_lights.rs) | Test rendering of many cameras and lights diff --git a/examples/stress_tests/many_materials.rs b/examples/stress_tests/many_materials.rs new file mode 100644 index 0000000000000..f2af7fb3827fc --- /dev/null +++ b/examples/stress_tests/many_materials.rs @@ -0,0 +1,103 @@ +//! Benchmark to test rendering many animated materials +use argh::FromArgs; +use bevy::{ + diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, + prelude::*, + window::{PresentMode, WindowPlugin, WindowResolution}, +}; +use std::f32::consts::PI; + +#[derive(FromArgs, Resource)] +/// Command-line arguments for the `many_materials` stress test. +struct Args { + /// the size of the grid of materials to render (n x n) + #[argh(option, short = 'n', default = "10")] + grid_size: usize, +} + +fn main() { + // `from_env` panics on the web + #[cfg(not(target_arch = "wasm32"))] + let args: Args = argh::from_env(); + #[cfg(target_arch = "wasm32")] + let args = Args::from_args(&[], &[]).unwrap(); + + App::new() + .add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + resolution: WindowResolution::new(1920.0, 1080.0) + .with_scale_factor_override(1.0), + title: "many_materials".into(), + present_mode: PresentMode::AutoNoVsync, + ..default() + }), + ..default() + }), + FrameTimeDiagnosticsPlugin::default(), + LogDiagnosticsPlugin::default(), + )) + .insert_resource(args) + .add_systems(Startup, setup) + .add_systems(Update, animate_materials) + .run(); +} + +fn setup( + mut commands: Commands, + args: Res, + mesh_assets: ResMut>, + material_assets: ResMut>, +) { + let args = args.into_inner(); + let material_assets = material_assets.into_inner(); + let mesh_assets = mesh_assets.into_inner(); + let n = args.grid_size; + + // Camera + let w = n as f32; + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(w * 1.25, w + 1.0, w * 1.25) + .looking_at(Vec3::new(0.0, (w * -1.1) + 1.0, 0.0), Vec3::Y), + )); + + // Light + commands.spawn(( + Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)), + DirectionalLight { + illuminance: 3000.0, + shadows_enabled: true, + ..default() + }, + )); + + // Cubes + let mesh_handle = mesh_assets.add(Cuboid::from_size(Vec3::ONE)); + for x in 0..n { + for z in 0..n { + commands.spawn(( + Mesh3d(mesh_handle.clone()), + MeshMaterial3d(material_assets.add(Color::WHITE)), + Transform::from_translation(Vec3::new(x as f32, 0.0, z as f32)), + )); + } + } +} + +fn animate_materials( + material_handles: Query<&MeshMaterial3d>, + time: Res