Skip to main content

many_materials/
many_materials.rs

1//! Benchmark to test rendering many animated materials
2use argh::FromArgs;
3use bevy::{
4    diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
5    prelude::*,
6    window::{PresentMode, WindowResolution},
7    winit::WinitSettings,
8};
9use std::f32::consts::PI;
10
11#[derive(FromArgs, Resource)]
12/// Command-line arguments for the `many_materials` stress test.
13struct Args {
14    /// the size of the grid of materials to render (n x n)
15    #[argh(option, short = 'n', default = "10")]
16    grid_size: usize,
17}
18
19fn main() {
20    // `from_env` panics on the web
21    #[cfg(not(target_arch = "wasm32"))]
22    let args: Args = argh::from_env();
23    #[cfg(target_arch = "wasm32")]
24    let args = Args::from_args(&[], &[]).unwrap();
25
26    App::new()
27        .add_plugins((
28            DefaultPlugins.set(WindowPlugin {
29                primary_window: Some(Window {
30                    resolution: WindowResolution::new(1920, 1080).with_scale_factor_override(1.0),
31                    title: "many_materials".into(),
32                    present_mode: PresentMode::AutoNoVsync,
33                    ..default()
34                }),
35                ..default()
36            }),
37            FrameTimeDiagnosticsPlugin::default(),
38            LogDiagnosticsPlugin::default(),
39        ))
40        .insert_resource(WinitSettings::continuous())
41        .insert_resource(args)
42        .add_systems(Startup, setup)
43        .add_systems(Update, animate_materials)
44        .run();
45}
46
47fn setup(
48    mut commands: Commands,
49    args: Res<Args>,
50    mesh_assets: ResMut<Assets<Mesh>>,
51    material_assets: ResMut<Assets<StandardMaterial>>,
52) {
53    warn!(include_str!("warning_string.txt"));
54
55    let args = args.into_inner();
56    let material_assets = material_assets.into_inner();
57    let mesh_assets = mesh_assets.into_inner();
58    let n = args.grid_size;
59
60    // Camera
61    let w = n as f32;
62    commands.spawn((
63        Camera3d::default(),
64        Transform::from_xyz(w * 1.25, w + 1.0, w * 1.25)
65            .looking_at(Vec3::new(0.0, (w * -1.1) + 1.0, 0.0), Vec3::Y),
66    ));
67
68    // Light
69    commands.spawn((
70        Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)),
71        DirectionalLight {
72            illuminance: 3000.0,
73            shadow_maps_enabled: true,
74            ..default()
75        },
76    ));
77
78    // Cubes
79    let mesh_handle = mesh_assets.add(Cuboid::from_size(Vec3::ONE));
80    for x in 0..n {
81        for z in 0..n {
82            commands.spawn((
83                Mesh3d(mesh_handle.clone()),
84                MeshMaterial3d(material_assets.add(Color::WHITE)),
85                Transform::from_translation(Vec3::new(x as f32, 0.0, z as f32)),
86            ));
87        }
88    }
89}
90
91fn animate_materials(
92    material_handles: Query<&MeshMaterial3d<StandardMaterial>>,
93    time: Res<Time>,
94    mut materials: ResMut<Assets<StandardMaterial>>,
95) {
96    for (i, material_handle) in material_handles.iter().enumerate() {
97        if let Some(mut material) = materials.get_mut(material_handle) {
98            let color = Color::hsl(
99                ((i as f32 * 2.345 + time.elapsed_secs()) * 100.0) % 360.0,
100                1.0,
101                0.5,
102            );
103            material.base_color = color;
104        }
105    }
106}