Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 19:

Простая программа на OpenGL

Пояснения кода Bounce

Библиотечная функция таймера

Мотором для создания движения прямоугольника в данной программе является вызов функции - таймера

glutTimerFunc(33, TimerFunction, 1);

Первый раз этот вызов осуществляется из функции main(), а затем повторяется в сервисной функции обратного вызова TimerFunction().

Синтаксис вызова этой GLUT -библиотечной функции следующий:

glutTimerFunc(unsigned int msecs, void (*func)(int value), int value);

Первый параметр указывает, сколько миллисекунд должна ждать эта функция перед однократным вызовом той сервисной (нашей) функции, имя которой будет подставлено вторым параметром в качестве фактического значения указателя на функцию. Наша (сервисная) функция обратного вызова (в данном случае - TimerFunction() ) должна иметь один аргумент целого типа, значение которого при вызове ей передаст таймер-функция. Этот целый параметр клиент функции-таймера передает сервисной (нашей) функции третьим аргументом при вызове функции-таймера. Проверяя значение этого аргумента как опцию в сервисной (нашей) функции обратного вызова, можно принимать те или иные решения, например, остановить процесс или сменить алгоритм.

Двойная буферизация

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

Но все равно пользователь может заметить отдельные этапы формирования кадра, особенно если изображение достаточно сложное и отдельную его фазу не удается построить за один период регенерации. В этом случае пользователь увидит половину кадра с новой фазой движения, а половину с прежней. Изображение перемещающегося объекта будет при этом искажено на экране.

Эту проблему можно решить с помощью двойной буферизации. Предположим, что в нашем распоряжении есть два буфера кадра: рабочий и фоновый. Рабочий буфер отображает информацию на экране, а фоновый буфер формируется программой. По команде от прикладной программы можно переключать функции буферов: сделать рабочим тот, который ранее был фоновым, а фоновым - тот, который ранее был рабочим.

Механизм двойной буферизации при формировании изображений мы устанавливаем в функции main() вызовом

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

с флагом GLUT_DOUBLE вместо GLUT_SINGLE, как это было ранее. В таком режиме функция рисования сцены

void RenderScene(void){...}

будет выполнять всю работу в фоновом буфере и только в самом конце своей работы по команде

// Переключение буфера с очисткой очереди командglutSwapBuffers();

сделает этот буфер рабочим - и это новенькое наконец-то и увидит пользователь.

Заметьте, что теперь функцию glFlush() мы уже не вызываем. Она уже не нужна, поскольку, выполняя переключение буферов, мы неявно вызываем функцию очистки очереди команд.

Двойная буферизация не решает проблемы скорости формирования изображения. Фактически эта технология позволяет только избежать наложения отображения и формирования новой фазы картинки - новое изображение выводится на экран только после завершения его формирования. Это несколько сглаживает размытие сцены.

В этом можно убедиться на примере нашей программы. Квадрат в законченный вид превращается мгновенно, поэтому нет разницы, по какой технологии его рисовать: с двойной буферизацией или без нее.

  • Внесите в текст программы Bounce следующие изменения
//**********************************************************
// Точка входа приложения
void main(int argc, char* argv[])
{
...............................................
  // glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
...............................................
}
  
//**********************************************************
// Рисование сцены
void RenderScene(void)
{
...............................................
  // Переключение буфера с очисткой очереди команд
  // glutSwapBuffers();
  glFlush();}
Листинг 19.33. Изменения в программе Bounce для проверки влияния на быстродействие технологии двойной буферизации

Остальные пояснения к коду Bounce приведены в комментариях листинга программы.

Вы, наверное, отметили главный недостаток в данной работе - вместе с графическим окном, создаваемым библиотекой GLUT, параллельно система создает консольное окно. Пока этот недостаток не должен нас смущать на данном этапе изучения самой библиотеки OpenGL, но в дальнейшем мы его устраним, построив другой тип оконного приложения.

Работу преподавателю сдавайте так: поочередно присоединяйте к проекту файлы

  • Simple.cpp
  • GLRect.cpp
  • Bounce.cpp

или сразу заготовьте три варианта исполнимых файлов, но будьте готовы к выполнению просьбы по внесению определенных изменений.


Александр Очеретяный
Александр Очеретяный
Украина, Киев
Анастасия Балыбердина
Анастасия Балыбердина
Украина, Киев, НТУУ КПИ