控制帧速率

时间:2013-11-26 12:59:37

标签: c++ winapi opengl glut frame-rate

我在VS上玩C ++,使用OpenGL进行渲染/移动形状,使用Win32进行窗口显示等(从过剩显示中移出)

如何控制帧率?

我看到很多使用dt和某种形式的帧刷新的例子,但是我不确定如何实现这个...有什么我可以用作Win32的一部分或者可以做到更简单的方法?

此外,可能是一个愚蠢的问题但是,如果没有实现,默认帧速率是多少?或者没有?

4 个答案:

答案 0 :(得分:3)

我的USB驱动器上有一些非常古老的代码,它使用旧的OpenGL和过剩,即使在更现代的版本中也适用相同的时序原则,但绘制代码会有所不同。代码用于不精确的时序,但是为了说明如何粗略地实现一组FPS就足够了:

// throttle the drawing rate to a fixed FPS
//compile with: g++ yourfilenamehere.cpp -lGL -lglut
#include <cstdlib>
#include <iostream>

#include <GL/gl.h>
#include <GL/glut.h>

GLint FPS = 0;

void FPS(void) {
  static GLint frameCounter = 0;         // frames averaged over 1000mS
  static GLuint currentClock;             // [milliSeconds]
  static GLuint previousClock = 0; // [milliSeconds]
  static GLuint nextClock = 0;     // [milliSeconds]

  ++frameCounter;
  currentClock = glutGet(GLUT_ELAPSED_TIME); //has limited resolution, so average over 1000mS
  if ( currentClock < nextClock ) return;

  FPS = frameCounter/1; // store the averaged number of frames per second

  previousClock = currentClock;
  nextClock = currentClock+1000; // set the next clock to aim for as 1 second in the future (1000 ms)
  frameCounter=0;
}

void idle() {
  static GLuint previousClock=glutGet(GLUT_ELAPSED_TIME);
  static GLuint currentClock=glutGet(GLUT_ELAPSED_TIME);
  static GLfloat deltaT;

  currentClock = glutGet(GLUT_ELAPSED_TIME);
  deltaT=currentClock-previousClock;
  if (deltaT < 35) {return;} else {previousClock=currentClock;}

  // put your idle code here, and it will run at the designated fps (or as close as the machine can get

  printf(".");
  //end your 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\n",FPS);
  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(&amp;argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
   glutCreateWindow("FPS test");

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

   init();

   glutMainLoop();
   return 0;
}

希望这有点帮助:)如果您需要更多信息,请告诉我。

答案 1 :(得分:2)

如果您不打算构建多用户系统,则无需修复帧速率(您可以使用QueryPerformanceCounter测量最后一帧花费的时间,并假设下一个帧花费的时间大约相同) 。然后你只根据帧时间移动对象。

如果在此模型中应用力/加速度,则可能需要进行补偿,例如使用velocity Verlet integration

然而,修复帧速率可能会有点混乱,特别是如果每​​帧的CPU / GPU负载变化很大。

固定帧率的简单版本:

如果您刚刚在机器上平稳移动并想要固定帧率,请实现此伪代码:

fps = 30    # Pick something good for you, 30 and 60 are common values.
main_loop:
    t0 = time()
    update_and_render(1/fps)
    t1 = time()
    frame_time = t1-t0
    sleep(1/fps - frame_time)
    goto main_loop
此示例中的

frame_time是您的示例所指的dt(“增量时间”),但大多数示例都没有固定的帧速率。相反,他们根据最后一帧花了多长时间移动你的精灵。

对于不同的帧速率相同:

last_frame_rate = 1/100
main_loop:
    t0 = time()
    update_and_render(last_frame_rate)
    t1 = time()
    last_frame_rate = t1-t0
    goto main_loop

答案 2 :(得分:1)

回答你的问题:帧率取决于显卡的性能。

dt 表示 delta time ,即自上次帧或更新以来的时间。根据您想要实现的目标,您可以在两个帧之间测量 dt ,并使用此更新对象的位置。

您可以按时间控制来控制帧速率: 如果你想强制30FPS并且你知道 rt 它渲染帧所需的时间然后你可以在零时刻渲染帧,然后在1/30 - rt时刻渲染一帧上。

在概念清理模型中,您可以将渲染与数据模型的更新分开,这样您就可以使用1/30秒的修复 dt 来更新您的位置等。在此模型中渲染尽可能经常运行,因此您存储最后两个位置。然后,渲染帧函数可以使用0-1之间的插值参数来插值位置。使用此模型可以获得以下几个优势:

  • 您可以在不渲染的情况下进行模拟
  • 您可以获得数据的确定性模拟,因为您的 dt 已修复
  • dt 可用于轻松实现渲染的慢动作或双快播放。

答案 3 :(得分:0)

使用time_t或clock_t通常会给出0 delta,而不是使用精确的Windows profile.h API

#include<profil.h>

#define FRAMES_PER_SEC 60.0

void tickfbs();

LARGE_INTEGER frequency;        // used for ticks per second
LARGE_INTEGER t1, t2;           // used for storing ticks passed
double elapsedTime;

int main(void){
    QueryPerformanceFrequency(&frequency);
    for(;;){
        //do something(drawing)
        tickfbs();//wait for the delta time between each iteration and the fbs ratio
    }
    return 0;
}

//this will wait for the amount of delta time between this call of the function and the last call
void tickfbs(){
    QueryPerformanceCounter(&t2);
    elapsedTime = (t2.QuadPart - t1.QuadPart) / frequency.QuadPart * 1000;
    if(elapsedTime < FRAMES_PER_SEC){
        delay(FRAMES_PER_SEC-elapsedTime);
    }
    t1 = t2;
}