Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid behavior of TimestepMode::Interpolated #464

Open
Vixenka opened this issue Dec 22, 2023 · 3 comments · May be fixed by #474
Open

Invalid behavior of TimestepMode::Interpolated #464

Vixenka opened this issue Dec 22, 2023 · 3 comments · May be fixed by #474
Labels
A-Integration very bevy specific bug Something isn't working D-Difficult Needs strong technical background, domain knowledge, or impacts are high, needs testing... P-High arbitrary important item S-not-started Work has not started

Comments

@Vixenka
Copy link

Vixenka commented Dec 22, 2023

I have a problem with TimestepMode::Interpolated, I analyze a code of this mode since few days and finally I think: it can not work correct with user defined systems.

Why?

Interpolated mode tries to keep selected frame rate (delta time) of physics pipeline steps like another engines tries to do this in thing which named FixedUpdate. Bevy also have their own FixedUpdate and it is a place where I tried to place things from my user defined systems, but this causes skipping Rapier's physics steps for my data which works by jitter.

Expected behavior

User defined systems should execute once for every Rapier's physics step. Rapier should do they work on end of every subupdate from Bevy's FixedUpdate instead of created own implementation of that. Or executing user defined systems in their own subupdate loop. In my opinion, first option is better.

A gameloop should looks like this:
expected_behavior

Actual behavior

User defined systems executes independently than Rapier's physics step. Code of step_simulation system invoke whole pipeline work in itself, without any calls of user defined systems etc. And this causes changing a data between user defined systems without propagating this in physics.

A gameloop looks now:
actual_behavior (1)

Reproduction

Registring:

// I register this in FixedUpdate, because I want to keep selected physics delta time, like another engines do that. 
app.add_systems(FixedUpdate, move_characters);

System code:

fn move_characters(mut query: Query<&mut KinematicCharacterController>) {
    for (mut controller) in &mut query {
        // Property of controller should always be `None`, because it was cleared after any pipeline step.
        // But now it can be executed few times before next pipeline step will be executed.
        controller.translation = Some(Vec3::new(0.0, 0.0, 1.0));
    }
}

Environment:

  • bevy v0.12.1
  • bevy_rapier v0.23.0

Research steps

I tried to eliminate the same problem like @liquidev, because I work with him.

@liquidev's idea of invalid interpolation

He started from this idea, and even he make a pull request #463 which try to fix that, but this is not patching our problem and in my opinion (he do not must agree with that) his changes are wrong, but I plan to explain why in that pull request.

Idea of unstable delta time

Bevy's ECS scheduler currently have a little problem with delta time stability. This is described in bevyengine/bevy#4669. Even @liquidev create chart of this, and how it is related with Rapier's lerp problem (dz is variation in character's position in z axis):
image

Initially I think about this like a big problem with lerp, but after consideration I think ustabilities like that should not very influence Because things which is unrelated with physics looks fine on different FPS, and generally so many published games on any engines have unstable frame time, but looks fine.

Generally from what I understanded and noticed, this relation exists, because this unstability causes an aditionals Rapier's subupdate and Bevy's FixedUpdate subupdate, which start a whole problem which I explain in this issue.

@Vixenka
Copy link
Author

Vixenka commented Dec 22, 2023

Ok, we moved this to graph from expected behavior and now this works almost correctly. Almost because this still have a bit problems with this lerp from #463.

@Vixenka
Copy link
Author

Vixenka commented Jan 25, 2024

Notes

Simple game loop:

let fixed_time = n;

let mut previous_time = get_system_time();
let mut overstep = 0.0;

loop {
    let current_time = get_system_time();
    let elapsed_time = current_time - previous_time;
    previous_time = current_time;
    overstep += elapsed_time;
    
    while overstep >= fixed_time {
        fixed_update();
        overstep -= fixed_time;
    }

    pre_update();
    update();
    post_update();
    render();
}

For n = 6 and frametime = 10 this will result:

Frame id Initial overstep Overstep Number of FixedUpdates Number of Updates
0 0 0 0 1
1 0 10 1 1
2 4 14 2 1
3 2 12 2 1
4 0 10 1 1

For n = 4 and frametime = 10 this will result:

Frame id Initial overstep Overstep Number of FixedUpdates Number of Updates
0 0 0 0 1
1 0 10 2 1
2 2 12 3 1
3 0 10 2 1
4 2 12 3 1

With this definition of fixed update function:

fn fixed_update() {
    position += 1;
}

Rendered data will be looks:

n = 6 and frametime = 10

Frame id Position Position delta
0 0 0
1 1 1
2 3 2
3 5 2
4 6 1

n = 4 and frametime = 10

Frame id Position Position delta
0 0 0
1 2 2
2 5 3
3 7 2
4 10 3

@Vixenka
Copy link
Author

Vixenka commented Jan 29, 2024

Little update which is works sooo nice, but still it have little problems due to unstable real time in Bevy.
liquidev@8dfab9c

@Vixenka Vixenka linked a pull request Jan 31, 2024 that will close this issue
@Vrixyz Vrixyz added bug Something isn't working D-Difficult Needs strong technical background, domain knowledge, or impacts are high, needs testing... P-High arbitrary important item S-not-started Work has not started A-Integration very bevy specific labels May 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Integration very bevy specific bug Something isn't working D-Difficult Needs strong technical background, domain knowledge, or impacts are high, needs testing... P-High arbitrary important item S-not-started Work has not started
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants