Skip to content

When using 2D and 3D cameras, moving the 2D UI camera to a nondefault render layer makes shadows flicker #19166

Open
@janhohenheim

Description

@janhohenheim

Bevy version

0.16.0

Relevant system information

AdapterInfo { name: "AMD Radeon RX 7900 XTX (RADV NAVI31)", vendor: 4098, device: 29772, device_type: DiscreteGpu, driver: "radv", driver_info: "Mesa 25.0.3", backend: Vulkan }

What you did

I have the following "concepts":

enum CameraOrder {
    World,
    ViewModel,
    Ui,
}

impl From<CameraOrder> for isize {
    fn from(order: CameraOrder) -> Self {
        order as isize
    }
}

bitflags! {
    struct RenderLayer: u32 {
        const DEFAULT = 0b00000001;
        const VIEW_MODEL = 0b00000010;
        const PARTICLES = 0b00000100;
        const GIZMO3 = 0b0001000;
        const UI = 0b0010000;
    }
}

impl From<RenderLayer> for RenderLayers {
    fn from(layer: RenderLayer) -> Self {
        RenderLayers::from_iter(layer.iter().map(|l| (l.bits() >> 1) as usize))
    }
}

Using these terms, my hierarchy is as follows:

  • UI camera
  • Player camera parent
    • World model camera
    • View model camera

where the relevant code look like this:

UI Camera

Full code: https://github.com/janhohenheim/foxtrot/blob/nondefault-ui-cam/src/ui_camera.rs#L18-L32

(
    Name::new("UI Camera"),
    Camera2d,
    IsDefaultUiCamera,
    Camera {
        // The UI camera order is the highest.
        order: CameraOrder::Ui.into(),
        ..default()
    },
)
World Model Camera

Full code: https://github.com/janhohenheim/foxtrot/blob/nondefault-ui-cam/src/gameplay/player/camera.rs#L98-L125

(
    Name::new("World Model Camera"),
    Camera3d::default(),
    Camera {
        order: CameraOrder::World.into(),
        hdr: true,
        ..default()
    },
    RenderLayers::from(
        RenderLayer::DEFAULT | RenderLayer::PARTICLES,
    ),
    Bloom::NATURAL,
    #[cfg(feature = "native")]
    (
        Msaa::Off,
        ScreenSpaceAmbientOcclusion::default(),
        TemporalAntiAliasing::default(),
        NormalPrepass,
        ShadowFilteringMethod::Temporal,
    ),
)
View Model Camera

Full code: https://github.com/janhohenheim/foxtrot/blob/nondefault-ui-cam/src/gameplay/player/camera.rs#L128-L148

(
    Name::new("View Model Camera"),
    Camera3d::default(),
    Camera {
        // Bump the order to render on top of the world model.
        order: CameraOrder::ViewModel.into(),
        hdr: true,
        ..default()
    },
    // Only render objects belonging to the view model.
    RenderLayers::from(RenderLayer::VIEW_MODEL),
)

The lights all belong to RenderLayer::DEFAULT | RenderLayer::VIEW_MODEL:

Light setup

Full code: https://github.com/janhohenheim/foxtrot/blob/nondefault-ui-cam/src/gameplay/player/camera.rs#L248-L270

fn add_render_layers_to_point_light(trigger: Trigger<OnAdd, PointLight>, mut commands: Commands) {
    let entity = trigger.target();
    commands.entity(entity).insert(RenderLayers::from(
        RenderLayer::DEFAULT | RenderLayer::VIEW_MODEL,
    ));
}

fn add_render_layers_to_spot_light(trigger: Trigger<OnAdd, SpotLight>, mut commands: Commands) {
    let entity = trigger.target();
    commands.entity(entity).insert(RenderLayers::from(
        RenderLayer::DEFAULT | RenderLayer::VIEW_MODEL,
    ));
}

fn add_render_layers_to_directional_light(
    trigger: Trigger<OnAdd, DirectionalLight>,
    mut commands: Commands,
) {
    let entity = trigger.target();
    commands.entity(entity).insert(RenderLayers::from(
        RenderLayer::DEFAULT | RenderLayer::VIEW_MODEL,
    ));
}

This all works fine. Now let's do one little change by moving the UI camera to a nondefault render layer:

fn spawn_ui_camera(mut commands: Commands) {
    commands.spawn((
        Name::new("UI Camera"),
        UiCamera,
        IsDefaultUiCamera,
        Camera {
            order: CameraOrder::Ui.into(),
            ..default()
        },
        // This line causes the issue
        RenderLayers::from(RenderLayer::UI),
    ));
}

What went wrong

The lights flicker uncontrollably (warning for flashing lights!)

Screencast_From_2025-05-10_14-39-17.mp4

Interestingly, this only happens when moving close to my spot lights

Screencast_From_2025-05-10_14-43-52.mp4

Additional information

To see this in action, clone https://github.com/janhohenheim/foxtrot/tree/nondefault-ui-cam (note the branch) and run bevy run.

This has only happened on native, but it's hard to test this on Wasm since there, the lights ignore most of the obstacles in their way anyways:

Image

Instead, I get #19167 on web

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-RenderingDrawing game state to the screenC-BugAn unexpected or incorrect behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions