Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Really slow rendering of tiled 3d floors #6032

Closed
terhechte opened this issue Sep 20, 2022 · 5 comments
Closed

Really slow rendering of tiled 3d floors #6032

terhechte opened this issue Sep 20, 2022 · 5 comments
Labels
C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled

Comments

@terhechte
Copy link

Bevy version

I tried:

  • 0.8.1
  • bevy = { git = "https://github.com/TheRawMeatball/bevy", branch = "optimize-large-entity-counts" }

[Optional] Relevant system information

  • macOS 12.5.1 on MacBook Pro (14-inch, 2021) with M1 Max
  • Rust: cargo 1.63.0 (fd9c4297c 2022-07-01)
`AdapterInfo { name: "Apple M1 Max", vendor: 0, device: 0, device_type: IntegratedGpu, backend: Metal }`

What you did

I'm trying to render something like a tiled floor in a 3d world. Initially I wanted to use a tiled texture, but I ran into this issue of tiled textures not working and the listed approaches somehow didn't work for me.

My next approach was to spawn a lot of cubes or planes instead. Here's the code:

use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin};
use bevy::window::close_on_esc;
use bevy::{log::LogSettings, prelude::*};
mod split;

const SIZE: f32 = 0.25;
const PLAYER_Y: f32 = 4.5;

fn main() {
    App::new()
        .insert_resource(LogSettings {
            filter: "info,wgpu_core=warn,wgpu_hal=warn,pacbomber=debug".into(),
            level: bevy::log::Level::DEBUG,
        })
        .insert_resource(ClearColor(Color::rgb(20. / 255., 20. / 255., 20. / 255.)))
        .insert_resource(WindowDescriptor {
            title: "Test".to_string(),
            width: 900.,
            height: 660.,
            resizable: true,
            ..default()
        })
        .add_plugins(DefaultPlugins)
        .add_plugin(LogDiagnosticsPlugin::default())
        .add_plugin(FrameTimeDiagnosticsPlugin::default())
        .add_startup_system(build_level_system)
        .add_system(keyboard_system)
        .add_system(move_camera_system)
        .add_system(close_on_esc)
        .run();
}

#[derive(Component)]
struct MainCamera;

#[derive(Component)]
struct Player;

