Skip to content

Fix Camera::is_active and delayed spawned no cpu culling camera not rendering anything - #25690

Open
CodingDaniel1 wants to merge 4 commits into
bevyengine:mainfrom
CodingDaniel1:fix-camera-is-active
Open

Fix Camera::is_active and delayed spawned no cpu culling camera not rendering anything#25690
CodingDaniel1 wants to merge 4 commits into
bevyengine:mainfrom
CodingDaniel1:fix-camera-is-active

Conversation

@CodingDaniel1

Copy link
Copy Markdown
Contributor

Objective

This is a followup pr for #25670

I have found issues related to toggling is_active at runtime causes the rendering to stop working, and this pr fixes that. While fixing on that, ive found another issues when using NoCpuCulling on Mesh entity, if the camera is spawned after the entity got collected for rendering, then the camera wont render that entity. The reason why NoCpuCulling on Mesh causes this but not on camera, is the gpu mesh collect pass looks for ViewVisibility changes, and cpu culling system will trigger the change detection even if the camera is tagged with NoCpuCulling. But it wont trigger it when mesh have NoCpuCulling .

Solution

For the is_active issue, I removed RenderVisibleEntities from the render camera when its inactive, but dont remove it when the window is minized. This behaviour matches what bevy other places does, which most places dont care if window is minized.

For the second issue, I check to see is RenderVisibleEntities added this frame in collect_gpu_culled_meshes and do a full table flush when RenderVisibleEntities is confirmed to be new. This means a freshly spawned camera will pick up previously registered mesh, and is_active toggling camera will still do the same. Be aware that this is solely for Mesh3d tagged with NoCpuCulling since thats purpose of this function, any Mesh3d not tagged with NoCpuCulling will still go through the cpu collect pass instead.

Testing

I used the following functions to toggle is_active field and use gpu culling path, put it in 3d_scene and ssao example. Live test it, the rendering stays the same when toggling is_active at runtime. But the issue remains on bevy/main.

fn use_no_cpu_culling(add: On<Add<Mesh3d>>, mut commands: Commands) {
    commands
        .entity(add.entity)
        .insert(bevy::camera::visibility::NoCpuCulling);
}
fn set_active(query: Query<&mut Camera>, keyboard: Res<ButtonInput<KeyCode>>) {
    if keyboard.just_pressed(KeyCode::KeyP) {
        for mut cam in query {
            cam.is_active = !cam.is_active;
        }
    }
}

Here is the full code snippet i used for testing both issues. The camera spawning will be delayed by 2sec. On main you will not see anything rendered, but with this pr, rendering is normal.

//! A simple 3D scene with light shining over a cube sitting on a plane.

use bevy::{camera::visibility::NoCpuCulling, prelude::*};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, (scene.spawn(), spawn_cam))
        .add_systems(Update, set_active)
        .add_observer(obs_test)
        .run();
}

/// set up a simple 3D scene
fn scene() -> impl SceneList {
    bsn_list! [
        (
            #CircularBase
            Mesh3d(asset_value(Circle::new(4.0)))
            MeshMaterial3d::<StandardMaterial>(asset_value(Color::WHITE))
            Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2))
        ),
        (
            #Cube
            Mesh3d(asset_value(Cuboid::new(1.0, 1.0, 1.0)))
            MeshMaterial3d::<StandardMaterial>(asset_value(Color::srgb_u8(124, 144, 255)))
            Transform::from_xyz(0.0, 0.5, 0.0)
        ),
        (
            PointLight {
                shadow_maps_enabled: true,
            }
            Transform::from_xyz(4.0, 8.0, 4.0)
        ),
        // (
        //     Camera3d
        //     Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y)
        // )
    ]
}

fn obs_test(add: On<Add<Mesh3d>>, mut commands: Commands) {
    commands.entity(add.entity).insert(NoCpuCulling);
}

fn spawn_cam(mut commands: Commands) {
    commands.delayed().secs(2.0).spawn((
        Camera3d::default(),
        Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
    ));
}

fn set_active(query: Query<&mut Camera>, keyboard: Res<ButtonInput<KeyCode>>) {
    if keyboard.just_pressed(KeyCode::KeyP) {
        for mut cam in query {
            cam.is_active = !cam.is_active;
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant