Fixed Frame Rate Timer: FPS Independent Movement

Hi all,
i’m currently working on a project that requires to fix the frame rate to a certain value. The fixed frame rates are only needed for 10-20 consecutive frames.
The reason why i fix the frame rates is that the application (an experiment) needs to act in a precise way. For instance: call update(float tpf) ever 17ms for the next 4 frames.
After the sequence of fixed frames rates it is switched back to be variable.
The only save way to accomplish this behaviour (i know) is through a custom timer that fixes the frame rate at a certain condition and switches back to a variable mode if the sequence is finished.

Yes fixed rates can cause problems, but we talk of a range of about 30 - 80 fps and if the machine cannot produce these values the experiment doesn’t work anyway.

The timer is implemented and produces rates that are very promising. This whole thing runs in a driving simulation and as i made my first test runs i noticed, that during the sequence of fixed rates the simulation runs way faster than during the variable ones. First i thought that the movement calculation is wrong, but i was able to reproduce the same behaviour in a very simple test project based on the jmonkey tutorials.

The faster/slower movement occurs if the frame rate limit set by settings.setFrameRate(fps) is a certain amount higher or lower than the fixed frame rate. It behaves normal if they are the same. Is this a bug or am i mistaken with the implementation?

I have a test implementation main class but i’m not sure if it is a problemen posting it here (170 lines)!?

That’s the timer i set in the application.

[java]
import com.jme3.system.Timer;

/**

  • A dynamic priming timer that is able to produce fixed and variable frame
  • rates.
  • Based on the NanoTimer by Matthew D. Hicks
  • @author Hannes Thaller

*/
public class PrimingTimer extends Timer {

private static final float INVERSE_RESOLUTION;
private static final long RESOLUTION = 1000000000L;

private float fps;
private boolean isFixed;
private long previousTime;
private long startTime;
private long time;
private float tpf;

static {
	INVERSE_RESOLUTION = 1f / RESOLUTION;
}

/**
 * Constructs a new priming timer that runs in a variable frame rate mode.
 */
public PrimingTimer() {
	startTime = System.nanoTime();
}

@Override
public float getFrameRate() {
	return fps;
}

@Override
public long getResolution() {
	return RESOLUTION;
}

@Override
public long getTime() {
	return System.nanoTime() - startTime;
}

@Override
public float getTimePerFrame() {
	return tpf;
}

/**
 * Returns whether the timer runs with a fixed frame rate.
 * 
 * @return If the timer is fixed or not.
 */
public boolean isFixed() {
	return isFixed;
}

@Override
public void reset() {
	startTime = System.nanoTime();
	previousTime = getTime();
}

/**
 * Switches the timer between fixed and variable mode. If the timer is
 * switched from variable to fixed mode the last fps of the variable will be
 * fixed.
 * 
 * @param isFixed
 *            whether the timer should be in fixed mode or not
 */
public void setFixed(boolean isFixed) {
	this.isFixed = isFixed;
}

/**
 * Sets the timer to a specific frame rate (fixed mode).
 * 
 * @param fps
 *            the timer should be set to
 */
public void setFrameRate(float fps) {
	if (fps > 0) {
		this.fps = fps;
		this.tpf = 1.0f / fps;
		isFixed = true;
	}
}

@Override
public void update() {
	time = getTime();

	if (!isFixed) {
		tpf = (time - previousTime) * INVERSE_RESOLUTION;
		fps = 1.0f / tpf;
	}
	previousTime = time;
}

}
[/java]

Thanks for the help.

You should multiply the movements you make with the tpf you get in the update loop, for example:
[java]
box.move(0.5f * tpf, 0.2f * tpf, 1.0f * tpf);
[/java]

That way the move will not be FPS dependant…

I guess you didn’t do that, but if you did and really want to limit the fps for a specific amount of time, you could maybe take a look at Display#sync, and how it’s used in here https://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/lwjgl/com/jme3/system/lwjgl/LwjglAbstractDisplay.java

1 Like

Thanks reveance, but that’s not the problem.
As i said, if i adjust the frame rate limit with
[java]
settings.setFrameRate(fps);
restart()
[/java]

the box rotates correctly, either on fixed 300 fps or an 20 fps it doesn’t matter. But restarting the context in the running simulation is not good.

This is the update method. Forgotten to post it. It rotates a box around the y-axis.
I will have a look at the display sync and report if it helped.

