我目前正尝试在Windows上使用OpenGL,SDL2和GLEW让特定频率的矩形闪烁。我面临的问题让我变得疯狂,因为我无法弄明白,我做错了什么 - 我还是一个OpenGL菜鸟。
我遇到的问题是,在某些频率上(所有频率明显低于屏幕刷新率),矩形闪烁开始st"绊倒"导致多个帧的重复静止图像,或者是空白屏幕或矩形可见。 简而言之,我不能在更长的时间内以恒定频率获得周期性闪烁。随着频率的增加,这个问题非常明显。
我尝试过的是启用/禁用VSync,使用SDL手动限制FPS,使用不同的计时器实现。我还测量了FPS - 当限制时我达到恒定的60 FPS偶尔+ -1抖动,无限FPS我得到> 3000 FPS。我不确定这个问题的原因是否真的是时间问题,或者我是否在OpenGL中做错了什么。
我的精简代码如下(我删除了错误检查,但没有错误)。我还尝试更改变量时做了一些注释。
我初始化系统的方法如下:
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
_window = SDL_CreateWindow(...);
SDL_GLContext glContext = SDL_GL_CreateContext(_window);
GLenum error = glewInit();
SDL_GL_SetSwapInterval(1); //For vsync
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
_rect.init(-0.5,-0.5, 1.0f, 1.0f);
我的游戏循环看起来像这样:
while (1)
{
logic(); // process game logic
processInput(); // process input using sdl
drawGame(); // draw the game on screen
}
drawGame()函数测量从绘制一帧到下一帧的时间,以便我可以适当地切换矩形。
void drawGame()
{
/* some declarations and initialization calls */
double freq = 20; // frequency in hertz
double interval = 1.0/(2.0*freq)*1000.0; // half of the interval in ms,
// determines when to toggle
delta = SDL_GetTicks() - tick; // measurement of time delta
tick = SDL_GetTicks();
delta_acc += delta; // accumulate the measurements
if (delta_acc > interval)
{
act = !act;
delta_acc = 0; // I've also tried delta_acc-=interval here to account for slightly
// overdue toggling, but it didn't help
}
// Now the actual rendering
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (act) _rect.draw();
glFinish(); // Tried with and without glFinish();
SDL_GL_SwapWindow(_window);
}
_rect
对象属于精灵类,基本上看起来像这样
Sprite::Sprite(void)
{
_vboID = 0;
}
void Sprite::init(float x, float y, float width, float height)
{
_x = x;
_y = y;
_height = height;
_width = width;
if (_vboID == 0)
{
glGenBuffers(1, &_vboID);
}
float vertexData[12];
/*
... setting vertices here
*/
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Sprite::draw()
{
glBindBuffer(GL_ARRAY_BUFFER, _vboID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
答案 0 :(得分:0)
对我来说这听起来像是一个采样问题:假设屏幕刷新率为60Hz,闪烁率为20Hz。这意味着我们希望对象在1 / 40sec内可见,然后在1 / 40sec内不可见。 现在看下面的图表:
on 1/60 on 1/60 off 1/60
|---------------------|---------------------|---------------------| Screen
|--------------------------------|--------------------------------| Flicker
1/40 (on) 1/40 (off)
我们看到,万一,我们将得到2帧显示对象,只有一帧没有显示它。我的猜测是,只要频率/ 2是屏幕刷新率的倍数,您的算法就应该工作。 (例如,频率= [30,15,......])
注意:禁用vsynch不会在屏幕上显示更多图像,只会在后台渲染更多图像。