Search code examples
rustbevy

How to use multiple cameras in bevy 0.5.0?


I have a simple bevy test app, that displays an array of cubes and an FPS counter in the upper left corner. The 3d scene can be zoomed and rotated.

I recently tried to upgrade the following code to bevy = 0.5.0.

Old code block (bevy = 0.4.0):

commands.spawn(LightBundle {
            transform: Transform::from_translation(Vec3::new(4.0, 8.0, 4.0)),
            ..Default::default()
        })
        .spawn(Camera3dBundle {
            transform: Transform::from_translation(Vec3::new(0.0, 0.0, 10 as f32 * 1.25))
                .looking_at(Vec3::default(), Vec3::unit_y()),
            ..Default::default()
        })
        .with(OrbitCamera::new(0.0, 0.0, 10 as f32 * 1.25, Vec3::zero()));

commands.spawn(CameraUiBundle::default())
    // texture
    .spawn(TextBundle {
        transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
        style: Style {
            align_self: AlignSelf::FlexEnd,
            ..Default::default()
        },
        text: Text {
            value: " FPS:".to_string(),
            font: asset_server.load("fonts/FiraSans-Bold.ttf"),
            style: TextStyle {
                font_size: 20.0,
                color: Color::WHITE,
                ..Default::default()
            },
        },
        ..Default::default()
    })
    .with(FpsText);

The reason I spawned the TextBundle in a separate camera, was that I wanted it to be stationary and not react to any camera transformations.

I tried to replicate that behaviour in bevy = 0.5.0 like this:

commands.spawn_bundle(LightBundle {
    transform: Transform::from_translation(Vec3::new(4.0, 8.0, 4.0)),
    ..Default::default()
});

commands.spawn_bundle(PerspectiveCameraBundle {
    transform: Transform::from_translation(Vec3::new(0.0, 0.0, 10 as f32 * 1.25)).looking_at(Vec3::default(), Vec3::Y),
    ..Default::default()
})
.insert(OrbitCamera::new(0.0, 0.0, 10 as f32 * 1.25, Vec3::ZERO));

commands.spawn_bundle(UiCameraBundle::default())
.insert_bundle(Text2dBundle {
    text: Text::with_section(
        " FPS:",
        TextStyle {
            font: asset_server.load("fonts/FiraSans-Bold.ttf"),
            font_size: 20.0,
            color: Color::WHITE,
        },
        TextAlignment {
            vertical: VerticalAlign::Top,
            horizontal: HorizontalAlign::Left,
        },
    ),
    ..Default::default()
})
.insert(FpsText);

Everything works as expected again, except the FPS Text is not in the upper left corner of the window anymore and is now rotated and scaled like the cubes in the scene, too (which I don't want to happen).

How can I replicate the old behaviour in bevy = 0.5.0, so that the Text is rendered as a stationary overlay?

The full code for both versions can be found on Github here (0.4.0) and here (0.5.0).


Solution

  • Text2dBundle is associated with the regular camera. If you want text associated with the UI camera, you need to use TextBundle instead. You will also need to set the Style component on the TextBundle in order to control its position so that it's visible on screen.

    Your bevy 0.4 code fragment was using TextBundle successfully, so this just needs porting more faithfully.