Руководство по работе с графической библиотекой OpenGL. Руководство разработано с учетом опыта чтения курса Компьютерная графика
Скачать 0.66 Mb.
|
9.1.1. Высокоуровневая оптимизация Обычно от программы под OpenGL требуется визуализация высокого качества на интерактивных скоростях. Но как правило, и то и другое сразу получить не удается. Следовательно, необходим поиск компромисса между качеством и производительностью. Существует множество различных подходов, но их подробное описание выходит за пределы этого пособия. Приведем лишь несколько примеров. • Можно отображать геометрию сцены с низким качеством во время анимации, а в моменты остановок показывать ее с 115 116 Глава 9. Оптимизация программ наилучшим качеством. Во время интерактивного вращения (например, при нажатой клавише мыши) визуализировать модель с уменьшенным количеством примитивов. При рисовании статичного изображения отображать модель полностью. • Аналогично, объекты, которые располагаются далеко от наблюдателя, могут быть представлены моделями пониженной сложности. Это значительно снизит нагрузку на все ступени конвейера OpcnGL. Объекты, которые находятся полностью вне поля видимости, могут быть эффективно отсечены без передачи на конвейер OpcnGL с помощью проверки попадания ограничивающих их простых объемов (сфер или кубов) в пирамиду зрения. 9.1.2. Низкоуровневая оптимизация Объекты, отображаемые с помощью OpenGL, хранятся в некоторых структурах данных. Одни типы таких структур более эффективны в использовании, чем другие, что определяет скорость визуализации. Желательно, чтобы использовались структуры данных, которые могут быть быстро и эффективно переданы на конвейер OpenGL. Например, если мы хотим отобразить массив треугольников, то использование указателя на этот массив значительно более эффективно, чем передача его OpenGL поэлементно. Пример. Предположим, что мы пишем приложение, которое реализует рисование карты местности. Один из компонентов базы данных — список городов с их шириной, долготой и названием. Соответствующая структура данных может быть такой: struct city { float latitute , longitude; /* положение города */ char *name; /* название */ 9.1. Организация приложения 117 int large_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 , city list [ i ]. latitude ); glEnd(); /* рисуем название, города */ DrawText ( citylist [ i ] . longitude , citylist [ i ] . latitude , citylist [ i ] . name); } } Эта реализация неудачна по следующим причинам: glPointSize вызывается для каждой итерации цикла; между glBegin и glEnd рисуется только одна точка; вершины определяются в неоптимальном формате. Ниже приведено более рациональное решение: void draw_cities( int n, struct city citylist [] ) { 118 Глава 9. Оптимизация программ } int i ; /* сначала рисуем маленькие точки */ glPointSize( 2.0 ); glBegin( GL_POINTS ); for ( i=0; i < n ; i++) { if ( city list [ i ]. large_flag==0) { glVertex2f( citylist [ i ] . longitude , city list [ i ]. latitude ); } } glEnd(); /* большие точки рисуем во вторую очередь */ glPointSize( 4.0 ); glBegin( GL_POINTS ); for ( i=0; i < n ; i++) { if ( city list [ i ]. large_flag==l) { glVertex2f( citylist [ i ] . longitude , city list [ i ]. latitude ); } } glEnd(); /* затем рисуем названия городов */ for ( i=0; i < n ; i++) { DrawText ( citylist [ i ] . longitude , citylist [i]. latitude , citylist [i]. name ) ; } В такой реализации мы вызываем glPointSize дважды и увеличиваем число вершин между glBegin и glEnd. Однако остаются еще пути для оптимизации. Если мы поме- 9.1. Организация приложения 119 няем наши структуры данных, то можем еще повысить эффективность рисования точек. Например: struct city list { _ int num_cities; /* число городов в списке */ float ^position;/* координаты города */ char **name; /* указатель на названия городов */ float size ; /* размер точки, обозначающей город */ }; Теперь города разных размеров хранятся в разных списках. Положения точек хранятся отдельно в динамическом массиве. После реорганизации мы исключаем необходимость в условном операторе внутри glBegin/glEnd и получаем возможность использовать массивы вершин для оптимизации. В результате наша функция выглядит следующим образом: void draw_cities( struct city list * 1 i s t ) { int i ; /* рисуем точки */ 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); } } 120 Глава 9. Оптимизация программ 9.2. Оптимизация вызовов OpenGL 9.2.1. Передача данных в OpenGL В данном разделе рассмотрим способы минимизации времени на передачу данных о примитивах в OpenGL. |