OpenGL Setting FPS

I’m trying to load the changing colors of a model in a .txt file. So this file could contain 100 values and I want to be able to have a integer passed in the .txt to set the FPS that these values will be rendered.
Is this possible? I read mixed things on the topic of Fixed FPS and wanted the advice of the community since I don’t know the credibility of the sources I read.

Thanks

Use "float curGameTime; " instead of “int curFrame;” .

On consoles (fixed hardware capabilities and power), you can use the “int curFrame” approach if you’re certain there won’t be frame-drops, and you target only a specific refresh-rate.
On a PC, some users will have highest-end gaming rigs, others will be using last decade’s laptops; some will have force-disabled vsync in the driver panels; and anyway some users run in 60Hz refresh-rate, others at 75Hz, others at 100Hz, etc.

Your text-file:


// time  R G B
0.0 :  0.4,0.4,0.4
5.7 :  1.0,0.3,0.4
14.3 :  1.0,0.3,0.4
...

Your frame-update code:


float g_CurGameTime;

vec3 Color;

void updateScene(float frameDuration){
	foreach(ScriptEntry e){ // optimize this...
		if(g_CurGameTime>=e->time && e->time<(g_CurGameTime+frameDuration)){
			Color = e->color;
		}
	}
	...
	g_CurGameTime+=frameDuration;
}

It could be better or useful to interpolate entries via linear or spline-interpolation. There are articles/tutes on it, keywords are: animation, script, spline, lerp, interpolation, timing, events.

Thanks for the quick response.

One clarifying question, do I call this function in the display function I use as a GLUT callback? Because if so, wouldn’t this only change the variable for the period of time specified rather than setting the actually FPS?

I might be missing something tho…

Yes, inside the display-function, call this updateScene(). You’ll have to measure how much time the previous frame took, and supply it as the “frameDuration” parameter.

Do not think in terms of “FPS” (frames per second), think in terms of “time passed”. For some frames, your code might take 3ms , for others you might take 44ms.

Illian,

I was hoping to control the actual render rate of OpenGL. To “throttle down” the rendering, if you will.

Is this possible?

wglSwapIntervalEXT(0) - no frame-limit
wglSwapIntervalEXT(1) - vsync (i.e 60Hz, depends on current monitor mode)
wglSwapIntervalEXT(2) - vsync/2 (if vsync is at 60Hz, you’ll update at 30Hz)
wglSwapIntervalEXT(3) - vsync/3 (if vsync is at 60Hz, you’ll update at 20Hz)
etc…

Anything else: OS-dependent timers: Sleep, polling-loops, events, etc etc. Generally anything but polling-loops will be imprecise.

I call that… when? Prior to rendering anything? Any 30Hz doesn’t correlate to 30FPS, right? Is there a way to tell what the Hz cooresponds to.

Thanks!

You call wglSwapIntervalEXT only once. There are specs about it on this site.
http://en.wikipedia.org/wiki/Hertz

Since you are using GLUT, you can use glutGet(GLUT_ELAPSED_TIME) to measure time in a cross-platform way. One thing to be aware of when using any timer function, they are not guaranteed precise beyond 10-100 millisecond. You can get around that by averaging multiple frames over a second (10xprecision of timer).

