
- •Глава 1. Основы OpenGl 8
- •Введение
- •ОсновыOpenGl
- •Основные возможности
- •ИнтерфейсOpenGl
- •АрхитектураOpenGl
- •Синтаксис команд
- •Пример приложения
- •Контрольные вопросы:
- •Рисование геометрических объектов
- •Процесс обновления изображения
- •Вершины и примитивы
- •Положение вершины в пространстве
- •Цвет вершины
- •Нормаль
- •Операторные скобкиglBegin/glEnd
- •Дисплейные списки
- •Массивы вершин
- •Контрольные вопросы
- •Преобразования объектов
- •Работа с матрицами
- •Модельно-Видовые преобразования
- •Проекции
- •Область вывода
- •Контрольные вопросы
- •Материалы и освещение
- •Модель освещения
- •Спецификация материалов
- •Описание источников света
- •Создание эффекта тумана
- •Контрольные вопросы
- •Текстурирование
- •Подготовка текстуры
- •Наложение текстуры на объекты
- •Текстурные координаты
- •Контрольные вопросы
- •Операции с пикселями
- •Смешивание изображений. Прозрачность
- •Буфер-накопитель
- •Буфер маски
- •Управление растеризацией
- •Приемы работы сOpenGl
- •Устранение ступенчатости
- •Построение теней
- •Зеркальные отражения
- •Оптимизация программ
- •Организация приложения
- •Высокоуровневая оптимизация
- •Низкоуровневая оптимизация
- •Оптимизация вызовов OpenGl
- •Передача данных в OpenGl
- •Преобразования
- •Растеризация
- •Текстурирование
- •Очистка буферов
- •СтруктураGlut-приложения
- •Примитивы библиотекGlUиGlut
- •Настройка приложенийOpenGl
- •Демонстрационные программы
- •Пример 1: Простое glut-приложение
- •Пример 2: Модель освещения OpenGl
- •Пример 3: Текстурирование
- •Примеры практических заданий
- •Виртуальные часы
- •Интерактивный ландшафт
- •Литература
- •Предметный указатель
Оптимизация программ
Организация приложения
На первый взгляд может показаться, что производительность приложений, основанных на OpenGL, определяется в первую очередь производительностью реализации самой библиотекиOpenGL. Это верно, однако организация всего приложения также очень важна.
Высокоуровневая оптимизация
Обычно от программы под OpenGLтребуется визуализация высокого качества на интерактивных скоростях. Но, как правило, и то и другое сразу получить не удается. Следовательно, необходим поиск компромисса между качеством и производительностью. Существует множество различных подходов, но их подробное описание выходит за пределы этого пособия. Приведем лишь несколько примеров.
Можно отображать геометрию сцены с низким качеством во время анимации, а в моменты остановок показывать ее с наилучшим качеством. Во время интерактивного вращения (например, при нажатой клавише мыши) визуализировать модель с уменьшенным количеством примитивов. При рисовании статичного изображения отображать модель полностью.
Аналогично, объекты, которые располагаются далеко от наблюдателя, могут быть представлены моделями пониженной сложности. Это значительно снизит нагрузку на все ступени конвейера OpenGL. Объекты, которые находятся полностью вне поля видимости, могут быть эффективно отсечены без передачи на конвейерOpenGLс помощью проверки попадания ограничивающих их простых объемов (сфер или кубов) в пирамиду зрения.
Во время анимации можно отключить псевдотонирование (dithering), плавную заливку, текстуры. Опять-таки включать все это во время демонстрации статичных изображений. Этот подход особенно эффективен для систем без аппаратной поддержкиOpenGL.
Низкоуровневая оптимизация
Объекты, отображаемые с помощью OpenGL, хранятся в некоторых структурах данных. Одни типы таких структур более эффективны в использовании, чем другие, что определяет скорость визуализации.
Желательно, чтобы использовались структуры данных, которые могут быть быстро и эффективно переданы на конвейер OpenGL. Например, если мы хотим отобразить массив треугольников, то использование указателя на этот массив значительно более эффективно, чем передача егоOpenGLпоэлементно.
Пример:
Предположим, что мы пишем приложение, которое реализует рисование карты местности. Один из компонентов базы данных – список городов с их шириной, долготой и названием. Соответствующая структура данных может быть такой:
struct city
{
float latitute, longitude; /* положение города */
char*name; /* название */
intlarge_flag; /* 0 = маленький, 1 = большой */
};
Список городов может храниться как массив таких структур. Допустим, мы пишем функцию, которая рисует города на карте в виде точек разного размера с подписями:
void draw_cities( int n, struct city citylist[] )
{
int i;
for (i=0; i < n; i++)
{
if (citylist[i].large_flag)
glPointSize( 4.0 );
else
glPointSize( 2.0 );
glBegin( GL_POINTS );
glVertex2f( citylist[i].longitude,
citylist[i].latitude );
glEnd();
/* рисуем название города */
DrawText(citylist[i].longitude, citylist[i].latitude,
citylist[i].name);
}
}
Это реализация неудачна по следующим причинам:
glPointSizeвызывается для каждой итерации цикла.
между glBeginиglEndрисуется только одна точка.
вершины определяются в неоптимальном формате.
Ниже приведено более рациональное решение:
void draw_cities( int n, struct city citylist[] )
{
inti;
/* сначала рисуем маленькие точки */
glPointSize( 2.0 );
glBegin( GL_POINTS );
for (i=0; i < n ;i++)
{
if (citylist[i].large_flag==0) {
glVertex2f( citylist[i].longitude,
citylist[i].latitude );
}
}
glEnd();
/* большие точки рисуем во вторую очередь */
glPointSize( 4.0 );
glBegin( GL_POINTS );
for (i=0; i < n ;i++)
{
if (citylist[i].large_flag==1)
{
glVertex2f( citylist[i].longitude,
citylist[i].latitude );
}
}
glEnd();
/* затем рисуем названия городов */
for (i=0; i < n ;i++)
{
DrawText(citylist[i].longitude, citylist[i].latitude,
citylist[i].name);
}
}
В такой реализации мы вызываем glPointSizeдважды и увеличиваем число вершин междуglBeginиglEnd.
Однако остаются еще пути для оптимизации. Если мы поменяем наши структуры данных, то можем еще повысить эффективность рисования точек. Например:
struct city_list
{
intnum_cities; /* число городов в списке */
float*position;/* координаты города */
char**name; /* указатель на названия городов */
floatsize; /* размер точки, обозначающей город */
};
Теперь города разных размеров хранятся в разных списках. Положения точек хранятся отдельно в динамическом массиве. После реорганизации мы исключаем необходимость в условном операторе внутри glBegin/glEndи получаем возможность использовать массивы вершин для оптимизации. В результате наша функция выглядит следующим образом:
void draw_cities( struct city_list *list )
{
inti;
/* рисуем точки */
glPointSize( list->size );
glVertexPointer( 2, GL_FLOAT, 0,
list->num_cities,
list->position );
glDrawArrays( GL_POINTS, 0, list->num_cities );
/* рисуем название города */
for (i=0; i < list->num_cities ;i++)
{
DrawText(citylist[i].longitude, citylist[i].latitude
citylist[i].name);
}
}