#Camera rotation causes jittery rendering of objects when moving

73 messages · Page 1 of 1 (latest)

empty anvil
#

I recently pulled my movement system into a fixed time update to make it not tied to frames for consistency but my camera look system (tied to mouse movement events) is still in update.

When I run around and strafe while wiggling the camera around rendered models appear jittery - doesn’t happen if I move rapidly around without the camera look system.

I feel like there’s something I’m missing with the order of execution of the camera system. I also have a camera follow system happening in post update after the transform propagation - I don’t think it’s tied to that as that’s been very smooth.

Any help appreciated ty

empty anvil
#

Okay if I change my camera_follow system to have a big lag with a lerp of 0.01 I don't see the jittery objects, so feels tied to the camera follow system I have

.add_system_to_stage(
    CoreStage::PostUpdate,
    player::camera_follow_entity
        .before(bevy::transform::TransformSystem::TransformPropagate),
)
novel flax
#

I'm guessing the followed entity is in the fixed time update?

#

Because in that case the camera updating would effectively be updating at the same time as the movement

#

since the player would be at a single spot for a couple of frames, then hop to another, the camera doesn't know to smoothly go inbetween the previous position and new position so it appears jittery

#

lerp would fix that since you are now trying to smoothly go between em though

empty anvil
#

Thanks @novel flax will try some stuff out

empty anvil
#

@novel flax I got it running buttery smooth, really awesome. you def helped visualize the steps FixedTimeUpdate is going to do vs. update

#

ty

empty anvil
#

I think I'm still stuck actually, def getting bummed

#

I can't wrap my head around introducing some lerp to the camera follow system (where I have now tried placing the camera rotate code) and keeping the camera at the player's eye level for an FPS game

#

but you know what, this might just be all the winit bug with high polling rate mice

#

and I'm banging my head against the wall for nothing - if I switch the camera to move with the keyboard or do some static look_at(Vec3::Y, Vec3::Y) it's pristine

novel flax
#

could you post the camera follow system in here? Lerping rotation isn't the easiest thing to do

empty anvil
#

after I grab the inputs (keyboard direction vector and mouse events) in a system in Update and store them in the controller I am moving in an iyes_loopless fixedtimestep with

//code above here is just getting camera forward, left, right
//and doing velocities

//Move player
let translate_by = controller_output
    .effective_translation
    .lerp(accelerate, 0.1);
controller.translation = Some(translate_by); //uses bevy_rapier KinematicCharacterController

//Rotate player
let rotate_by = Quat::from_euler(EulerRot::ZYX, 0.0, source_movement.input_state.yaw, 0.0);
player.rotation = player.rotation.slerp(rotate_by, 10. * time.delta_seconds());

//Rotate camera
let rotate_camera_by = Quat::from_euler(
    EulerRot::ZYX,
    0.0,
    source_movement.input_state.yaw, //radians
    source_movement.input_state.pitch, //radians
);
camera.rotation = camera.rotation.slerp(rotate_camera_by, 40. * time.delta_seconds());

then in PostUpdate before the transform propagation the follow system just does this right now

camera.translation = camera.translation.lerp(
    player.translation + (player.forward() * 0.3) + (player.up() * 2.),
    1.,
);
#

you can especially see the snap/jitter right at the end

empty anvil
#

It's also possibly just I am royally screwing up the ordering of things

novel flax
#

I would take the camera follow out of the fixed timestep

#

if it is

#

make it a separate system

empty anvil
#

it's out of there right now

.add_system_to_stage(
    CoreStage::PostUpdate,
    player::camera_follow_entity
        .before(bevy::transform::TransformSystem::TransformPropagate),
)

is where that follow code is

novel flax
#

Move the slerp there too

empty anvil
#

seems the snaps the camera was doing are gone but it introduced the jumps in the rendering as you move + rotate camera...assuming because it's not lerping in the right places

edit: hard to tell if the snaps are gone because of the introduced jumpy rendering

#

If I lerp the camera translation in the follow system it's smooth but of course begins to trail behind the player

novel flax
#

oh take the time.delta_seconds() out from the system lerps as well by the way

#

it won't really give anything useful in a fixed timestep

#

I'm willing to bet some amount of those jitters previously were because delta seconds were too big and caused the lerp to go outside the 0.0 to 1.0 range

#

what you probably want is a lerp based on how far you are from the target translation

#

a simple way you could do this:

let diff = (camera.translation - target.translation).length();
let lerp = diff.clamp(0.0, 1.0);
#

this means that if the camera and the entity to follow are greater than 1 unit apart it will be positioned immediately ontop of it, otherwise it is more smooth

#

ill be around to help more tomorrow, been kind of off and on my computer/phone sorry

empty anvil
#

