#Fly Camera Jitter/Stutter

17 messages · Page 1 of 1 (latest)

mystic coral
#

I'm having issues with my camera movement not being smooth. I'm not sure what I'm missing. I lerp my camera position every update and update the player position on a fixed physics update. As far as I can tell, my system implementation is more or less textbook, but I'm new to bevy and I think something is still wrong with the ordering somehow. Any ideas?

fn main() {
    App::new()
    .add_plugins(DefaultPlugins)
        .add_systems(Startup, (
            setup,
            window_setup,
        ))
        .add_systems(Update, (
            (process_mouse_input,
            process_keyboard_input),
            lerp_positions,
        ).chain())
        .add_systems(FixedUpdate, physics_update)
        .run();
}  
#

Notably, the PlayerBundle uses the #[bundle()] on the camera bundle, so the camera bundle's transform is getting reused directly as the player's transform instead of using a separate position for each.
Here's my player, lerp_positions, and physics_update implementation for reference:

struct PlayerBundle {
    player: Player,
    position: TargetTransform,
    velocity: Velocity,

    #[bundle()]
    camera: Camera3dBundle,
}

fn lerp_positions(mut tick: ResMut<PhysicsTick>, time: Res<Time>, fixed_time: Res<FixedTime>, mut query: Query<(&mut Transform, &TargetTransform)>)
{
    tick.stopwatch.tick(time.delta());
    let s = tick.stopwatch.elapsed().as_secs_f32() / fixed_time.period.as_secs_f32(); 
    for (mut transform, target) in query.iter_mut() {
        transform.translation = transform.translation.lerp(target.0.translation, s);
    }
    println!("{}",s);
}

fn physics_update(mut tick: ResMut<PhysicsTick>, time: Res<FixedTime>, mut query: Query<(Option<&mut Player>, &mut TargetTransform, &mut Velocity)>) {
    tick.stopwatch.reset();
    println!("reset");
    for (player_option, mut target, mut velocity) in query.iter_mut() {
        // Do half the update using last tick's velocity
        target.0.translation += velocity.0 * time.period.as_secs_f32() * 0.5;
        // Update velocity
        // First, apply friction
        velocity.0 *= 0.1_f32.powf(time.period.as_secs_f32());
        match player_option {
            Some(_) => {
                let player = player_option.unwrap();
                // update velocity with new input
                velocity.0 += player.input_dir * player.acceleration;
            },
            _ => {}
        }
        // clamp max velocity
        velocity.0 = velocity.0.clamp_length_max(8.0);
        // Do half the update using the new velocity
        target.0.translation += velocity.0 * time.period.as_secs_f32() * 0.5;
    }
}
#

and here's some sample output from the prints, to give some idea of the current scheduling behavior:

0.8467055
reset
0.80107516
reset
0.8002933
1.60289
reset
0.7497614
reset
0.87058765
reset
0.7693757
reset
0.8160051
1.6061858
reset
jovial current
#

This kind of stutter is generally caused by a system ordering issue

mystic coral
#

After digging into the system ordering more, I still have no idea what the issue could be. All the actual position updates used for rendering happen in Update, before TransformPropagate in PostUpdate, changing the ordering of my systems in Update has no noticeable effect, and disabling my lerp just makes the jitter worse.

#

My best idea is maybe I could try doing something weird like using a running average of the number of ticks between lerps instead of the absolute amount to attempt to smooth it more.

#

Frankly, I don't really want to do that, it doesn't sound like the answer.

#

Maybe it would just work, though.

jovial current
#

I would update the camera position independently of the physics

mystic coral
#

It is, the physics only updates the target postion

#

the actual camera position is updated every frame during the lerp in Update

#

Stepping through the footage frame by frame, it seems like even though the camera rotation updates every frame, the camera position sometimes doesn't change for several frames

mystic coral
#

Probably this would go away if I ran a release build, but if the physics update ever runs late it'll become noticeable again, maybe I need to project the position beyond the target if the physics update is running late?

jovial current
#

no it wouldn't fix it in release mode

mystic coral
#

damn, it should already be doing this...

#

I guess it's more like it's teleporting from the projected position to the actual?