Game Development Community

1.5 1.6 1.7 - Camera Jitter

by DragonSix · in Torque Game Builder · 07/16/2007 (5:59 pm) · 194 replies

When the camera is mounted to a moving sprite, the sprite and the background are trembling (when moving).
Especially visible when there's multiple parallax backgrounds. I have the sprite moving using setlinearvelocity at about 50 and the camera mounted with a force set to 0 or higher than 5, the design screen size is 100*75 on a game resolution of 1024*768. Also, it is clearly more visible with vertical sync (and vertical sync is more than necessary for high resolution). The shaking is not something constant, but it is happening very often. When it happen, it seems like the camera go in the wrong direction then catch up back for the time of 2 frames (so, the lower is the framerate, the more remarkable is the issue).

I just tried a workaround by not mounting the camera. For that, I updated the camera position at the player position in updatescene callaback, using getrenderposition to get the exact drawn sprite position... With no success, everything is still trembling a lot.

It could be many things causing it : something with drawn sprite interpolation or camera interpolation or some updating no more happening precisely on each frame. If someone could take a look at it, I would appreciate the help.
#41
02/13/2008 (11:19 pm)
Changing the tick shift isn't going to resolve this issue. Only make it worse in the long wrong. You are basically doubling the amount of work the engine has to do in a time frame. And it doesn't even address the root of the issue, just pushes it under a rug.

As an experiment, someone should setup a scenario where they are getting camera or object jittering. And then for that scenario set the $timeScale really low and watch and see what the camera / objects are doing. If they are stuttering then it sounds like it is an interpolation problem with the physics and not an update frequency issue.
#42
02/13/2008 (11:50 pm)
Just want to share how I got over this issue. In our game Bubble Warrior I wrote an onUpdate function that force the camera to follow the player or players by

%camera.setPosition( %posVec )  ; 
      // update camera size
     //  update camera area

You could see the camera in action from the video in my plan.

Aun.
#43
02/14/2008 (12:46 pm)
@Aun Arinyasak
I already tried something like that, by putting the following code in t2dscenegraph::OnUpdateScene :
$player.rpos = $player.getrenderposition();
	$player.rposx = getWord($player.rpos, 0);
	$player.rposy = getWord($player.rpos, 1);
	scenewindow2d.setCurrentCameraPosition($player.rposx, $player.rposy, 100, 75);
The result stutter as much as when I mount it (as I told it in the first post of this topic). Maybe you have another way?

@Robert
I just tried, and it still jitter when I change $timescale to 0.2 (a lot less noticeable though).

Updated the topic title to reflect how long it's been around :/
#44
02/14/2008 (1:05 pm)
@Benjamin - If you could distill the problem you're seeing down to a simple test case that really demonstrates the problem clearly, it would probably be helpful. There's a lot of stuff going on in your game, which makes it kind of hard to tell where any weirdness might be happening.
#45
02/14/2008 (1:15 pm)
@Dan
You're right, that's why at first I uploaded this little test case dragon.six.free.fr/deviantgames/camerajittering.rar right after the 1.6 update (see my post from Dec 16, 2007 in this very topic). You should see it jittering too, as I do.
However, in the end, I wouldn't see the point if I couldn't make "big" action games using TGB.
#46
02/14/2008 (3:11 pm)
Ok tested the file that you uploaded one quick question

Why would you want to enable the verticleSync ? What do you need it for ?


Aun.
#47
02/14/2008 (3:17 pm)
I've disable the verticleSync and everything seems to work fine for me, no jitters at all.

Aun.
#48
02/14/2008 (3:18 pm)
Well, tearing on games with lot of scrollings and moving camera is a big no for me, it's as horrid as jittering.
And, beside, it also stutter without vertical sync on bigger games, so it doesn't resolve the problem (as said in some post higher here around august).
#49
02/14/2008 (3:42 pm)
If you really need to enable verticleSync, then I think the camera jittering is understandable.

- Enable verticleSync
+ will try to slow you game down
+ as a result camera will not move smoothly

- Disable verticleSync
+ camera would be updating normally and displaying normally
+ it will anyway, jitters if the framerate goes down. Optimise your game so it runs fast enough.

I had the same problem with my game but since I didn't feel that veticleSync is a big issue so I just disable it.

Good luck.

Aun.
#50
02/14/2008 (4:57 pm)
If anyone else also want to say that the issue doesn't exist because their fighting game or sim-game or whatever-game-that-move-camera-slowly has no jittering or tearing, please post right now and be done with it.
Then, maybe we can go back at trying to resolve it.
#51
02/14/2008 (4:58 pm)
@ Robert Yeah I've been thinking about that and I too suspect the physics iterpolation is not handling things properly. On the face of it I can't see anything wrong with what it's doing though.

@Benjamin I tried your test case with my tickshift change and I get rather horrible jitters still. Turning off the VBL sync helps, but the jitters are still there.
#52
02/14/2008 (5:38 pm)
I'm sorry for the impression. I wasn't trying to tell you that the problem doesn't exist, it does. My statement was that, in my case, I ignored the verticlesync.

