bevyengine / bevyengine/bevy

[0.13] An orthographic 2d Camera on top of a 3d Perspective Camera - Potential bug with Camera2d ClearColorConfig

Open
#12,121 7 comments 3 reactions 0 assignees View on GitHub
A-Rendering C-Bug
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

0.13

Just in case it doesn't happen for someone - I don't think so, but better save than sorry:

```ignore
` bevy_render::renderer: AdapterInfo { name: "AMD Radeon RX 6700 XT (RADV NAVI22)", vendor: 4098, device: 29663, device_type: DiscreteGpu, driver: "radv", driver_info: "Mesa 24.0.1-arch1.1", backend: Vulkan }`
```

## What you did

I want to render a menu on top of a "scene" (not a bevy scene) - Right now that's for an "interactive" main-menu... I want a background "video" (actually just a small example world rendered where the camera moves around)

I want to add TWO cameras

1. 3d perspective camera for the actual world
2. 2d orthographic camera for the UI

I want to have that distinction - especially since I want to add some specific cursor-images to my HUD and it's way easier with `viewport_to_world_2d`.

`main.rs`

```rust

use bevy::{prelude::*, window::WindowResolution};

fn main() {
App::new()
.add_plugins(
DefaultPlugins
.set(ImagePlugin::default_nearest())
.set(WindowPlugin {
primary_window: Some(Window {
resolution: WindowResolution::new(1920.0, 1080.0),
title: "Just a test".to_owned(),
..default()
}),
..default()
}),
)
.add_plugins((
camera::CameraPlugin,
mainmenu::MainMenuPlugin,
world::WorldPlugin,
))
//.insert_resource(Msaa::Off)
.run();
}

mod camera {
use bevy::{core_pipeline::bloom::BloomSettings, prelude::*};

#[derive(Component)]
pub struct MainCamera;

#[derive(Component)]
pub struct UiCamera;

pub struct CameraPlugin;

impl Plugin for CameraPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup)
.add_systems(Update, move_camera_around_origin);
}
}

fn setup(mut cmd: Commands) {
info!("Setting up cameras!");
// 3d Main Camera
cmd.spawn((
Camera3dBundle {
camera: Camera {
hdr: true,
clear_color: ClearColorConfig::Custom(Color::BLACK),
..default()
},
projection: bevy::prelude::Projection::Perspective(PerspectiveProjection {
fov: std::f32::consts::PI / 6.0,
..default()
}),
..default()
},
BloomSettings {
intensity: 0.3,
..default()
},
MainCamera,
))
//.insert(ScreenSpaceAmbientOcclusionBundle::default())
//.insert(TemporalAntiAliasBundle::default())
;

// UI
let mut cam = Camera2dBundle::default();
cam.camera.order = 2; // On top of the 3d "background" camera
cam.camera.clear_color = ClearColorConfig::None; //::Custom(Color::NONE);
cmd.spawn((cam, UiCamera));
}

fn move_camera_around_origin(
time: Res

// camera will always orbit 0,0,0, but can look somewhere slightly different
const CAM_TARGET_X: f32 = 2.0;
const CAM_TARGET_Z: f32 = -5.5;

const CAM_T_OFFSET: f32 = -0.4;
let mut transform = query.single_mut();
let time = std::f32::consts::PI - time.elapsed_seconds() * CAM_SPEED + CAM_T_OFFSET;
transform.translation.x = time.sin() * CAM_DISTANCE;
transform.translation.y = CAM_HEIGHT;
transform.translation.z = time.cos() * CAM_DISTANCE;
transform.look_at(Vec3::new(CAM_TARGET_X, 0.0, CAM_TARGET_Z), Vec3::Y);
}
}

mod mainmenu {
use bevy::prelude::*;

pub struct MainMenuPlugin;

impl Plugin for MainMenuPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup);
}
}

fn setup(mut cmd: Commands, ass: Res) {
let image = ass.load("ui/panel-border-030.png");

let slicer = TextureSlicer {
border: BorderRect::square(22.0),
center_scale_mode: SliceScaleMode::Stretch,
sides_scale_mode: SliceScaleMode::Stretch,
max_corner_scale: 1.0,
};

cmd.spawn((NodeBundle {
style: Style {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..default()
},
..default()
},))
.with_children(|parent| {
parent
.spawn((
ButtonBundle {
style: Style {
width: Val::Px(300.0),
height: Val::Px(100.0),
// horizontally center child text
justify_content: JustifyContent::Center,
// vertically center child text
align_items: AlignItems::Center,
margin: UiRect::all(Val::Px(20.0)),
..default()
},
image: image.clone().into(),
..default()
},
ImageScaleMode::Sliced(slicer.clone()),
))
.with_children(|parent| {
parent.spawn(TextBundle::from_section(
"Play",
TextStyle {
font: ass.load("fonts/FiraSans-Bold.ttf"),
font_size: 40.0,
color: Color::rgb(0.9, 0.9, 0.9),
},
));
});
});
}
}

mod world {
use bevy::prelude::*;

pub struct WorldPlugin;
impl Plugin for WorldPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup);
}
}

fn setup(
mut cmd: Commands,
mut meshes: ResMut>,
mut materials: ResMut>,
) {
cmd.spawn((PbrBundle {
mesh: meshes.add(Sphere::new(0.6)),
material: materials.add(Color::WHITE),
transform: Transform::from_xyz(-0.9, 0.5, -4.2),
..default()
},));
}
}
```

`Cargo.toml`

```rust
[package]
name = "bevy_bug_camera_ui"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bevy = { version = "0.13" }
```

## What went wrong

The problem: When I add the Camera2d with `order: 2` (so it renders on top of the Camera3d) and `clear_color = ClearColorConfig::None;` there is a black background:

![screenshot_26 02 2024-12 08 27](https://github.com/bevyengine/bevy/assets/97800396/27b4f61d-73d0-4077-a990-fdca387f6a4f)

If I do NOT spawn the camera2d:

```rust
//cmd.spawn((cam, UiCamera));
```

Then it looks like this:

![screenshot_26 02 2024-12 09 17](https://github.com/bevyengine/bevy/assets/97800396/562fede5-3d18-4354-a0b1-6fca71914f11)

The UI is rendered on top of the 3d camera which renders an unlighted Sphere.

Contributor guide

Open the contributing guide

Research direction

Start by running the reproduction from main.rs with the Bevy 0.13 dependency in Cargo.toml, focusing on the Camera3d and Camera2d setup. Investigate how camera order and ClearColorConfig::None interact when both cameras render, then verify that the 3D scene remains visible behind the UI without the black background.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.