Пусть прямоугольник мигает / мерцает с определенной частотой

0

В настоящее время я пытаюсь включить мерцание прямоугольников с определенной частотой, используя OpenGL, SDL2 и GLEW в Windows. Проблемы, с которыми я сталкиваюсь, заставляют меня сходить с ума, потому что я просто не могу понять, что я делаю неправильно - я все еще OpenGL noob.

Проблема в том, что на некоторых частотах (все частоты явно ниже, чем частота обновления экранов) мерцание прямоугольника начинает "спотыкаться", вызывая повторные неподвижные изображения для нескольких кадров, либо пустой экран, либо видимый прямоугольник. В двух словах, я просто не могу периодически периодически мерцать с постоянной частотой в течение более длительных периодов времени. Проблема сильно заметна с ростом частот.

Я попытался включить/отключить VSync, вручную ограничивая FPS с помощью SDL, используя различные реализации таймера. Я также измерил 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
    Вы правы конечно. Я просто хотел сжать код, чтобы все было в одной функции, чтобы лучше видеть, что происходит.
Теги:
opengl
sdl

1 ответ

0

Для меня это звучит как проблема выборки: Предполагая частоту обновления экрана 60 Гц и скорость мерцания 20 Гц. Это означает, что мы хотим, чтобы объект был видимым в течение 1/40 секунд, а затем был невидим для 1/40 секунд. Теперь рассмотрим следующую диаграмму:

on        1/60        on       1/60        off       1/60
|---------------------|---------------------|---------------------| Screen

|--------------------------------|--------------------------------| Flicker
             1/40 (on)                        1/40 (off)

Мы видим, что в случае, мы получим 2 кадра, показывающие объект, и только один кадр не покажет его. Я предполагаю, что ваш алгоритм должен работать всякий раз, когда частота /2 кратно вашей частоте обновления экрана. (например, частота = [30, 15,....])

Примечание. Отключение vsynch не отображает больше изображений на экране, оно просто отображает больше изображений в фоновом режиме.

  • 0
    Спасибо за ваш ответ. Я понял, что вы имеете в виду, и я также подумал, что это проблема выборки, но, например, 30 Гц еще хуже при заикании по сравнению с 20 Гц. Это даже не входит в периодическое мерцание. Он просто заикается, что меня действительно беспокоит, потому что обычно при включенном vsync перерисовка должна синхронизироваться с частотой обновления мониторов, что означает переключение на каждом кадре, то есть 60 раз в секунду. Но это просто не работает, и я понятия не имею, почему.
  • 0
    Что произойдет, если вы просто переключаетесь в каждом кадре? (с включенным vsync)
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню