Jump to content
  • Advertisement
Sign in to follow this  
Avencherus

Interpolating a direction that reverses.

This topic is 745 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I ran into an issue with interpolating a distance of an object when it reverses direction.

 

These objects interpolate between a previous position and a current position based on an alpha value that represents a percentage of time.

 

However, when it hits a wall, I have the ball reflect away from the wall with it's remaining velocity.  If it has a velocity that travels 100 pixels, and was previously 20 pixels away from that wall, it will be pushed out 80 pixels and have it's velocity reversed.

 

Now the problem is that it's previous position is much closer than 100 pixels, so it's interpolation will do a slow gliding.

 

The best solution I could come up with is to project the previous position to where the ball would've been if it were traveling from the other direction, ignoring the wall.  This still has some issues with it in application.

 

So when a collision and response happens:  previous = current + velocity

Then for interpolation:  interpolation = previous + (current - previous) * alpha

 

Mainly I was wondering aside from increasing the resolution, is there some clever solution or other information I should retain?

 

Below I attached an image that hopefully depicts the problem well enough.

A: Is no collision.

B: Is the collision, but the interpolation of 80% taking place between the new and old positions.

C: Is my best attempt so far at a solution.  The previous position is the new position plus the velocity.

Share this post


Link to post
Share on other sites
Advertisement
Your alpha value is missing some key information. You should track the start timestamp for interpolation and the end timestamp instead. Then you can compute alpha based on the current timestamp with minimal effort.

When you hit an obstacle or otherwise change directions, set the start time of interpolation to the time of impact, and the end time to the timestamp at which your end-position is valid. Problem solved :-)

Share this post


Link to post
Share on other sites

Your alpha value is missing some key information. You should track the start timestamp for interpolation and the end timestamp instead. Then you can compute alpha based on the current timestamp with minimal effort.

When you hit an obstacle or otherwise change directions, set the start time of interpolation to the time of impact, and the end time to the timestamp at which your end-position is valid. Problem solved :-)

 

I see.  I still have some questions if you don't mind.

 

I'm currently testing it inside a game loop, so I'm trying to wrap my head around where the logic might find a home for measuring and storing the time of impact.  At the moment it's just update(dt) and render(remainingTime / dt) running inside that loop.

 

I would like to avoid having the rendering doing collision detection calculations.  Where would it be best implemented?

 

Then assuming this value is now available, when or how does rendering code would know there was an impact to interpolate from?

Share this post


Link to post
Share on other sites
There's a lot of options here, but the simplest one I can think of is to have your physics/collision/etc. run one frame ahead of the renderer.

Physics should output the "future" position of all objects in this case, and the renderer interpolates between the past frame's position of the object up to the future position over dt. By the time the renderer reaches the "future" you should have had time to simulate another physics tick and move up the interpolation.

Share this post


Link to post
Share on other sites

There's a lot of options here, but the simplest one I can think of is to have your physics/collision/etc. run one frame ahead of the renderer.

Physics should output the "future" position of all objects in this case, and the renderer interpolates between the past frame's position of the object up to the future position over dt. By the time the renderer reaches the "future" you should have had time to simulate another physics tick and move up the interpolation.

 

Thanks for replying.

 

I am letting the render lag behind one frame.  Everything works very well at high frame rate and objects traveling at particular speeds.  However, I'm concerned about how to interpolate in the cases that might be low frame rate, or a really fast moving object.

 

An object in these cases could cover a lot of distance in one update.  In the update it will find a future position, in doing so it will reflect off the wall when testing it's collision.  However, in that one frame of update, the future position will be closer to the previous position, rather than further away, since it bounced back towards it.  So the alpha, whatever it may be, would be applied directly between those positions.  In the case where it's close to 100% it should be rendered somewhere between the new(future) position and the wall it hit, not between the previous and new points.  Not like the center image (B.) in my posted diagram.

 

