Ugly little interpolation problem

EE recently got interpolation (old news at this point) but last night while working on a problem that ConSiGno reported relating to voodoo dolls, I had an unfortunate revelation that it's insufficient to backup objects' positions during Mobj::Think (equiv. of P_MobjThinker in vanilla) because it's possible for objects to move before that.

Theoretical situation demonstrating the possibility:

  • A sleeping imp that is further down the thinker list is hit by a barrel explosion (it is the barrel's thinking turn and it has called P_RadiusAttack).
  • The imp transitions to its seestate in P_DamageMobj and calls the action function A_Chase
  • A_Chase moves the thing via P_SmartMove -> P_Move -> P_TryMove
  • It hasn't thought yet so, its previous position data has just been wiped out.
Given this reality, I don't see any one place in the code where mobj positions can be reliably backed up in every situation *without* the highly undesirable "solution" of iterating over the entire thinker list twice... >_>

Any ideas, or pre-existing solutions I haven't seen yet?

Share this post


Link to post

Calculate the interpolated positions after all moves have taken place for the tic.

Share this post


Link to post
fraggle said:

Calculate the interpolated positions after all moves have taken place for the tic.

I have to interpolate from the previous position to the position the object has at the end of the frame. This implies needing to backup the coordinates at the start of the frame somewhere.

Share this post


Link to post

It's kinda hard to tell what you need from your description. Are "fake-moving" the mobjs on off-tics, and then correcting the positions at the next frame? In other words, do you calculate tic 99.4 mobj x and y positions, then correct them on tic 100? Are you actually moving the mobjs to mid-tic positions in the simulation, or only for rendering? And, finally, if you are rendering tic 99.4, do you forcibly render tic 100.0, or is it possible that the next render might occur at tic 100.2, skipping tic 100.0 altogether?
In other words, you may not render tic 100.0, but you always calculate it, right?

How do you store the interim momentum for that imp, from tic 99 to tic 100? Are you actually running the simulation, and doing mobj->X = mobj->X + (delta / interp_diff)? Are you really changing the standard mobj vars by interpolated amounts, and then backing out, and calculating the actual tic with previous values?

Sorry for my ignorance, but it's interesting stuff. Without knowing the specifics, seems tome that there's still not very many places where a mobj gets moved. Even if it's more than one, is it a big cost to dup some code, call an inline func, or even a normal func? Surely you'd only need to had a few lines per movement, right? Anything is better than iterating all the mobjs per tic.

I don't suppose you could use P_SetThingPosition? That would cover the non-Mobj::Think cases, if I'm not mistaken.

Share this post


Link to post

Of course, all these problems disappear when one extrapolates the "future" values rather than attempting to interpolate between two previously calculated frames. Naturally this will lead to some (very) minor visual issues but these will be corrected automatically every 1/35 seconds...

Clearly one must have two game tics worth in order to interpolate, so, what does Eternity do before the "second" tic's data becomes available (e.g., at the very start of the map)? Or, maybe you always run two tics before attempting to draw the world?

Does any other DOOM port implement this using interpolation? (I don't believe so, but I may be wrong).

Share this post


Link to post
DaniJ said:

Does any other DOOM port implement this using interpolation? (I don't believe so, but I may be wrong).

ZDoom, GZDoom, PrBoom-Plus, Odamex, and Doom64 EX all use interpolation AFAIK.

Share this post


Link to post
DaniJ said:

No, they use extrapolation, not interpolation.

That would be entirely inconsistent with everything I've been told or seen to date. Particularly in the cases of Odamex and PrBoom-Plus.

Share this post


Link to post
Quasar said:

Given this reality, I don't see any one place in the code where mobj positions can be reliably backed up in every situation *without* the highly undesirable "solution" of iterating over the entire thinker list twice... >_>


You are correct, it can't be done without iterating over the entire thinker list again.

ZDoom doesn't handle this case at all, btw.
I personally never noticed because I always use the option NOT to interpolate any movement done by A_Chase, because I always found it looks very bad. This of course will hide the mentioned problem.

The question is, is it really such a problem to iterate the list once more? ZDoom can do this multiple times in one tic, e.g. for some ACS functions affecting multiple actors, and it was never considered a major issue.

Share this post


Link to post

Usually, these ACS functions aren't called every single tic, though.

Share this post


Link to post

From the fact no other ports worry about it, I am getting the impression that it's not a big enough problem to bother disturbing the design of the game engine to fix.

Share this post


Link to post

You add fields for the previous position to the mobj, and a time-stamp of when it was saved.

Before ANY update of position (including the barrel explosion example), the previous time-stamp is checked. If it is less than the global interpolation time-stamp, then the previous position is updated before moving, and the its time-stamp is updated to be the global interpolation time-stamp.

The global interpolation time-stamp provides a consistent time interval to do the later interpolation over. Otherwise you could not trust when the previous positions were saved, and moving the same object twice in a tic would fail to save previous position only once.

There is no need to iterate the list again. The overhead is a time-stamp compare, and a copy of position.

This is similar to the time-stamp used to detect if an object has been updated more than once in a tic.
DoomLegacy has interpolation, but I have not paid any attention to it.
Someone disabled it so it may be unfinished.

Share this post


Link to post
wesleyjohnson said:

You add fields for the previous position to the mobj, and a time-stamp of when it was saved.

Before ANY update of position<snip>

And I'm cutting you off there because it implies mass conversion of everywhere that handles mobj coordinates to a method call. The code is currently in no state for that to happen.

Share this post


Link to post

There is already a method/function call, though (in vanilla at least). Whenever a mobj is moved it is necessary to unlink it from structures like the blockmap and sector lists and then relink it again once the move has been completed. Can't you attach your interpolation hooks here?

Share this post


Link to post
Quasar said:

From the fact no other ports worry about it, I am getting the impression that it's not a big enough problem to bother disturbing the design of the game engine to fix.

Why didn't you provide the brief description I asked for? Interpolation can be done a few different ways, so the method that you used matters. I haven't been able to check the source yet.

I'll make a guess:

Please tell me if this description is correct:
. You calculated frame 99 sometime in the past.
. Then, frame 100 is calculated.
. Now, it's time to render, and your time calcs tell you that you're half-way through a frame.
. You then move mobjs halfway between their frame 99 position and their frame 100 position, and render.
. Finally, you must now move the mobjs back, so your question is:
Where should I store this previous mobj position, and insure that that variable is always up-to-date?

Is that the question?

Share this post


Link to post

So did you resolve it, and, if so, can I ask what the resolution was?

Share this post


Link to post
Quasar said:

EE recently got interpolation (old news at this point) but last night...


I'm assuming no problems arise using 140 HZ vsync...? Can interpolation be disabled?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now