I think others that don't mind verticlesync might try this easiest solution.

@ Robert ,Ken : Yes, I think so too.

Good luck guys.
Aun.
#53
02/14/2008 (6:52 pm)
@Aun
You're right, while some genre can still do well, there's cases where it can't be ignored. Sorry but that's why I was getting really nervous about it. All I'm trying to make is an action-platform game, I didn't even made it that much speed-paced, and the issue totally killed it (like totally).

@Ken
Aw, too bad for the time shift (I was thinking it would've been too easy for a so resistant issue). Hopefully the GG guys are on the right track with the two test cases.
#54
02/15/2008 (8:07 am)
I think I've mostly found the problem. Whenever the tick time is a multiple of smTickShift, objects and windows don't do their physics interpolations. So with the default smTickShift of 32, there is a 1/32 chance that physics won't be updated. Plus, when this does happen at 60fps, you'll likely go two frames in a row without a physics update.

At the beginning of both t2dSceneGraph::interpolateTick() and t2dSceneWindow::interpolateTick(), simply comment out the line:
if ( mIsZero(timeDelta) ) return;

The cause problem is probably explained by the comment in t2dSceneGraph::interpolateTick():
// Ignore any interpolation if we're at the start of a tick.
...but a zero timeDelta actually means the end of a tick, so we need to finish our interpolation!

I say mostly above because on the Mac in fullscreen mode it's perfectly smooth but in windowed mode there is still some jitter even when there's not much running in the background taking up cycles. I think this is a different problem, and I'm curious if it occurs on Windows too.

Oh, and this is with the original smTickShift of 5 (=32) on Benjamin's test case. In my own project I still find that I need to have a lower smTickShift to avoid objects jittering. Haven't figured that out yet.
#55
02/16/2008 (8:22 am)
Hi all,

I've been looking at this thread and the code this morning and I'll do some detailed investigation this evening.

First though let me talk about what I've found so far and hopefully summarise the above detail into a simpler problem.

Okay, so first-up I can see a very subtle jitter using the app provided by Benjamin above but it does highlight a problem and I'm grateful to Benjamin for providing it. Of course when I say subtle, that's not to say that it wouldn't break the immersion in a game or just be annoying as hell!

So looking at it carefully on several of my systems (all PC) seems to show that the problem isn't related specifically to mounting. Indeed, if I dismount the camera and move the object around it still exhibits the same occasional jitter. When you mount the camera you see the same jitter except the effect is more profound because the whole scene will jitter. Again, I'm being careful to highlight that this is what *I'm* seeing because in most cases I can only fix what I can reproduce.

Moving on, it is clear that sync-locking to the display is a major catalyst.

Before I talk further let me just clarify a few points on the scene-ticking itself. Hopefully, in providing this info, someone will point out something and say "hey Melv, you've done something dumb"!

The idea is to be able to seperate the internal engine object updates from the rendering system in such a way that they can operate at completely independent frequencies. We want to update the engine-objects at a fixed-frequency that's enough to provide a fine-enough resolution for the simulation itself. We then need to allow the rendering to happen at an arbitrary rate. In other words, the simulation happens on a fixed timebase but your rendering will happen as fast as it can. This makes sense if you've got a uber-graphics card and want lots of FPS. The thing is that it's of no use rendering the same frame again and again at high FPS, you want to actually see something change else what's the point!

So the idea is that during the simulation update, it will note the current state of all engine objects and proceed to calculate the next state for all engine objects. At this point, the next-step is actually the current object state and the current object state is the last object state. In other words, when an update happens the current is noted as the state "from" and the new state as the state "to".

Now these simulation updates happen at a relatively low frequency so what happens from frame-to-frame? Well, this is where interpolation happens. Because the simulation maintains state for each and every object it can calculate (or defer to the object itself) the interpolation state for that object at the current time interval (between updates) so each frame, every object gets a chance to do some simple interpolation before its rendered.

What this means is that the objects state actually changes during simulation update only at a relatively low-frequency. During rendering which could be 60fps or 600fps the engine interpolates the object state. This means (in theory) that the objects will always update state at a fixed-rate which is important (sometimes essential) for the simulation. It also provides finer and finer rendering updates as the FPS goes up. Eventually though having over 100fps, you'll get diminishing returns.

Depending on how the objects store their state and process the interpolation, different methods can be used. In the engine there's an ITickable interface class written by Pat Wilson that provides a number of useful functions. The ones used here are the "processTick" and "interpolateTick". "ProcessTick" provides regular guaranteed updates and "interpolateTick" provides the time-step between ticks.

So back to the problem and the thread above:

Ken mentions the time-delta check above and he's pretty darn close to what I believe the problem is. Indeed, I wish I had read this thread thoroughly before looking at the code this morning! Those lines were part of the development and should not be there, oops! Anyway, the ITickable interface puts this (Zero-delta-time) out to all objects indicating the end of a tick / start of a tick (both are the same thing). This *can* be useful to some processes using the interface but not T2D. In T2Ds case I use the "processTick" which explicitly signifies a new tick and I don't need to do any prep-work to "roll back" the interpolation with the highly implicit zero-time-delta callback. This is because in T2D I *interpolate* between the last and current state rather than extrapolate between the current and a projected state.

So you can go ahead and remove the two lines:
void t2dSceneGraph::interpolateTick( F32 timeDelta )
{
...
    // Ignore any interpolation if we're at the start of a tick.
    //if ( mIsZero(timeDelta) ) return;
...
}
...and...
void t2dSceneWindow::interpolateTick( F32 timeDelta )
{
...
    // Ignore any interpolation if we're at the start of a tick.
    //if ( mIsZero(timeDelta) ) return;
...
}

... continued ...
#56
02/16/2008 (8:22 am)
...

Now removing these lines doesn't solve the problem. What we'll still get from the ITickable interface class is this implicit zero-time-delta callback. Now this wouldn't make much difference in some cases but it can here. Indeed it can cause the interpolation scheme to interpolate between the tick, jump back to the start of the tick and then receive a new update and jump to the next tick. This gives an awful constant jumping motion which you'll know if you see it!

So the next step and this is something that I'll need to chat with the GG guys about (having a phone conference tonight anyway) is the removal of the implicit zero-delta-time callback from the ITickable interface class. At the moment I believe that nothing is keying off this callback anyway. I propose that we remove it or provide another mechanism. The simplest way is to go into the "ITickable.cc" source and remove the following code:
bool ITickable::advanceTime( U32 timeDelta )
{
...
   // If we are going to send a tick, call interpolateTick(0) so that the objects
   // will reset back to their position at the last full tick
   //if( smLastDelta && tickCount )
   //   for( ProcessListIterator i = getProcessList().begin(); i != getProcessList().end(); i++ )
   //      if( (*i)->isProcessingTicks() )
   //         (*i)->interpolateTick( 0.f );

...
Removing the above code and recompiling causes the demo provided by Benjamin to behave without any jitter at all no matter what I do to it.

I am acutely aware though that given other extremes of FPS with/without vsync, "smTickShift" being change etc that you may encounter other related problems so I'll state this as a tentative fix. Also, in the demo provided by Benjamin you'll notice that the camera mount is via a force. Nothing wrong with this but I will state that this is a fairly complex scenario which I worked hard to get right when I implemented all the tick-based physics. Making this a rigid mount can remove jitter in a camera mounted scenario in some cases. Not a fix, just an observation.

One interesting thing you can always try is to disable tick-physics. You can easily do this by adding the following to you preferences (or using the console):
$pref::T2D::disableSceneTick = true;
Unfortunately, a check for this one didn't get added to the t2dSceneWindow so you should add the following code:
void t2dSceneWindow::interpolateTick( F32 timeDelta )
{
    // Disable Scene Tick.
    if ( Con::getBoolVariable( "$pref::T2D::disableSceneTick" ) ) return;
...


With regards to the "smTickShift" variable, I would say that having as high an update-rate as possible is recommended but as with anything, it's a compromise. The only thing which will really benefit would be the rigid-body physics, complex custom movement (based upon a simple euler forward transform or similar) and potentially the particles (as mentioned above). You can obviously really hurt performance on lower-end systems but you're all big boys and can choose how to balance that one yourself. :) The rules is, if in doubt then leave well alone.

So as a final note I'd say that I'm going to work on this some more this evening to see if I can cause any form of jitter. At the moment though, I'm now not seeing any issues with Benjamins demo. I'm going to put together one of my own apps to stress it though.

Please be aware that GG are treating this problem seriously. You can tell its status is elevated because I've just asked my wife if she minds me working on a T2D problem on Saturday night. Makes me sounds like a trooper but in fact I'll have a big-ass bottle of Whisky next to me so it'll be a pleasure. ;)

Melv.
#57
02/16/2008 (9:27 am)
Just had a chat with GG and I'll be changing the implicit zero time-delta in the TGB head as well as the other TGE codebases etc. I'll implement an explicit "preTick" callback mechanism so as to remove any ambiguity in the process.

Melv.
#58
02/16/2008 (9:45 am)
Melv, good to see you on the case :)

To show you the jittering that I'm seeing, here's a slightly modified version of Benjamin's example (download link). For simplicity, it's just the game folder, althought the only changed files are game.cs and an added sprite.

Basically, all I did was add a square that bounces up and down the screen.

Thanks!
#59
02/16/2008 (10:02 am)
Downloading now Ken.

As I say, I'll be looking at this stuff in more detail in about two hours or so.

Melv.
#60
02/16/2008 (10:22 am)
Ken,

Just to let you know that without the changes outlined above I get jitter (in your demo) and with the changes it completely disappears.

I'll be more thorough later though.

Melv.