I imagine the problem being something like interpolating the total distance, and then tracing it in the positive direction and reflect the remainder in the negative direction across the path the object took.  If it were 100 pixels with an alpha of .75, maybe the object hits the wall at 50 pixels and bounces 50 pixels away.  The path of the interpolation is going to be 75 pixels, where it takes 50 to make contact with the wall, and then has -25 as reflected, offsetting it 25 pixels from the wall.

 

I just haven't found a clean way to communicate this to the rendering logic.  The time of impact suggestion sounds interesting, but I'm still trying to think of what needs to be captured and calculated, and when, in the context of a fixed time step loop.

Edited by Avencherus

Share this post


Link to post
Share on other sites
Scenario:
At time 0, the ball is headed towards the wall.
At time 0.5 it hits it.
At time 1, it's moved a bit away from the wall.

You calculate physics positions for time 0 and 1, and tell the renderer to interpolate all positions between time 0 and 1.

If you reset your interpolation start/end like suggested above, you will be unable to properly represent times before 0.5.

If you want an interpolation function that works for pre and post collision times, it would have to look something like:
 
if (t < 0.5)
{
    interpolatedPosition = initialPosition + initialVelocity * t;
}
else // t >= 0.5
{
    interpolatedPosition = impactPosition + postImpactVelocity * (t - 0.5);
}
But then... what if there is more than one impact per physics frame? (Ex: it hits both walls at the very corner of a room)

Generalized, your information would look be an array of "rays" that indicate the movement change at a specific time:
 
float time;
Vector origin;
Vector velocity;
With a function that works something like this:
 
entry = binary search to find the last entry with entry.time < interpolationTime
position = entry.origin + entry.velocity * (interpolationTime - entry.time);
Your physics code would update the entries each time a collision or some other velocity-altering event occurs. You could also add acceleration to the entries if you have a constant acceleration to take into account. Edited by Nypyren

Share this post


Link to post
Share on other sites

Scenario:
At time 0, the ball is headed towards the wall.
At time 0.5 it hits it.
At time 1, it's moved a bit away from the wall.

You calculate physics positions for time 0 and 1, and tell the renderer to interpolate all positions between time 0 and 1.

If you reset your interpolation start/end like suggested above, you will be unable to properly represent times before 0.5.

If you want an interpolation function that works for pre and post collision times, it would have to look something like:
 

if (t < 0.5)
{
    interpolatedPosition = initialPosition + initialVelocity * t;
}
else // t >= 0.5
{
    interpolatedPosition = impactPosition + postImpactVelocity * (t - 0.5);
}
But then... what if there is more than one impact per physics frame? (Ex: it hits both walls at the very corner of a room)

Generalized, your information would look be an array of "rays" that indicate the movement change at a specific time:
 
float time;
Vector origin;
Vector velocity;
With a function that works something like this:
 
entry = binary search to find the last entry with entry.time < interpolationTime
position = entry.origin + entry.velocity * (interpolationTime - entry.time);
Your physics code would update the entries each time a collision or some other velocity-altering event occurs. You could also add acceleration to the entries if you have a constant acceleration to take into account.

 

 

Interesting.  Is it correct to say that it's about having the physics-update generate a list of positions and times during specific events, such as collision?  Then having the interpolation traverse through it based on alpha.  After finding a position between two points that the alpha falls between in measure of time, interpolate between these points using a recalculated alpha.

 

Either way, it gives me more to think about, appreciate the post.  =)

Share this post


Link to post
Share on other sites

Is it correct to say that it's about having the physics-update generate a list of positions and times during specific events, such as collision?  Then having the interpolation traverse through it based on alpha.  After finding a position between two points that the alpha falls between in measure of time, interpolate between these points using a recalculated alpha.


Yeah, that's the idea. Maintaining such a list will add some overhead to your physics and rendering code, so you'll have to see whether it works for you and whether it's worth the cost or not.

Share this post


Link to post
Share on other sites

Yeah, that's the idea. Maintaining such a list will add some overhead to your physics and rendering code, so you'll have to see whether it works for you and whether it's worth the cost or not.

 

Awesome, thanks.  ^_^

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!