Я сейчас пишу небольшую игру, чтобы научиться рендерингу OpenGL, поскольку это одна из тех вещей, которыми я еще не занимался. Раньше я использовал SDL, и эта же функция, хотя и работала плохо, не была такой чрезмерной, как сейчас.
По сути, в моей игре пока мало что происходит, только некоторые базовые движения и рисование фона. Когда я переключился на OpenGL, мне показалось, что это слишком слишком быстро. Мои кадры в секунду превышают 2000, и эта функция использует большую часть вычислительной мощности.
Интересно то, что программа в своей версии SDL использовала 100% ЦП, но работала без сбоев, в то время как версия OpenGL использует только около 40% - 60% ЦП, но, похоже, нагружает мою видеокарту таким образом, что весь мой рабочий стол перестает отвечать на запросы. Плохой.
Это не слишком сложная функция, она визуализирует фоновый тайл 1024x1024 в соответствии с координатами X и Y игрока, чтобы создать впечатление движения, в то время как само изображение игрока остается заблокированным в центре. Поскольку это маленькая плитка для большого экрана, мне приходится визуализировать ее несколько раз, чтобы сшить плитки вместе для получения полного фона. Два цикла for в приведенном ниже коде повторяются 12 раз вместе, поэтому я могу понять, почему это неэффективно при вызове 2000 раз в секунду.
Итак, чтобы перейти к делу, это злодей:
void render_background(game_t *game)
{
int bgw;
int bgh;
int x, y;
glBindTexture(GL_TEXTURE_2D, game->art_background);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &bgw);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &bgh);
glBegin(GL_QUADS);
/*
* Start one background tile too early and end one too late
* so the player can not outrun the background
*/
for (x = -bgw; x < root->w + bgw; x += bgw)
{
for (y = -bgh; y < root->h + bgh; y += bgh)
{
/* Offsets */
int ox = x + (int)game->player->x % bgw;
int oy = y + (int)game->player->y % bgh;
/* Top Left */
glTexCoord2f(0, 0);
glVertex3f(ox, oy, 0);
/* Top Right */
glTexCoord2f(1, 0);
glVertex3f(ox + bgw, oy, 0);
/* Bottom Right */
glTexCoord2f(1, 1);
glVertex3f(ox + bgw, oy + bgh, 0);
/* Bottom Left */
glTexCoord2f(0, 1);
glVertex3f(ox, oy + bgh, 0);
}
}
glEnd();
}
Если я искусственно ограничиваю скорость, вызывая SDL_Delay(1)
в игровом цикле, я уменьшаю FPS до ~ 660 ± 20, я не получаю «излишка производительности». Но я сомневаюсь, что это правильный способ говорить об этом.
В заключение, вот мои общие функции рендеринга и игрового цикла:
void game_main()
{
long current_ticks = 0;
long elapsed_ticks;
long last_ticks = SDL_GetTicks();
game_t game;
object_t player;
if (init_game(&game) != 0)
return;
init_player(&player);
game.player = &player;
/* game_init() */
while (!game.quit)
{
/* Update number of ticks since last loop */
current_ticks = SDL_GetTicks();
elapsed_ticks = current_ticks - last_ticks;
last_ticks = current_ticks;
game_handle_inputs(elapsed_ticks, &game);
game_update(elapsed_ticks, &game);
game_render(elapsed_ticks, &game);
/* Lagging stops if I enable this */
/* SDL_Delay(1); */
}
cleanup_game(&game);
return;
}
void game_render(long elapsed_ticks, game_t *game)
{
game->tick_counter += elapsed_ticks;
if (game->tick_counter >= 1000)
{
game->fps = game->frame_counter;
game->tick_counter = 0;
game->frame_counter = 0;
printf("FPS: %d\n", game->fps);
}
render_background(game);
render_objects(game);
SDL_GL_SwapBuffers();
game->frame_counter++;
return;
}
Согласно профилированию gprof, даже когда я ограничиваю выполнение с помощью SDL_Delay()
, он все равно тратит около 50% времени на рендеринг моего фона.