[java]
@Override
public void simpleUpdate(float tpf) {

	// Compute movement
	movement = MOVEMENT_STEP * tpf;

	// Move object
	box.rotate(0, movement, 0);

	// Periodically update hud
	counter += tpf;
	updateHud(tpf);
}

[/java]

The video recording app state temporarily locks the timer to 30 FPS (regardless of how long the frames take to render) by using a custom timer. You might look and see how this was done if you haven’t already.

Hello pspeed,
do you mean the IsoTimer from Robert McIntyre Capture Live Video Feeds?
I’ll get the same results.

The strange thing is if i lock the limit to 30 fps i get the desired tpf of 33.3ms with a normal rotation speed.
On the other side if i lock the limit for an instance to 300fps, and fix the frame rate again to 30fps, i also get a tpf of 33.3ms but the cube is rotating like a drunken dog chasing its tail.

I’ve uploaded the small eclipse project to a repo. The wiki contains the four steps to reproduce the behaviour.
https://bitbucket.org/hthaller/fixedframeratetimer

It would help if someone could point me to the piece of code that limits the frame rate to the value set in the settings. I thought it should be somewhere in the base class (update) but i couldn’t find it.

Thanks for your help

Have you had a look at the Video Recorder App State source ?

Probably a silly question… but isn’t the idea counter-productive to what you are trying to accomplish?

You say you need to app to be precise, however… precise is going to greatly fluctuate based on the machine it is running, unless you are pushing the entire logical portion of the update loop to a separate thread, keeping it completely independent from the update loop of the application (which includes a render pass after update… which varies based on each machine config).

Everyone has mentioned taking a look at the Video Recorder App State… I suggest running it and see if this is the kind of precise you were talking about :wink:

So hello again

@tonegod: Precise up to 1ms. Which should be valid because of the indirect “prerequest” of lwjgl lwjgl Timing Tutorial.
Therefore syncing the entire application, Lwjgl and the build on engine, on the frame rate should be the closest way to get “precise”.

I’ve solved the problem:
After looking at the Video Recorder App i figured out that my application has to be correct because they internal mechanics are just the same. Now that i knew that the problem must lie beyond i got back to reveance post and the Abstract display.

The problem is this pieces of code in the the LwjglAbstractDisplay.

[java]
if (frameRate > 0)
Display.sync(frameRate);
[/java]

Since in most applications the frame rate is variable it doesn’t sync up with lwjgl - just be as fast as possible.
The other case would be if the frame rate is limited with the settings, than it syncs with the maximum.

Because my applications changes the fixed frame rate over runtime lwjgl and the engine where out of sync causing fast or slower movements.

To overcome this problem i reluctantly had to change the code within the engine to a more sophisticated syncing.

[java]
// Update current application timer and sync lwjgl with it, if it has a valid
// value. Choosing maxFrameRate smaller than the fixed frame rate will
// cause lwjgl to be out of sync with the application.
systemTimer = listener.getSystemTimer();

    if (systemTimer != null && systemTimer.isFixed()) {

        frameRate = (int) systemTimer.getFrameRate();

        if (frameRate > 0 && frameRate <= maxFrameRate) {
            Display.sync(frameRate);
        }
    }

[/java]

In order to get the desired timing information i changed the SystemListener interface to return the system’s timer.
To keep it as simple as possible i also extended the timer interface by a isFixed method.

Now if the timer is fixed it will sync on the fixed value, if not it won’t sync at all.

Thanks for all your help and suggestions.

I suggest simply not making your application framerate dependent. Thats as simple as multiplying movement vectors with tpf. Fixed rate games basically died out when the Amiga and C64 stopped being the favorite home computers and even then framerate dependent games were rare.

<cite>@normen said:</cite> I suggest simply not making your application framerate dependent. Thats as simple as multiplying movement vectors with tpf. Fixed rate games basically died out when the Amiga and C64 stopped being the favorite home computers and even then framerate dependent games were rare.

Except starwars battlefornt in multiplayer wich was fixed to 30fps and i hated it for that :slight_smile:

<cite>@normen said:</cite> I suggest simply not making your application framerate dependent. Thats as simple as multiplying movement vectors with tpf. Fixed rate games basically died out when the Amiga and C64 stopped being the favorite home computers and even then framerate dependent games were rare.

This is kinda what I was hinting at (in a round about way). I think there are other approaches you could consider that will not effect the render portion of your game and still be as accurate as you require.