Smooth Animations

Started by
18 comments, last by flery 14 years ago
This is my game loop and I get perfectly smooth animations in window mode, fullscreen, v-sync on and off.

// TICKS_PER_SEC is the update rate, I have it set at 25Hzvoid run(void){	const int64_t timestep = tickfreq()/TICKS_PER_SEC; // TODO: calc once	static int64_t next_tick = 0;	int count = 0;	float a;	if (!next_tick) next_tick = tickcount();	while (tickcount() >= next_tick && count < MAX_FRAMESKIP) {		update();		next_tick += timestep;		++count;	}	a = (tickcount()+timestep-next_tick)/(double)timestep;	draw(a); // I use a to interpolate between previous and current state		glfwSwapBuffers(); // Window messages gets pumped here by glfw}


Here is the main loop:
	start = tickcount();	invfreq = 1/(double)tickfreq();	done = 0;	while (!done) {		done = !glfwGetWindowParam(GLFW_OPENED);		if (glfwGetKey(GLFW_KEY_ESC)) done = 1;		run();		if (framelimit > 0) {			while ((tickcount()-start)*invfreq < 1/((float)framelimit*1.2f)) Sleep(1);			while ((tickcount()-start)*invfreq < 1/(float)framelimit) ;		}		{			char str[128];			double fps = 1/((tickcount()-start)*invfreq);			sprintf(str, "fps: %.2Lf", fps);			glfwSetWindowTitle(str);		}		start = tickcount();	}

I try to check if v-sync is on, if it is I set framelimit to 0, otherwise I set it to 60 (or let the user set the limit).
Advertisement
I've noticed that in my tests, regardless of the time-stepping scheme, the movement of translating polygons can appear to be un-smooth because of aliasing; especially at slower speeds, there are e.g sudden jumps as columns of pixels turn on/off when a square is translating horizontally.

IMO some sort of spatial and/or temporal anti-aliasing is needed if you want super-smooth movement of 2D polygons.

For spatial AA, you could try using GL_SMOOTH drawing, or FSAA/MSAA/CSAA/etc.

For temporal AA, AFAIK there is no "best" method for this, most people seem to either take a multisample approach (render the scene at multiple times between the previous and current state, using additive blending to accumulate) or a geometry-based approach (create fin/trail geometry based on velocity). The former approach breaks down under large movement (you can see the samples spaced out individually) and the latter is tricky to get working with arbitrary movements (i.e objects that are spinning as they translate). I know some 3D games use post-processing to achieve motion blur, the same approach should be applicable to 2D.. right?
i compared the fps rates between ogl and dx10 (forcing on vsync with driver settings for opengl and using presentation interval for dx)
left = current fps, right = average framerate

Open GL:
 [  1] FPS: 180.49 60.0014 [  1] FPS: 49.9521 60 [  1] FPS: 49.9453 60.0016 [  1] FPS: 50.0262 60 [  1] FPS: 50.0125 60.0009 [  1] FPS: 68.9501 59.9518 [  1] FPS: 182.647 60.0087 [  1] FPS: 49.9819 60.0031 [  1] FPS: 49.9827 60.0371 [  1] FPS: 49.9964 60.0022 [  1] FPS: 50.0501 60.0021 [  1] FPS: 68.5235 59.9519 [  1] FPS: 184.542 60.0013 [  1] FPS: 50.0373 60.0028 [  1] FPS: 49.8867 59.9981 [  1] FPS: 50.0339 60.0006 [  1] FPS: 49.7818 59.9869 [  1] FPS: 68.5379 59.9526


DX10:
 [  1] FPS: 62.4125 59.9392 [  1] FPS: 58.9586 59.9273 [  1] FPS: 61.1321 59.9424 [  1] FPS: 59.8128 59.9511 [  1] FPS: 58.5937 59.9124 [  1] FPS: 61.2086 59.9301 [  1] FPS: 59.316 59.9293 [  1] FPS: 59.6863 59.9094 [  1] FPS: 61.215 59.9425 [  1] FPS: 58.8876 59.9327 [  1] FPS: 60.4721 59.9283 [  1] FPS: 59.7629 59.9638 [  1] FPS: 60.3515 59.9465 [  1] FPS: 59.1618 59.9042 [  1] FPS: 60.4933 59.943 [  1] FPS: 60.2376 59.9611 [  1] FPS: 59.5459 59.9379 [  1] FPS: 60.2561 59.9274 [  1] FPS: 60.0822 59.9298 [  1] FPS: 59.4795 59.9531 [  1] FPS: 60.7249 60.0393 [  1] FPS: 58.9693 60.02


As you could expect the animation looks much smoother in directx than it does with opengl. Is that a driver issue? Should I try to handle frame limitation by myself? I thought the driver would know best when the monitor is expecting the next frame.

its really weird its exactly every 6th frame that spikes.

[Edited by - flery on April 3, 2010 8:49:46 AM]
after some profiling i found out that SwapBuffers(HDC) performs in very uneven ways. this is the reason for the varying frame rates. i have yet to find a way to fix that.
Quote:Original post by flery

its really weird its exactly every 6th frame that spikes.


A frame is rendered every 20ms (50fps) when it should be rendered every 16.6ms (60fps). Then, every 6 frames it catches up (5ms/180fps) to maintain 60fps average.

What happens if you comment out the actual drawing so that it just draws empty screen? Excluding a bug in driver it leaves the incorrect or too heavy usage of OGL which causes the spikes.

Assuming that the timing measured is correct.

The only thing where 50Hz vs. 60Hz comes to mind would be NTSC vs. PAL, but I don't see how this could matter here.
i only timed the swap buffer command and it is the root of the problem. drawing an empty scene (or no scene at all, just swap buffers) has the same effect. managing the frame rate by myself seems to solve this problem. if someone has a nicer solution please tell.
Could you explain what you mean by "managing the frame rate by myself"? Do you just mean no-vsync? Sorry if this is obvious.. it's not clear to me how you would ever NOT be managing the frame rate yourself!
Yes, i ment no v-sync. Turning on V-Sync leads to the driver managing the frame rate with blocking. Disabling vsync and using a max fps value is not the exact same behaviour i would asume, but at least i get decent animations.

with a bit more profiling i saw weird behaviour using wglSwap instead of SwapBuffers... i'll post a graph later. Anyone else experiencing that?
Try changing:

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

to:

while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
in regards to what? what change should that result in?
here is the data i collected timing different swap buffer calls

This topic is closed to new replies.

Advertisement