我在VS上玩C ++,使用OpenGL进行渲染/移动形状,使用Win32进行窗口显示等(从过剩显示中移出)
如何控制帧率?
我看到很多使用dt
和某种形式的帧刷新的例子,但是我不确定如何实现这个...有什么我可以用作Win32的一部分或者可以做到更简单的方法?
此外,可能是一个愚蠢的问题但是,如果没有实现,默认帧速率是多少?或者没有?
答案 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(&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之间的插值参数来插值位置。使用此模型可以获得以下几个优势:
答案 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;
}