我正在VS上玩C ++,使用OpenGL渲染/移动形状,使用Win32进行窗口显示等(从过剩显示移出)
如何控制帧频?
[我看到了很多使用dt
的示例和某种形式的帧刷新,但是我不确定如何实现这一点...是否可以将某些东西用作Win32的一部分,或者可以通过更简单的方法来完成?
也可能是一个愚蠢的问题,但是,如果未执行任何操作,则默认帧速率是多少?还是没有?
我的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(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutCreateWindow("FPS test");
glutIdleFunc(idle);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
init();
glutMainLoop();
return 0;
}
希望这会有所帮助:)如果您需要更多信息,请告诉我。
[如果您不打算构建多用户系统,则不需要固定帧速率(您可以使用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
要回答您的问题:帧速率取决于图形卡的性能。
dt表示delta time,它是自上一帧或更新以来的时间。根据您要实现的目标,您可以在两个帧之间测量dt并使用此更新对象的位置。
您可以通过时间测量来控制帧率:如果要强制30FPS,并且知道rt是渲染帧所需的时间,则可以在零时间渲染一帧,然后在时间1/30-rt渲染一帧,依此类推。] >
在概念上更清洁的模型中,您将渲染与数据模型的更新分开,这样您就可以使用修补程序dt
(如1/30秒来更新位置等)。在此模型中,渲染会经常运行尽可能多地存储最后两个位置。然后,渲染框架函数可以使用0-1之间的interpolation参数对位置进行插值。使用此模型,您将获得几个优点:使用time_t或clock_t通常会给出0 delta,而不是使用精确的Windows profile.h API