If you just want to control the speed of the display loop you can simply put a blocking condition in the display loop. I have attached a piece of minimal code that measures FPS with averaging and a blocking condition in the display loop to throttle the speed of the display (to turn on the throttling loop change in the idle() function “#undef REGULATE_FPS” to “#define REGULATE_FPS”). When REGULATE_FPS is undef’ed then rendering loop will go as fast as hardware allows and FPS will be >>60 (assuming vsync off on my machine I measure FPS ~8000) and when REGULATE_FPS is define’ed then the FPS will be fixed to 1 frame per 35milliseconds = ~29FPS which FPS() will measure. Note that it takes approximately 1 second after startup for the FPS() to accurately begin displaying the measured frames per second in the printf call.

ps for advanced users: if you want to go non-cross platform to avoid having an imprecise clock measure, please try to avoid QueryPerformanceCounter in windows since the Performance counter value may unexpectedly leap forward. One approach I have found is to use the CPU RDSTC assembly op-code on Intel/AMD processors – see the wiki at Time Stamp Counter and for working code find cycle.h at the bottom. I like RDTSC opcode since it works in linux as well as windows. But note, in my applications I have been perfectly happy to live with averaging over multiple frames to deal with the imprecise clock functions. end of comment for advanced users.


//this shows one way to get FPS using an inprecise clock
//or to throttle the drawing rate to a fixed FPS
//g++ glut_fps_demo.cpp -lGL -lglut
#include <cstdlib>
#include <iostream>

//linux openGL headers
#include <GL/gl.h>
#include <GL/glut.h>

GLint gFramesPerSecond = 0;

void FPS(void) {
  static GLint Frames = 0;         // frames averaged over 1000mS
  static GLuint Clock;             // [milliSeconds]
  static GLuint PreviousClock = 0; // [milliSeconds]
  static GLuint NextClock = 0;     // [milliSeconds]

  ++Frames;
  Clock = glutGet(GLUT_ELAPSED_TIME); //has limited resolution, so average over 1000mS
  if ( Clock < NextClock ) return;

  gFramesPerSecond = Frames/1; // store the averaged number of frames per second

  PreviousClock = Clock;
  NextClock = Clock+1000; // 1000mS=1S in the future
  Frames=0;
}

void idle() {
  #define REGULATE_FPS
  #ifdef REGULATE_FPS
  static GLuint PreviousClock=glutGet(GLUT_ELAPSED_TIME);
  static GLuint Clock=glutGet(GLUT_ELAPSED_TIME);
  static GLfloat deltaT;

  Clock = glutGet(GLUT_ELAPSED_TIME);
  deltaT=Clock-PreviousClock;
  if (deltaT < 35) {return;} else {PreviousClock=Clock;}
  #endif

  //put your specific idle code here
  //... this code will run at FPS
  printf(".");
  //end your specific idle code here

  FPS(); //only call once per frame loop 
  glutPostRedisplay();
}

void display() {
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT);

  // Set the drawing color (RGB: WHITE)
  printf("FPS %d
",gFramesPerSecond);
  glColor3f(1.0,1.0,1.0);

  glBegin(GL_LINE_STRIP); {
     glVertex3f(0.25,0.25,0.0);
     glVertex3f(0.75,0.25,0.0);
     glVertex3f(0.75,0.75,0.0);
     glVertex3f(0.25,0.75,0.0);
     glVertex3f(0.25,0.25,0.0);
  }
  glEnd(); 

  glutSwapBuffers();
}

void init() {
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0.0,1.0,0.0,1.0,-1.0,1.0); 
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:  // escape key
         exit(0);
         break;
      default:
         break;
   }
}

int main(int argc, char** argv) {
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
   glutCreateWindow("FPS test");

   glutIdleFunc(idle);
   glutDisplayFunc(display);
   glutKeyboardFunc(keyboard);

   init();

   glutMainLoop();
   return 0;
}

Thanks for the posts! Very helpful, I’ll probably go with the non-vsync changing route.

for those interested, an alternative to the code in post #261479 above is listed here based on glutTimerFunc() rather than a blocking condition in idle().


//this shows a second way to get FPS using an imprecise clock
//while throttling the drawing rate to a fixed FPS with glutTimerFunc
//g++ glut_fps_demo.cpp -lGL -lglut
#include <cstdlib>
#include <iostream>

//linux openGL headers
#include <GL/gl.h>
#include <GL/glut.h>

GLint gFramesPerSecond = 0;

void FPS(void) {
  static GLint Frames = 0;         // frames averaged over 1000mS
  static GLuint Clock;             // [milliSeconds]
  static GLuint PreviousClock = 0; // [milliSeconds]
  static GLuint NextClock = 0;     // [milliSeconds]

  ++Frames;
  Clock = glutGet(GLUT_ELAPSED_TIME); //has limited resolution, so average over 1000mS
  if ( Clock < NextClock ) return;

  gFramesPerSecond = Frames/1; // store the averaged number of frames per second

  PreviousClock = Clock;
  NextClock = Clock+1000; // 1000mS=1S in the future
  Frames=0;
}

void timer(int value)
{
  const int desiredFPS=120;
  glutTimerFunc(1000/desiredFPS, timer, ++value);

  //put your specific idle code here
  //... this code will run at desiredFPS
  char spinner[] = {'|','/','-','~','\\'};
  printf("%c",spinner[value%sizeof(spinner)/sizeof(char)]);
  //end your specific idle code here

  FPS(); //only call once per frame loop to measure FPS 
  glutPostRedisplay();
}

