控制帧频

问题描述 投票:3回答:4

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

如何控制帧频?

[我看到了很多使用dt的示例和某种形式的帧刷新,但是我不确定如何实现这一点...是否可以将某些东西用作Win32的一部分,或者可以通过更简单的方法来完成?

也可能是一个愚蠢的问题,但是,如果未执行任何操作,则默认帧速率是多少?还是没有?

c++ winapi opengl glut frame-rate
4个回答
3
投票

我的USB驱动器上有一些非常旧的代码,这些代码使用了旧的OpenGL和glut,即使在更现代的版本中,计时的原理也相同,但是绘制代码会有所不同。该代码用于不精确的计时,尽管足以说明如何大致实现一组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;
}

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


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

1
投票

要回答您的问题:帧速率取决于图形卡的性能。

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

您可以通过时间测量来控制帧率:如果要强制30FPS,并且知道rt是渲染帧所需的时间,则可以在零时间渲染一帧,然后在时间1/30-rt渲染一帧,依此类推。] >

在概念上更清洁的模型中,您将渲染与数据模型的更新分开,这样您就可以使用修补程序dt

(如1/30秒来更新位置等)。在此模型中,渲染会经常运行尽可能多地存储最后两个位置。然后,渲染框架函数可以使用0-1之间的interpolation参数对位置进行插值。使用此模型,您将获得几个优点:
  • 您可以模拟而无需渲染
  • 因为您的dt
  • 已修复,所以您对数据进行了确定性模拟
  • dt
  • 可用于轻松实现渲染的慢动作或双倍快回放。

0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.