2014-11-18 2 views
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

Вы, конечно, правы. Я просто хотел сконденсировать код, чтобы иметь все в одной функции, чтобы лучше видеть, что происходит. – lmNt

ответ

0

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

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 раз в секунду. Но это просто не работает, и я понятия не имею, почему. – lmNt

+0

Что произойдет, если вы просто включите каждый кадр?(с включенным vsync) – BDL

+0

Извините, забыл упомянуть, я также пробовал решения на основе рамок. Это уменьшает проблемы, но в любом случае он по-прежнему продолжает заикаться. – lmNt

Смежные вопросы