void display() {
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT);

  // Set the drawing color (RGB: WHITE)
  printf("FPS %d\r",gFramesPerSecond); fflush(stdout);

  glColor3f(1.0,1.0,1.0);

  glBegin(GL_LINE_STRIP); {
     glVertex3f(0.25,0.25,0.0);
     glVertex3f(0.75,0.25,0.0);
     glVertex3f(0.75,0.75,0.0);
     glVertex3f(0.25,0.75,0.0);
     glVertex3f(0.25,0.25,0.0);
  }
  glEnd(); 

  glutSwapBuffers();
}

void init() {
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0.0,1.0,0.0,1.0,-1.0,1.0); 
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:  // escape key
         exit(0);
         break;
      default:
         break;
   }
}

int main(int argc, char** argv) {
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
   glutCreateWindow("FPS test");

   glutTimerFunc(0,timer,0);
   glutDisplayFunc(display);
   glutKeyboardFunc(keyboard);

   init();

   glutMainLoop();
   return 0;
}


Hello, it is very impressive. Congratulations. But I have a problem, when I use glTranslatef*() or glRotatef*() I have a poor smooth movement. What happens?

It seems as if it made small jumps. :frowning:

There is some way to have a smooth movement independent of fps?

for your help, thank you very much.

Assuming you are calling glTranslate/glRotate from within the display() function, you have to scale your inputs to the time between frames ie dt = 1/gFramesPerSecond to make the code FPS independent.

For instance, if you want a full rotation of 360 degrees every 8 seconds then you would do something like


GLfloat dt = (gFramesPerSecond>0 ? 1.0/gFramesPerSecond : 1.0);
static GLfloat angle=0.0;
angle += 360./8.*dt
glRotatef(angle,...);

Here’s a follow up on the previous post… working bare code for animation using glutTimerFunc and regulating the FPS to a set value “desiredFPS”.


//this shows a second way to get FPS using an imprecise clock
//while throttling the drawing rate to a fixed FPS with glutTimerFunc
//g++ glut_fps_demo.cpp -lGL -lglut
#include <cstdlib>
#include <iostream>

//linux openGL headers
#include <GL/gl.h>
#include <GL/glut.h>

GLint gFramesPerSecond = 0;
GLfloat gAngle = 0.0;

void FPS(void) {
  static GLint Frames = 0;         // frames averaged over 1000mS
  static GLuint Clock;             // [milliSeconds]
  static GLuint NextClock = 0;     // [milliSeconds]

  ++Frames;
  Clock = glutGet(GLUT_ELAPSED_TIME); //has limited resolution, so average over 1000mS
  if ( Clock < NextClock ) return;

  gFramesPerSecond = Frames/1; // store the averaged number of frames per second

  NextClock = Clock+1000; // 1000mS=1S in the future
  Frames=0;
}

void timer(int value)
{
  const int desiredFPS=120;
  glutTimerFunc(1000/desiredFPS, timer, ++value);
    GLfloat dt = (gFramesPerSecond>0 ? 1.0/gFramesPerSecond : 1.0);

  //put your specific idle code here
  //... this code will run at desiredFPS
    gAngle += dt*360./8.; //rotate 360 degrees every 8 seconds
  //end your specific idle code here

  FPS(); //only call once per frame loop to measure FPS
  glutPostRedisplay(); // initiate display() call at desiredFPS rate
}

void display() {
  // Will be called at FPS rate, ok to use global values now to rener scene
  glClear(GL_COLOR_BUFFER_BIT);

  //quick and dirty way to display FPS value
  printf("FPS %d\r",gFramesPerSecond); fflush(stdout);

  glColor3f(1.0,1.0,1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glRotatef(gAngle,0.,0.,1.);
    glScalef(0.25,0.25,0.25);

  glBegin(GL_LINE_STRIP); {
     glVertex3f(-1.0, -1.0, 0.0);
     glVertex3f( 1.0, -1.0, 0.0);
     glVertex3f( 1.0,  1.0, 0.0);
     glVertex3f(-1.0,  1.0, 0.0);
     glVertex3f(-1.0, -1.0, 0.0);
  }
  glEnd();

  glutSwapBuffers();
}

void init() {
  glClearColor(0.0, 0.0, 0.0, 0.0);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:  // escape key
         exit(0);
         break;
      default:
         break;
   }
}

int main(int argc, char** argv) {
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE);
   glutCreateWindow("FPS test /w glutTimerFunc");

   glutTimerFunc(0,timer,0);
   glutDisplayFunc(display);
   glutKeyboardFunc(keyboard);

   init();

   glutMainLoop();
   return 0;
}