Автор работы: Пользователь скрыл имя, 08 Апреля 2015 в 13:26, курсовая работа
Описание работы
Библиотека OpenGL представляет собой программный интерфейс для аппаратного обеспечения машинной графики. Этот интерфейс состоит приблизительно из 250 отдельных команд (почти 200 команд в ядре OpenGL и еще 50 команд в библиотеке утилит OpenGL), которые используются для того, чтобы определить объекты и операции, необходимые для создания интерактивных трехмерных прикладных программ.
Содержание работы
1.1. Программный код OpenGL.. 5 1.2. Синтаксис команд OpenGL.. 8 1.3 OpenGL как конечный автомат. 10 1.4. Конвейер визуализации OpenGL.. 11 1.4.1. Конвейер. 11 1.4.2 Списки вывода. 12 1.4.3 Вычислители. 13 1.4.4 Операции обработки вершин. 13 1.4.5 Сборка примитивов. 13 1.4.6 Операции обработки пикселей. 14 1.4.7 Сборка текстуры.. 15 1.4.8. Растеризация. 15 1.4.9 Операции обработки фрагментов. 16 2 Библиотеки, относящиеся к OpenGL.. 17 2.1 Библиотека OpenGL.. 17 2.2. Подключаемые файлы.. 19 2.3 GLUT, инструментарий утилит библиотеки OpenGL.. 20 2.3.1. Инструментарий библиотек. 20 2.3.2 Управление окнами. 21 2.3.3 Функция обратного вызова отображения. 22 2.3.4. Исполнение программы.. 23 2.3.4 Обработка событий ввода данных пользователем.. 25 2.3.5 Управление фоновым процессом.. 25 2.3.6 Рисование трехмерных объектов. 26 3. Анимация. 27 3.1. анимация компьютерной графики. 27 3.2 Обновление отображаемой информации во время паузы.. 30
Подпрограмма gIutDisplayFunc(void
(*/«nc)(void)) представляет собой первую и
наиболее важную функцию обратного вызова
по событию, с которой вам предстоит столкнуться.
Всякий раз, когда библиотека GLUT определяет,
что содержимое данного окна должно быть
восстановлено, выполняется функция обратного
вызова, зарегистрированная подпрограммой
glutDisplayFunc(). Поэтому вы должны поместить
все подпрограммы, которые необходимы
для перерисовки сцены, в данную функцию
обратного вызова отображения.
Если ваша программа
изменяет содержимое окна, то иногда вы
должны будете вызывать подпрограмму
glutPostRedisplay(void), которая вынуждает подпрограмму
glutMainLoopO вызывать зарегистрированную
функцию обратного вызова отображения
при следующем удобном случае.
2.3.4. Исполнение
программы
Самое последнее, что
вы должны сделать, это вызвать подпрограмму
glutMainLoop(void). При этом отображаются все
окна, которые были созданы, и в этих окнах
теперь работает визуализация. Начинается
обработка событий, и вызывается зарегистрированная
функция обратного вызова отображения.
Войдя однажды в этот цикл, из него не выходят
никогда!
Пример 2 демонстрирует,
как можно было бы воспользоваться инструментарием
GLUT, чтобы создать простую программу, показанную
ранее в примере 1. Обратите внимание на
реструктурирование программного кода.
Для того чтобы сделать эффективность
программы максимальной, все операции,
которые должны вызываться однократно
(установка цвета фона и системы координат),
теперь включены в состав процедуры, названной
init(). Операции, необходимые для визуализации
(и, возможно, для повторной визуализации)
сцены, включены в состав процедуры display(),
которая представляет собой зарегистрированную
функцию обратного вызова отображения
библиотеки GLUT.
Пример
2 Простая программа
OpenGL, использующая инструментарий GLUT:
hello.c
#include <GL/glut.h> #include
<stdlib.h>
void display(void)
/* Очистить все
пиксели */
glClear(GL_COLOR_BUFFER_BIT);
/* нарисовать белый
многоугольник (прямоугольник) с углами,
расположенными в точках
с координатами (0.25, 0.25, 0.0)
и (0.75, 0.75, 0.0)*/
glColor3f(1.0, 1.0, 1.0); glBegin(GL_POLYGON);
glVertex3f(0.25, 0.25, 0.0);
glVertex3f(0.75, 0.25, 0.0);
glVertex3f(0.75, 0.75, 0.0);
glVertex3f(0.25, 0.75, 0.0);glEnd()
;
/* He ждать! Запустить
обработку буферизированных
* подпрограмм OpenGL*/
glFlushO ; }
void init(void) {
/* Выбрать цвет
очистки (цвет фона) */
glClearColor (0.0, 0.0, 0.0, 0.0);
/* Инициализировать
просматриваемые значения */
glMatrixMode(GL_PROJECTION);
glLoadldentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0,
1.0); } /*
Объявить начальный
размер окна, его положение на экране и
режим отображения (одинарная буферизация
и режим RGBA).
Открыть окно со словом
"hello" в строке заголовка. Вызвать
подпрограммы инициализации. Зарегистрировать
функцию обратного вызова для отображения
графики. Войти в основной цикл и обрабатывать
события.*/
int main(int argc, char** argv) {
glutInit(Sargc, argv);
glutInitDisplayMode(GLUT_SINGLE |
GLUT_RGB);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow("hello");
init();
glutDisplayFunc(display);
glutMainLoop();
return 0; /* Язык программирования
С, согласно ISO, требует, чтобы функция
main возвращала значение типа int. */ }
2.3.4 Обработка
событий ввода данных пользователем
Для того чтобы зарегистрировать
обратный вызов команд, которые вызываются
в том случае, когда происходят указанные
события, можно воспользоваться следующими
подпрограммами.
Подпрограмма glutReshapeFunc(void
(*func)(int w, int h)) указывает на то, какое именно
действие должно быть выполнено при изменении
размера окна.
Подпрограммы glutKeyboardFunc(void
(*/«wc)(unsigned char key, int x, int у)) иglutMouseFunc (void (*func)(int
button, int state, int x, int у)) позволяют связывать
определенную клавишу клавиатуры или
кнопку мыши с подпрограммой, которая
вызывается, когда данная клавиша или
кнопка мыши нажимается или отпускается
пользователем.
Подпрограмма glutMotionFunc(void
(*func)(int x, int у)) регистрирует некоторую
подпрограмму для обратного вызова при
перемещении мыши с нажатой кнопкой.
2.3.5 Управление
фоновым процессом
Можно определить некоторую
функцию, которая должна быть выполнена
с помощью подпрограммы glutIdleFunc(void (*/«nc)(void))
в том случае, если не ожидаются
никакие другие события,
например, когда цикл обработки событий
в противном случае перешел бы в состояние
простоя. Эта подпрограмма в качестве
своего единственного параметра принимает
указатель на данную функцию. Для того
чтобы отключить выполнение этой функции,
передайте ей значение NULL (нуль).
2.3.6 Рисование
трехмерных объектов
Библиотека GLUT включает
в себя несколько подпрограмм для рисования
перечисленных ниже трехмерных объектов:
Конус
Икосаэдр
Чайник
Куб
Октаэдр
Тетраэдр
Додекаэдр
Сфера
Тор
Вы можете нарисовать
эти объекты в виде каркасных моделей
или в виде сплошных закрашенных объектов
с определенными нормалями к поверхностям.
Например, подпрограммы для куба и сферы
имеют следующий синтаксис:
Все эти модели рисуются
центрированными относительно начала
мировой системы координат.
3. Анимация
3.1. Анимация
компьютерной графики
Одна из наиболее захватывающих
вещей, которую вы можете сделать в области
компьютерной графики, — это рисование
движущихся изображений. Вне зависимости
от того, являетесь ли вы инженером, пытающимся
увидеть все стороны разрабатываемого
механического узла, пилотом, изучающим
с использованием моделирования процесс
пилотирования самолета, или же просто
страстным любителем компьютерных игр,
очевидно, что анимация является
важной составной частью компьютерной
графики.
В кинотеатре иллюзия
движения достигается за счет использования
последовательности изображений и проецирования
их на экран с частотой 24 кадра в секунду.
Каждый кадр последовательно перемещается
в положение позади объектива, затвор
открывается, и данный кадр отображается
на экране. Затвор на мгновение закрывается,
в то время как пленка протягивается к
следующему кадру, затем на экране отображается
этот следующий кадр, и так далее. Хотя
каждую секунду вы наблюдаете на экране
24 различные кадра, ваш мозг смешивает
все эти кадры в "непрерывную" анимацию.
(Старые фильмы Чарли Чаплина снимались
с частотой 16 кадров в секунду и при воспроизведении
фигуры двигались заметными резкими толчками.)
Экран в компьютерной графике обычно обновляется
(перерисовывает изображение) приблизительно
от 60 до 76 раз в секунду, а иногда прикладные
программы обеспечивают даже приблизительно
120 обновлений в секунду. Очевидно, что
анимация с частотой 60 кадров в секунду
выглядит более "гладкой", чем при
частоте 30 кадров в секунду, а 120
кадров в секунду заметно
лучше, чем 60 кадров в секунду. Однако частоты
регенерации, превышающие 120 кадров в секунду,
могут быть за пределами точки уменьшения
повторного появления, в зависимости от
пределов восприятия.
Основная причина того,
что технология проецирования кинофильма
работает, заключается в том, что каждый
кадр является законченным в момент его
отображения на экране. Предположим, что
вы пытаетесь сделать компьютерную анимацию
из своего кинофильма, состоящего из одного
миллиона кадров, с помощью программы,
подобной приведенному ниже фрагменту
псевдокода:
Если вы добавите время,
которое требуется вашей вычислительной
системе для того, чтобы очистить экран
и нарисовать типичный кадр, то приведенная
выше программа показывает все более тревожащие
результаты в зависимости от того, насколько
близко подходит время, требуемое ей для
очистки экрана и прорисовки кадра к 1/
24 доле секунды. Предположим, что процедура
рисования в этой программе почти полностью
занимает 1/24 долю секунды. Элементы, нарисованные
в самом начале, видимы в течение полной
1/24 доли секунды и представляют сплошное
изображение на экране; элементы, нарисованные
в конце рассматриваемого интервала, немедленно
очищаются, как только программа запускается
для рисования следующего кадра. Они представляют
собой в лучшем случае некое подобие призрачного
изображения, поскольку большую часть
интервала в 1/24 секунды ваш глаз рассматривает
очищенный фон вместо тех элементов, которые,
к несчастью для них, были нарисованы последними.
Проблема в данном случае заключается
в том, что приведенная выше программа
не отображает полностью нарисованные
кадры; вместо этого вы наблюдаете процесс
рисования в его развитии.
Большинство реализаций
библиотеки OpenGL обеспечивает двойную буферизацию —
аппаратную или программную, которая предоставляет
два готовых буфера с цветными изображениями.
Изображение из одного буфера отображается
на экране, в то время как в другом буфере
рисуется новое изображение. Когда рисование
очередного кадра завершается, эти два
буфера меняются местами, и тот буфер,
что содержал отображаемое изображение,
теперь используется для рисования, и
наоборот. Это похоже на работу кинопроектора,
пленка в котором содержит всего два кадра
и склеена в петлю; в то время как один
проецируется на экран, киномеханик отчаянно
стирает и перерисовывает невидимый зрителю
кадр. Если киномеханик работает достаточно
быстро, то зритель не замечает различий
между таким "кинопроектором" и реальной
системой, в которой все кадры уже нарисованы,
и кинопроектор просто отображает их один
за другим. При использовании двойной
буферизации каждый кадр отображается
только тогда, когда его рисование завершено;
зритель никогда не увидит частично нарисованного
кадра.
Псевдокод измененной
версии приведенной выше программы, которая
отображает плавно анимированную графику,
используя при этом двойную буферизацию,
мог бы выглядеть следующим образом:
открыть_окно_в_режиме_двойной_буфериэации();
for (i = 0; i < 1000000; i++) {
очис1ить_окно();
нарисовать_кадр(i);
поменять_буферы_местами()
; }
3.2 Обновление
отображаемой информации во время
паузы
Для некоторых реализаций
библиотеки OpenGL в дополнение к простой
перемене мест отображаемого и рисуемого
буферов, подпрограмма поменять_буферы_местами() ожидает,
пока не закончится текущий период обновления
отображаемой информации для того, чтобы
информация из предыдущего буфера был
отображена полностью. Эта подпрограмма
также позволяет новому буферу быть полностью
отображенным, начиная с начала. Принимая,
что ваша вычислительная система обеспечивает
обновление отображения 60 раз в секунду,
получим, что максимальная скорость передачи
кадров, которой можно достичь — 60 кадров
в секунду (fps — frames per second). Это
означает, что, если все кадры могут быть
очищены и нарисованы в течение 1/60 доли
секунды, то ваша анимация при данной скорости
будет воспроизводиться плавно.
В подобных системах
часто бывает так, что кадр оказывается
слишком сложным для того, чтобы быть нарисованным
в течение 1/60 доли секунды, и, таким образом,
каждый кадр отображается более одного
раза. Если, например, требуется 1/45 доля
секунды для того, чтобы нарисовать некоторый
кадр, вы задаете скорость передачи кадров
равной 30 fps, и тогда графическое изображение
"простаивает" в течение 1/30 — 1/45 =
1/90 доли секунды на каждый кадр, или треть
всего времени отображения.
Кроме того, частота
обновления отображаемой видеоинформации
является постоянной величиной, которая
может иметь некоторые неожиданные последствия
с точки зрения производительности. Например,
при периоде обновления информации, отображаемой
на мониторе, равной 1/60 доли секунды и
при постоянной скорости передачи кадров
вы можете работать со скоростями 60 fps,
30 fps, 20 fps, 15 fps, 12 fps и т. д. (60/1, 60/2, 60/3, 60/4, 60/5,
и т. д.). Это означает, что если вы пишете
прикладную программу и постепенно добавляете
к ней новые функциональные возможности
(предположим, что эта программа — имитатор
полета, и вы добавляете наземный пейзаж),
то сначала каждая новая добавляемая деталь
не будет оказывать никакого эффекта на
суммарную производительность — вы все
равно получаете скорость передачи кадров,
равную 60 fps. Затем, когда вы добавляете
еще одну новую деталь, система уже не
может нарисовать все это в течение 1/60
доли секунды, и анимация резко замедляется
— с 60 fps до 30 fps, поскольку она пропускает
первый возможный момент смены буферов.
Аналогичная ситуация происходит, когда
время рисования одного кадра становится
больше, чем 1/30 доля секунды — скорость
передачи кадров анимации скачком уменьшается
от 30 fps до 20 fps.
Если сложность сцены
такова, что время ее рисования оказывается
близко к любому из этих "волшебных"
интервалов времени (1/60 доля секунды, 2/60
доли секунды, 3/60 доли секунды и т. д. в
рассматриваемом примере), то из-за наличия
случайного изменения некоторые кадры
будут идти немного быстрее, а некоторые
— немного медленнее. В результате скорость
передачи кадров становится непостоянной,
что визуально может быть неприятно. В
этом случае, если вы не можете упростить
сцену так,
чтобы все кадры рисовались
достаточно быстро, возможно, лучше было
бы преднамеренно добавить крошечную
задержку для того, чтобы иметь уверенность,
что все кадры пропущены, задавая при этом
постоянную, более медленную скорость
передачи кадров. Если же кадры имеют существенно
отличающуюся степень сложности, тогда,
возможно, вам потребуется более сложный
подход к решению этой проблемы.
Движение
= Перерисовка изображения + Перестановка
буферов
Структура реальных
программ анимации не слишком отличается
от приведенного описания. Обычно проще
перерисовать буфер целиком с чистого
листа для каждого кадра, чем выяснять,
какие части кадра требуют изменения.
Это положение особенно справедливо для
таких прикладных программ, как трехмерные
имитаторы полета, где самое малое изменение
ориентации самолета изменяет позицию
всего вида из окна пилотской кабины.
В большинстве видов
анимации объекты на сцене просто перерисовываются
с различными преобразованиями: перемещается
точка наблюдения зрителя или автомобиль
немного проезжает по дороге, или какой-нибудь
объект поворачивается на небольшой угол.
Если для операций, не связанных с рисованием,
требуется существенный объем повторных
вычислений, то достижимая скорость передачи
кадров часто замедляется. Следует иметь
в виду, однако, что для выполнения таких
вычислений после выполнения подпрограммы
поменять_буферы_местами() часто может
использоваться время простоя.