В настоящее время я пытаюсь, чтобы прямоугольники мерцали с определенной частотой, используя 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);
}
технически все, что до «фактического рендеринга» должно быть в логике, но это не изменяет вашу проблему. –
Вы, конечно, правы. Я просто хотел сконденсировать код, чтобы иметь все в одной функции, чтобы лучше видеть, что происходит. – lmNt