让矩形以特定频率闪烁/闪烁

时间:2014-11-18 10:30:08

标签: c++ opengl sdl

我目前正尝试在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);
}

1 个答案:

答案 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不会在屏幕上显示更多图像,只会在后台渲染更多图像。