Jump to content

Calculate coefficient for smooth physical movement


photo

Recommended Posts

I use Body::setLinearVelocity() function to move some physical objects. In flush method I calculate force, that applies to body (in every frame) to move object from current position to destination position. This movement seems smooth with good fps, but when fps is low or tear, object moves by jerks. I use next logic:

 

vec3 pos = body.getWorldCenterOfMass();
vec3 p2 = ...; // calculating destination pos

float ifps = engine.game.getIFps() / engine.physics.getIFps() * engine.physics.getScale(); // calculate coefficient, that must smooth movement

vec3 force = (p2 - pos) * 0.5f / engine.game.getIFps();
force *= ifps;

body.setLinearVelocity(force); // apply force to object

 

Question is: anybody know, how to calculate right coefficient, that will be take into account different frame rate? Thanks.

Link to comment

Interpolation is already done under the hood. The engine interpolates positions of the object so that it is rendered smoothly in-between physics calculations (i.e. based on the calculated position of the body). In fact, the problem that should be dealt with is low FPS, not interpolation.

When the rendering framerate is low, your physics will have time to be calculated several times updating the body position while the previous one was not yet rendered. That is the reason of jerks. Only update() code optimization together with world optimization would help.

 

A workaround is to slow down the game (not only physics! but the whole game: physics + animations, particles, etc.) manually, when the rendering framerate drops. In this case, use the following:

1. Calculate the body velocity with which it should move to get to the destination point in flush():

 

vec3 direction = (p2 - pos) * 0.5f;
vec3 velocity = direction / engine.physics.getIFps();

2. In the update() add some game FPS managing code. If engine.game.getIFps returns too high value, scale it down manually.

Link to comment

I see. But I think, there is one reason more: I use body.setLinearVelocity(force), and in all frames I clear old force, and add new... So, this can add jerks too. Instead this, I try to use next:

vec3 pos = body.getWorldCenterOfMass();
vec3 p2 = ...; // calculating destination pos

vec3 force = (p2 - pos) * 4.0f;
force /= engine.physics.getIFps();

body.addWorldForce(pos, force);

In this way all jerks is vanish, but appears (increase) amplitude movements - object move to destination point, then object pass through it, and move by inertia, then it move to some threshold, and move back, again it pass it destination point and move further. It seems like swing of the pendulum. This movements decreasing in time, and after some time (about minute) this movements is finished, and object hovers in destination point (result, that I need).

 

So new question is: how to decrease this swings? Object must react more quickly.

Link to comment

These are two different approaches that both have their own specifics:

 

  • If you use setLinearVelocity(), you directly reset body's velocity each physics tick without accounting for its velocity in the previous frame. Thus, you can set an exact position you want body to get to.
  • If you use addForce() it hard to get a body to the exact position, but the body movement is smooth. With forces, you effectively push the body and it slides in the specified direction: forces account for the linear velocity in the previous frame, body inertia, gravity. All applied forces are integrated before changing the body's linear velocity in the current frame.

Have a shot at using engine.game.getTime() and engine.game.setTime(). You can set linear velocity to the body and slow down the game when the framerate drops. The idea is as follows:

 

float time;
float max_frame_time = 1.0f / 20.0f;

void init() {
    time = 0.0f;
    engine.game.setTime(time);
}

void update() {
    float new_time = engine.game.getTime();
    float delta = clamp(new_time - time,0.0f,max_frame_time);
    time += delta;
    engine.game.setTime(time);

    // do something
}

Link to comment
×
×
  • Create New...