fn build_level_system(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    let camera_bundle = Camera3dBundle {
        transform: Transform::from_xyz(0.0, PLAYER_Y, 3.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    };
    commands.spawn_bundle(camera_bundle).insert(MainCamera);

    let player = meshes.add(Mesh::from(shape::Cube { size: SIZE }));
    let player_material = materials.add(StandardMaterial {
        base_color: Color::YELLOW,
        metallic: 0.5,
        reflectance: 0.15,
        ..Default::default()
    });

    commands
        .spawn_bundle(PbrBundle {
            mesh: player,
            material: player_material,
            transform: Transform::from_xyz(10. * SIZE, 0.5, 10. * SIZE),
            ..Default::default()
        })
        .insert(Player);

    let floor = meshes.add(Mesh::from(shape::Cube { size: SIZE - 0.01 }));
    let floor_material = materials.add(StandardMaterial {
        base_color: Color::RED,
        metallic: 0.5,
        reflectance: 0.15,
        ..Default::default()
    });

    let offset = SIZE * -10.;
    let (mut x, mut z) = (offset, offset);
    for zc in 0..=1280 {
        z += SIZE;
        for xc in 0..=1280 {
            x += SIZE;
            commands.spawn_bundle(PbrBundle {
                mesh: floor.clone(),
                material: floor_material.clone(),
                transform: Transform::from_xyz(x, -0.1, z),
                ..Default::default()
            });
            // every corner a light
            match (zc, xc) {
                (1, 1) => spawn_light(&mut commands, x, z),
                (1, 127) => spawn_light(&mut commands, x, z),
                (127, 127) => spawn_light(&mut commands, x, z),
                (127, 1) => spawn_light(&mut commands, x, z),
                (64, 64) => spawn_light(&mut commands, x, z),
                (64, 1) => spawn_light(&mut commands, x, z),
                (1, 64) => spawn_light(&mut commands, x, z),
                _ => (),
            }
        }
        x = offset;
    }
}

fn spawn_light(commands: &mut Commands, x: f32, z: f32) {
    commands.spawn_bundle(PointLightBundle {
        point_light: PointLight {
            intensity: 50.0,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(x, 1.0, z),
        ..default()
    });
}

fn keyboard_system(
    keyboard_input: Res<Input<KeyCode>>,
    mut player: Query<&mut Transform, With<Player>>,
) {
    let speed = 0.15;
    for (code, (d_x, d_z)) in [
        (KeyCode::Left, (-1, 0)),
        (KeyCode::Right, (1, 0)),
        (KeyCode::Up, (0, -1)),
        (KeyCode::Down, (0, 1)),
    ] {
        if keyboard_input.pressed(code) || keyboard_input.just_pressed(code) {
            let (x, z) = ((d_x as f32) * speed, (d_z as f32) * speed);
            for mut transform in player.iter_mut() {
                transform.translation.x += x;
                transform.translation.z += z;
            }
        }
    }
}

fn move_camera_system(
    player_query: Query<&Transform, (With<Player>, Without<MainCamera>)>,
    mut camera_query: Query<(&Camera, &mut Transform), With<MainCamera>>,
) {
    if player_query.is_empty() {
        return;
    }
    if camera_query.is_empty() {
        return;
    }
    let player_pos = player_query.single().translation;
    let mut value = camera_query.single_mut().1;
    *value = Transform::from_xyz(player_pos.x, PLAYER_Y - player_pos.y, player_pos.z + 3.0)
        .looking_at(player_pos, Vec3::Y);
}

What went wrong

The FPS goes down to ~35 when I spawn 128 x 128 cubes. Which is not a particularly large level size. It crawls to ~10 fps when I spawn 1280 x 1280 cubes. I also tried rendering with the high entity count PR, but that didn't really change much either. Now, I understand that 1280 x 1280 is quite a lot of entities, but wouldn't frustum culling do away with anything not visible? Also, even if tiling would work, constructing bigger levels with lots of floor texture changes would still quickly run into a high entity situation. So either I'm doing something wrong or something is really slow here.

Additional information

Other information that can be used to further reproduce or isolate the problem.

Screenshot 2022-09-20 at 11 04 17

@terhechte terhechte added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Sep 20, 2022
@konsti219
Copy link
Contributor

Did you compile with --release?

@afonsolage
Copy link
Contributor

afonsolage commented Sep 20, 2022

I have some doubts if this is a bug or just a heavy unoptimized way to rendering a floor. So here are some things to keep in mind:

  1. If you are running in debug mode, there are a lot of checks which is done, that in release mode aren't (you can compile only Bevy dependencies in release, by adding opt-level = 3 or a [profile.dev.package."*"] section)
  2. Every floor tile is being spawned as a cube, which has 16 vertices;
  3. You are spawning 1.6m cubes, even tho there is a frustum culling, that is a lot of entities;
  4. Debug printing will slow down your FPS and should not be used to measure performance, it most intended as a quick and dirty way to check the current FPS with some error margin;

With all being said, if you have made this previous work with other engine and it acted as you expected, that may be a bug in Bevy, but I don't expect any market engine to have a good performance under those conditions.

Note: I tried your conde on my machine and I got 0.1 FPS

@terhechte
Copy link
Author

@afonsolage I did try a release build before I submitted here, yes.

Good to know that debug printing will slow down the FPS. This is really the first time I'm using a game engine to do 3d stuff, so I wasn't sure about the limitations. I did try to recreate the scene in Godot but I gave up quickly because I found everything a tad unintuitive.
The 1280 x 1280 was mostly for testing the limits, but even with 128 x 128 I had problems. However spawning planes instead of cubes does speed this up quite a bit. I'll try some more. Thanks!

@afonsolage
Copy link
Contributor

Since it seems that it isn't a bug on Bevy, the issue will likely to be closed, but you may consider joining the Discord, so we may help you out with what you are trying to achieve.

Also, you can use the discussion tab on GitHub, that way, other users with experience in 3D rendering may help you also.

@terhechte
Copy link
Author

Will do, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled
Projects
None yet
Development

No branches or pull requests

3 participants