Thanks a lot for your help so far, I’ll post here with changes / updates soon

empty anvil
#

I took all the time.delta_seconds() out of the fixedupdate systems - hardcoded values for those now

camera_follow system in PostUpdate switched to use your diff and it seems unchanged on the jittery rendering of the objects but introducing any lerp on the camera following makes the player bounce around (shown in last few sec of video)

empty anvil
#

maybe I just need to wait for stageless and the iyes hack is causing this? here's my input collection that runs in Update storing in a struct called SourceMovement, nothing fancy

    //MOUSE
    if let Some(w) = windows.get_primary() {
        if !w.is_focused() || w.cursor_visible() {
            return;
        }
    }

    for event in mouse_motion_events.iter() {
        let yaw = (SENS * event.delta.x).to_radians();
        let pitch = (SENS * event.delta.y).to_radians();
        source_movement.input_state.pitch -= pitch;
        source_movement.input_state.yaw -= yaw;
    }
    source_movement.input_state.pitch = source_movement.input_state.pitch.clamp(-1.5, 1.5);

    //KEYBOARD
    let pressed = actions.get_pressed();
    let mut direction = Vec3::ZERO;
    for action in pressed {
        match action {
            PlayerAction::Forward => direction += Vec3::Z,
            PlayerAction::Back => direction -= Vec3::Z,
            PlayerAction::Left => direction -= Vec3::X,
            PlayerAction::Right => direction += Vec3::X,
            PlayerAction::Jump => direction += Vec3::Y,
            _ => {}
        }
    }
    source_movement.direction = direction;
empty anvil
#

If I change my timestep to be 1ms everything is of course smooth, but hoping to achieve a smoother experience if I increase that to 15ms or so. Strafing has smooth rendering but it's just the moment you move around and rotate the camera is when the shakiness is introduced

empty anvil
#

this has to be an ordering of stages wrong or something. I've reduced the code so much and just make the camera look_at(...) static values and I can see the camera jitter every few seconds. maybe bevy 0.10 will help me out here

novel flax
#

do you have your project up in any repo somewhere?

empty anvil
#

let me slim it down and get it public

empty anvil
#

okay trimmed it down to just the essentials without all my sloppy testing 😅

where the translation happens https://github.com/psiofxt/pipedream/blob/main/src/controller.rs#L142 of the character
camera following the player's translation https://github.com/psiofxt/pipedream/blob/main/src/player.rs#L195
fixedtimestep system adds https://github.com/psiofxt/pipedream/blob/main/src/player.rs#L114

If you run it escape to lock the cursor to WASD. If you strafe around a pillar while rotating the camera you can see the jitter happen every so often

novel flax
#

im not too sure tbh

#

im trying to just exacerbate the problem by making the timestep very low fps

#

actually wait

#

I think I figured it out

#

but I think there are 2 problems here

#

1 is the camera needs to interpolate while inbetween fixed timesteps

#

2 is that the character's model shouldn't be attached to the fixed timestep

#

it should also be interpolated in some way to the "real" position of the player

#

the characters capsule collider is still jittery, but that should be fine

#

also I'm not sure if you added the rapier stuff to the fixed timestep, but that'd probably be a good idea if you are doing the controller there too

#

my guess is a tertiary issue might be that rapier is being funky with all this fixed timestep stuff when it doesn't know about that

#

just replace any add_network_stage_after with a more corresponding iyes loopless thing

#

gonna head to bed though, I'll be around tomorrow if it didn't fully fix it

empty anvil
#

well that completely fixed it and the fixes you did make a lot of sense - never crossed my mind to put the model with the camera (duh)

#

the lerp on the camera makes sense now, no issues except as you said the collider moving like that but I think that's super minor and I saw on the dimforge discord someone debugging the collider movement by adding it after WriteBack or something

#

I can't thank you enough lmk if you have any site or crypto wallet for a tip 😄

novel flax
#

the collider should be fine as that should be like that in a fixed timestep

empty anvil
#

yeah gotcha

novel flax
#

it won't be visible when in actual gameplay anyways so should be good

empty anvil
#

done

novel flax
#

ty 🙂

empty anvil
#

now to just decouple the player model rotation from the camera's rotation

empty anvil
#

that scenebundle is automatically a child of the camera - locking that rotation in the pitch for the player model is proving tricky

novel flax
#

yeah I'd just make a separate entity for the model and have it only follow the translation

#

I've ran into a couple of issues with the transforms propagation not having an opt out for entities

empty anvil
#

It's crazy the small issues you run into with this but just the nature of development. offsetting the camera makes it so when you rotate the player it now lerps the translation of the camera too so not in sync with the player model moving

novel flax
#

ya, a lot of this just ends up being a binary search of things, also just knowing how the deeper stuff works helps a lot